summaryrefslogtreecommitdiffstats
path: root/libs/surfaceflinger
diff options
context:
space:
mode:
Diffstat (limited to 'libs/surfaceflinger')
-rw-r--r--libs/surfaceflinger/Android.mk49
-rw-r--r--libs/surfaceflinger/Barrier.h59
-rw-r--r--libs/surfaceflinger/BlurFilter.cpp326
-rw-r--r--libs/surfaceflinger/BlurFilter.h35
-rw-r--r--libs/surfaceflinger/BootAnimation.cpp403
-rw-r--r--libs/surfaceflinger/BootAnimation.h87
-rw-r--r--libs/surfaceflinger/CPUGauge.cpp171
-rw-r--r--libs/surfaceflinger/CPUGauge.h74
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp353
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardware.h113
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp403
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h96
-rw-r--r--libs/surfaceflinger/GPUHardware/GPUHardware.cpp581
-rw-r--r--libs/surfaceflinger/GPUHardware/GPUHardware.h63
-rw-r--r--libs/surfaceflinger/Layer.cpp568
-rw-r--r--libs/surfaceflinger/Layer.h120
-rw-r--r--libs/surfaceflinger/LayerBase.cpp740
-rw-r--r--libs/surfaceflinger/LayerBase.h356
-rw-r--r--libs/surfaceflinger/LayerBitmap.cpp185
-rw-r--r--libs/surfaceflinger/LayerBitmap.h84
-rw-r--r--libs/surfaceflinger/LayerBlur.cpp234
-rw-r--r--libs/surfaceflinger/LayerBlur.h65
-rw-r--r--libs/surfaceflinger/LayerBuffer.cpp655
-rw-r--r--libs/surfaceflinger/LayerBuffer.h216
-rw-r--r--libs/surfaceflinger/LayerDim.cpp113
-rw-r--r--libs/surfaceflinger/LayerDim.h57
-rw-r--r--libs/surfaceflinger/LayerOrientationAnim.cpp287
-rw-r--r--libs/surfaceflinger/LayerOrientationAnim.h75
-rw-r--r--libs/surfaceflinger/MODULE_LICENSE_APACHE20
-rw-r--r--libs/surfaceflinger/OrientationAnimation.cpp155
-rw-r--r--libs/surfaceflinger/OrientationAnimation.h73
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.cpp1840
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.h435
-rw-r--r--libs/surfaceflinger/Tokenizer.cpp172
-rw-r--r--libs/surfaceflinger/Tokenizer.h57
-rw-r--r--libs/surfaceflinger/Transform.cpp204
-rw-r--r--libs/surfaceflinger/Transform.h87
-rw-r--r--libs/surfaceflinger/VRamHeap.cpp176
-rw-r--r--libs/surfaceflinger/VRamHeap.h78
-rw-r--r--libs/surfaceflinger/clz.cpp37
-rw-r--r--libs/surfaceflinger/clz.h37
-rw-r--r--libs/surfaceflinger/tests/Android.mk1
-rw-r--r--libs/surfaceflinger/tests/overlays/Android.mk16
-rw-r--r--libs/surfaceflinger/tests/overlays/overlays.cpp58
44 files changed, 9994 insertions, 0 deletions
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
new file mode 100644
index 0000000..496e271
--- /dev/null
+++ b/libs/surfaceflinger/Android.mk
@@ -0,0 +1,49 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ clz.cpp.arm \
+ DisplayHardware/DisplayHardware.cpp \
+ DisplayHardware/DisplayHardwareBase.cpp \
+ GPUHardware/GPUHardware.cpp \
+ BootAnimation.cpp \
+ BlurFilter.cpp.arm \
+ CPUGauge.cpp \
+ Layer.cpp \
+ LayerBase.cpp \
+ LayerBuffer.cpp \
+ LayerBlur.cpp \
+ LayerBitmap.cpp \
+ LayerDim.cpp \
+ LayerOrientationAnim.cpp \
+ OrientationAnimation.cpp \
+ SurfaceFlinger.cpp \
+ Tokenizer.cpp \
+ Transform.cpp \
+ VRamHeap.cpp
+
+
+# need "-lrt" on Linux simulator to pick up clock_gettime
+ifeq ($(TARGET_SIMULATOR),true)
+ ifeq ($(HOST_OS),linux)
+ LOCAL_LDLIBS += -lrt
+ endif
+endif
+
+LOCAL_SHARED_LIBRARIES := \
+ libhardware \
+ libutils \
+ libcutils \
+ libui \
+ libcorecg \
+ libsgl \
+ libpixelflinger \
+ libEGL \
+ libGLESv1_CM
+
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, corecg graphics)
+
+LOCAL_MODULE:= libsurfaceflinger
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/surfaceflinger/Barrier.h b/libs/surfaceflinger/Barrier.h
new file mode 100644
index 0000000..e2bcf6a
--- /dev/null
+++ b/libs/surfaceflinger/Barrier.h
@@ -0,0 +1,59 @@
+/*
+ * 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() {
+ // gcc memory barrier, this makes sure all memory writes
+ // have been issued by gcc. On an SMP system we'd need a real
+ // h/w barrier.
+ asm volatile ("":::"memory");
+ 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/libs/surfaceflinger/BlurFilter.cpp b/libs/surfaceflinger/BlurFilter.cpp
new file mode 100644
index 0000000..5dc0ba0
--- /dev/null
+++ b/libs/surfaceflinger/BlurFilter.cpp
@@ -0,0 +1,326 @@
+/*
+**
+** 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;
+ }
+};
+
+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)
+{
+ return blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat);
+}
+
+} // 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/libs/surfaceflinger/BlurFilter.h b/libs/surfaceflinger/BlurFilter.h
new file mode 100644
index 0000000..294db43
--- /dev/null
+++ b/libs/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/libs/surfaceflinger/BootAnimation.cpp b/libs/surfaceflinger/BootAnimation.cpp
new file mode 100644
index 0000000..2b30336
--- /dev/null
+++ b/libs/surfaceflinger/BootAnimation.cpp
@@ -0,0 +1,403 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BootAnimation"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <math.h>
+#include <fcntl.h>
+#include <utils/misc.h>
+
+#include <utils/threads.h>
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/AssetManager.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/DisplayInfo.h>
+#include <ui/ISurfaceComposer.h>
+#include <ui/ISurfaceFlingerClient.h>
+#include <ui/EGLNativeWindowSurface.h>
+
+#include <core/SkBitmap.h>
+#include <images/SkImageDecoder.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <EGL/eglext.h>
+
+#include "BootAnimation.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+BootAnimation::BootAnimation(const sp<ISurfaceComposer>& composer) :
+ Thread(false) {
+ mSession = SurfaceComposerClient::clientForConnection(
+ composer->createConnection()->asBinder());
+}
+
+BootAnimation::~BootAnimation() {
+}
+
+void BootAnimation::onFirstRef() {
+ run("BootAnimation", PRIORITY_DISPLAY);
+}
+
+const sp<SurfaceComposerClient>& BootAnimation::session() const {
+ return mSession;
+}
+
+status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
+ const char* name) {
+ Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
+ if (!asset)
+ return NO_INIT;
+ SkBitmap bitmap;
+ SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(),
+ &bitmap, SkBitmap::kNo_Config, SkImageDecoder::kDecodePixels_Mode);
+ asset->close();
+ delete asset;
+
+ // ensure we can call getPixels(). No need to call unlock, since the
+ // bitmap will go out of scope when we return from this method.
+ bitmap.lockPixels();
+
+ const int w = bitmap.width();
+ const int h = bitmap.height();
+ const void* p = bitmap.getPixels();
+
+ GLint crop[4] = { 0, h, w, -h };
+ texture->w = w;
+ texture->h = h;
+
+ glGenTextures(1, &texture->name);
+ glBindTexture(GL_TEXTURE_2D, texture->name);
+
+ switch (bitmap.getConfig()) {
+ case SkBitmap::kA8_Config:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
+ GL_UNSIGNED_BYTE, p);
+ break;
+ case SkBitmap::kARGB_4444_Config:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
+ GL_UNSIGNED_SHORT_4_4_4_4, p);
+ break;
+ case SkBitmap::kARGB_8888_Config:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, p);
+ break;
+ case SkBitmap::kRGB_565_Config:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
+ GL_UNSIGNED_SHORT_5_6_5, p);
+ break;
+ default:
+ break;
+ }
+
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ return NO_ERROR;
+}
+
+status_t BootAnimation::readyToRun() {
+ mAssets.addDefaultAssets();
+
+ DisplayInfo dinfo;
+ status_t status = session()->getDisplayInfo(0, &dinfo);
+ if (status)
+ return -1;
+
+ // create the native surface
+ sp<Surface> s = session()->createSurface(getpid(), 0, dinfo.w, dinfo.h,
+ PIXEL_FORMAT_RGB_565);
+ session()->openTransaction();
+ s->setLayer(0x40000000);
+ session()->closeTransaction();
+
+ // initialize opengl and egl
+ const EGLint attribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 0, EGL_NONE };
+ EGLint w, h, dummy;
+ EGLint numConfigs;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLContext context;
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglChooseConfig(display, attribs, &config, 1, &numConfigs);
+
+ mNativeWindowSurface = new EGLNativeWindowSurface(s);
+ surface = eglCreateWindowSurface(display, config,
+ mNativeWindowSurface.get(), NULL);
+
+ context = eglCreateContext(display, config, NULL, NULL);
+ eglQuerySurface(display, surface, EGL_WIDTH, &w);
+ eglQuerySurface(display, surface, EGL_HEIGHT, &h);
+ eglMakeCurrent(display, surface, surface, context);
+ mDisplay = display;
+ mContext = context;
+ mSurface = surface;
+ mWidth = w;
+ mHeight = h;
+ mFlingerSurface = s;
+
+ // initialize GL
+ glShadeModel(GL_FLAT);
+ glEnable(GL_DITHER);
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_SCISSOR_TEST);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+ return NO_ERROR;
+}
+
+void BootAnimation::requestExit() {
+ mBarrier.open();
+ Thread::requestExit();
+}
+
+bool BootAnimation::threadLoop() {
+ bool r = android();
+ eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroyContext(mDisplay, mContext);
+ eglDestroySurface(mDisplay, mSurface);
+ mNativeWindowSurface.clear();
+ return r;
+}
+
+bool BootAnimation::android() {
+ initTexture(&mAndroid[0], mAssets, "images/android_320x480.png");
+ initTexture(&mAndroid[1], mAssets, "images/boot_robot.png");
+ initTexture(&mAndroid[2], mAssets, "images/boot_robot_glow.png");
+
+ // erase screen
+ glDisable(GL_SCISSOR_TEST);
+ glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
+
+ // clear screen
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(mDisplay, mSurface);
+
+ // wait ~1s
+ usleep(800000);
+
+ // fade in
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ const int steps = 8;
+ for (int i = 1; i < steps; i++) {
+ float fade = i / float(steps);
+ glColor4f(1, 1, 1, fade * fade);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDrawTexiOES(0, 0, 0, mAndroid[0].w, mAndroid[0].h);
+ eglSwapBuffers(mDisplay, mSurface);
+ }
+
+ // draw last frame
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glDisable(GL_BLEND);
+ glDrawTexiOES(0, 0, 0, mAndroid[0].w, mAndroid[0].h);
+ eglSwapBuffers(mDisplay, mSurface);
+
+ // update rect for the robot
+ const int x = mWidth - mAndroid[1].w - 33;
+ const int y = (mHeight - mAndroid[1].h) / 2 - 1;
+ const Rect updateRect(x, y, x + mAndroid[1].w, y + mAndroid[1].h);
+
+ // draw and update only what we need
+ mNativeWindowSurface->setSwapRectangle(updateRect.left,
+ updateRect.top, updateRect.width(), updateRect.height());
+
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
+ updateRect.height());
+
+ const nsecs_t startTime = systemTime();
+ do {
+ // glow speed and shape
+ nsecs_t time = systemTime() - startTime;
+ float t = ((4.0f / (360.0f * us2ns(16667))) * time);
+ t = t - floorf(t);
+ const float fade = 0.5f + 0.5f * sinf(t * 2 * M_PI);
+
+ // fade the glow in and out
+ glDisable(GL_BLEND);
+ glBindTexture(GL_TEXTURE_2D, mAndroid[2].name);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glColor4f(fade, fade, fade, fade);
+ glDrawTexiOES(updateRect.left, mHeight - updateRect.bottom, 0,
+ updateRect.width(), updateRect.height());
+
+ // draw the robot
+ glEnable(GL_BLEND);
+ glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glDrawTexiOES(updateRect.left, mHeight - updateRect.bottom, 0,
+ updateRect.width(), updateRect.height());
+
+ // make sure sleep a lot to not take too much CPU away from
+ // the boot process. With this "glow" animation there is no
+ // visible difference.
+ usleep(16667 * 4);
+
+ eglSwapBuffers(mDisplay, mSurface);
+ } while (!exitPending());
+
+ glDeleteTextures(1, &mAndroid[0].name);
+ glDeleteTextures(1, &mAndroid[1].name);
+ glDeleteTextures(1, &mAndroid[2].name);
+ return false;
+}
+
+bool BootAnimation::cylon() {
+ // initialize the textures...
+ initTexture(&mLeftTrail, mAssets, "images/cylon_left.png");
+ initTexture(&mRightTrail, mAssets, "images/cylon_right.png");
+ initTexture(&mBrightSpot, mAssets, "images/cylon_dot.png");
+
+ int w = mWidth;
+ int h = mHeight;
+
+ const Point c(w / 2, h / 2);
+ const GLint amplitude = 60;
+ const int scx = c.x - amplitude - mBrightSpot.w / 2;
+ const int scy = c.y - mBrightSpot.h / 2;
+ const int scw = amplitude * 2 + mBrightSpot.w;
+ const int sch = mBrightSpot.h;
+ const Rect updateRect(scx, h - scy - sch, scx + scw, h - scy);
+
+ // erase screen
+ glDisable(GL_SCISSOR_TEST);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ eglSwapBuffers(mDisplay, mSurface);
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ mNativeWindowSurface->setSwapRectangle(updateRect.left,
+ updateRect.top, updateRect.width(), updateRect.height());
+
+ glEnable(GL_SCISSOR_TEST);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ // clear the screen to white
+ Point p;
+ float t = 0;
+ float alpha = 1.0f;
+ const nsecs_t startTime = systemTime();
+ nsecs_t fadeTime = 0;
+
+ do {
+ // Set scissor in interesting area
+ glScissor(scx, scy, scw, sch);
+
+ // erase screen
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // compute wave
+ const float a = (t * 2 * M_PI) - M_PI / 2;
+ const float sn = sinf(a);
+ const float cs = cosf(a);
+ GLint x = GLint(amplitude * sn);
+ float derivative = cs;
+
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ if (derivative > 0) {
+ // vanishing trail...
+ p.x = (-amplitude + c.x) - mBrightSpot.w / 2;
+ p.y = c.y - mLeftTrail.h / 2;
+ float fade = 2.0f * (0.5f - t);
+ //fade *= fade;
+ glColor4f(fade, fade, fade, fade);
+ glBindTexture(GL_TEXTURE_2D, mLeftTrail.name);
+ glDrawTexiOES(p.x, p.y, 0, mLeftTrail.w, mLeftTrail.h);
+
+ // trail...
+ p.x = (x + c.x) - (mRightTrail.w + mBrightSpot.w / 2) + 16;
+ p.y = c.y - mRightTrail.h / 2;
+ fade = t < 0.25f ? t * 4.0f : 1.0f;
+ fade *= fade;
+ glColor4f(fade, fade, fade, fade);
+ glBindTexture(GL_TEXTURE_2D, mRightTrail.name);
+ glDrawTexiOES(p.x, p.y, 0, mRightTrail.w, mRightTrail.h);
+ } else {
+ // vanishing trail..
+ p.x = (amplitude + c.x) - (mRightTrail.w + mBrightSpot.w / 2) + 16;
+ p.y = c.y - mRightTrail.h / 2;
+ float fade = 2.0f * (0.5f - (t - 0.5f));
+ //fade *= fade;
+ glColor4f(fade, fade, fade, fade);
+ glBindTexture(GL_TEXTURE_2D, mRightTrail.name);
+ glDrawTexiOES(p.x, p.y, 0, mRightTrail.w, mRightTrail.h);
+
+ // trail...
+ p.x = (x + c.x) - mBrightSpot.w / 2;
+ p.y = c.y - mLeftTrail.h / 2;
+ fade = t < 0.5f + 0.25f ? (t - 0.5f) * 4.0f : 1.0f;
+ fade *= fade;
+ glColor4f(fade, fade, fade, fade);
+ glBindTexture(GL_TEXTURE_2D, mLeftTrail.name);
+ glDrawTexiOES(p.x, p.y, 0, mLeftTrail.w, mLeftTrail.h);
+ }
+
+ const Point p(x + c.x - mBrightSpot.w / 2, c.y - mBrightSpot.h / 2);
+ glBindTexture(GL_TEXTURE_2D, mBrightSpot.name);
+ glColor4f(1, 0.5, 0.5, 1);
+ glDrawTexiOES(p.x, p.y, 0, mBrightSpot.w, mBrightSpot.h);
+
+ // update animation
+ nsecs_t time = systemTime() - startTime;
+ t = ((4.0f / (360.0f * us2ns(16667))) * time);
+ t = t - floorf(t);
+
+ eglSwapBuffers(mDisplay, mSurface);
+
+ if (exitPending()) {
+ if (fadeTime == 0) {
+ fadeTime = time;
+ }
+ time -= fadeTime;
+ alpha = 1.0f - ((float(time) * 6.0f) / float(s2ns(1)));
+
+ session()->openTransaction();
+ mFlingerSurface->setAlpha(alpha * alpha);
+ session()->closeTransaction();
+ }
+ } while (alpha > 0);
+
+ // cleanup
+ glFinish();
+ glDeleteTextures(1, &mLeftTrail.name);
+ glDeleteTextures(1, &mRightTrail.name);
+ glDeleteTextures(1, &mBrightSpot.name);
+ return false;
+}
+
+// ---------------------------------------------------------------------------
+
+}
+; // namespace android
diff --git a/libs/surfaceflinger/BootAnimation.h b/libs/surfaceflinger/BootAnimation.h
new file mode 100644
index 0000000..b20cea0
--- /dev/null
+++ b/libs/surfaceflinger/BootAnimation.h
@@ -0,0 +1,87 @@
+/*
+ * 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_BOOTANIMATION_H
+#define ANDROID_BOOTANIMATION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+#include <utils/AssetManager.h>
+
+#include <ui/ISurfaceComposer.h>
+#include <ui/SurfaceComposerClient.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+
+#include "Barrier.h"
+
+class SkBitmap;
+
+namespace android {
+
+class AssetManager;
+class EGLNativeWindowSurface;
+
+// ---------------------------------------------------------------------------
+
+class BootAnimation : public Thread
+{
+public:
+ BootAnimation(const sp<ISurfaceComposer>& composer);
+ virtual ~BootAnimation();
+
+ const sp<SurfaceComposerClient>& session() const;
+ virtual void requestExit();
+
+private:
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+
+ struct Texture {
+ GLint w;
+ GLint h;
+ GLuint name;
+ };
+
+ status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
+ bool android();
+ bool cylon();
+
+ sp<SurfaceComposerClient> mSession;
+ AssetManager mAssets;
+ Texture mLeftTrail;
+ Texture mRightTrail;
+ Texture mBrightSpot;
+ Texture mAndroid[3];
+ int mWidth;
+ int mHeight;
+ EGLDisplay mDisplay;
+ EGLDisplay mContext;
+ EGLDisplay mSurface;
+ sp<Surface> mFlingerSurface;
+ sp<EGLNativeWindowSurface> mNativeWindowSurface;
+ Barrier mBarrier;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_BOOTANIMATION_H
diff --git a/libs/surfaceflinger/CPUGauge.cpp b/libs/surfaceflinger/CPUGauge.cpp
new file mode 100644
index 0000000..74a9270
--- /dev/null
+++ b/libs/surfaceflinger/CPUGauge.cpp
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "CPUGauge"
+
+#include <stdint.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <math.h>
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/DisplayInfo.h>
+#include <ui/ISurfaceComposer.h>
+#include <ui/ISurfaceFlingerClient.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "CPUGauge.h"
+
+namespace android {
+
+CPUGauge::CPUGauge( const sp<ISurfaceComposer>& composer,
+ nsecs_t interval,
+ int clock,
+ int refclock)
+ : Thread(false),
+ mInterval(interval), mClock(clock), mRefClock(refclock),
+ mReferenceTime(0),
+ mReferenceWorkingTime(0), mCpuUsage(0),
+ mRefIdleTime(0), mIdleTime(0)
+{
+ mFd = fopen("/proc/stat", "r");
+ setvbuf(mFd, NULL, _IONBF, 0);
+
+ mSession = SurfaceComposerClient::clientForConnection(
+ composer->createConnection()->asBinder());
+}
+
+CPUGauge::~CPUGauge()
+{
+ fclose(mFd);
+}
+
+const sp<SurfaceComposerClient>& CPUGauge::session() const
+{
+ return mSession;
+}
+
+void CPUGauge::onFirstRef()
+{
+ run("CPU Gauge");
+}
+
+status_t CPUGauge::readyToRun()
+{
+ LOGI("Starting CPU gauge...");
+ return NO_ERROR;
+}
+
+bool CPUGauge::threadLoop()
+{
+ DisplayInfo dinfo;
+ session()->getDisplayInfo(0, &dinfo);
+ sp<Surface> s(session()->createSurface(getpid(), 0, dinfo.w, 4, PIXEL_FORMAT_OPAQUE));
+ session()->openTransaction();
+ s->setLayer(INT_MAX);
+ session()->closeTransaction();
+
+ static const GGLfixed colors[4][4] = {
+ { 0x00000, 0x10000, 0x00000, 0x10000 },
+ { 0x10000, 0x10000, 0x00000, 0x10000 },
+ { 0x10000, 0x00000, 0x00000, 0x10000 },
+ { 0x00000, 0x00000, 0x00000, 0x10000 },
+ };
+
+ GGLContext* gl;
+ gglInit(&gl);
+ gl->activeTexture(gl, 0);
+ gl->disable(gl, GGL_TEXTURE_2D);
+ gl->disable(gl, GGL_BLEND);
+
+ const int w = dinfo.w;
+
+ while(!exitPending())
+ {
+ mLock.lock();
+ const float cpuUsage = this->cpuUsage();
+ const float totalCpuUsage = 1.0f - idle();
+ mLock.unlock();
+
+ Surface::SurfaceInfo info;
+ s->lock(&info);
+ GGLSurface fb;
+ fb.version = sizeof(GGLSurface);
+ fb.width = info.w;
+ fb.height = info.h;
+ fb.stride = info.w;
+ fb.format = info.format;
+ fb.data = (GGLubyte*)info.bits;
+
+ gl->colorBuffer(gl, &fb);
+ gl->color4xv(gl, colors[3]);
+ gl->recti(gl, 0, 0, w, 4);
+ gl->color4xv(gl, colors[2]); // red
+ gl->recti(gl, 0, 0, int(totalCpuUsage*w), 2);
+ gl->color4xv(gl, colors[0]); // green
+ gl->recti(gl, 0, 2, int(cpuUsage*w), 4);
+
+ s->unlockAndPost();
+
+ usleep(ns2us(mInterval));
+ }
+
+ gglUninit(gl);
+ return false;
+}
+
+void CPUGauge::sample()
+{
+ if (mLock.tryLock() == NO_ERROR) {
+ const nsecs_t now = systemTime(mRefClock);
+ const nsecs_t referenceTime = now-mReferenceTime;
+ if (referenceTime >= mInterval) {
+ const float reftime = 1.0f / referenceTime;
+ const nsecs_t nowWorkingTime = systemTime(mClock);
+
+ char buf[256];
+ fgets(buf, 256, mFd);
+ rewind(mFd);
+ char *str = buf+5;
+ char const * const usermode = strsep(&str, " "); (void)usermode;
+ char const * const usernice = strsep(&str, " "); (void)usernice;
+ char const * const systemmode = strsep(&str, " ");(void)systemmode;
+ char const * const idle = strsep(&str, " ");
+ const nsecs_t nowIdleTime = atoi(idle) * 10000000LL;
+ mIdleTime = float(nowIdleTime - mRefIdleTime) * reftime;
+ mRefIdleTime = nowIdleTime;
+
+ const nsecs_t workingTime = nowWorkingTime - mReferenceWorkingTime;
+ const float newCpuUsage = float(workingTime) * reftime;
+ if (mCpuUsage != newCpuUsage) {
+ mCpuUsage = newCpuUsage;
+ mReferenceWorkingTime = nowWorkingTime;
+ mReferenceTime = now;
+ }
+ }
+ mLock.unlock();
+ }
+}
+
+
+}; // namespace android
diff --git a/libs/surfaceflinger/CPUGauge.h b/libs/surfaceflinger/CPUGauge.h
new file mode 100644
index 0000000..5bb53c0
--- /dev/null
+++ b/libs/surfaceflinger/CPUGauge.h
@@ -0,0 +1,74 @@
+/*
+ * 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_CPUGAUGE_H
+#define ANDROID_CPUGAUGE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Timers.h>
+
+#include <ui/SurfaceComposerClient.h>
+
+namespace android {
+
+class CPUGauge : public Thread
+{
+public:
+ CPUGauge( const sp<ISurfaceComposer>& composer,
+ nsecs_t interval=s2ns(1),
+ int clock=SYSTEM_TIME_THREAD,
+ int refclock=SYSTEM_TIME_MONOTONIC);
+
+ ~CPUGauge();
+
+ const sp<SurfaceComposerClient>& session() const;
+
+ void sample();
+
+ inline float cpuUsage() const { return mCpuUsage; }
+ inline float idle() const { return mIdleTime; }
+
+private:
+ virtual void onFirstRef();
+ virtual status_t readyToRun();
+ virtual bool threadLoop();
+
+ Mutex mLock;
+
+ sp<SurfaceComposerClient> mSession;
+
+ const nsecs_t mInterval;
+ const int mClock;
+ const int mRefClock;
+
+ nsecs_t mReferenceTime;
+ nsecs_t mReferenceWorkingTime;
+ float mCpuUsage;
+ nsecs_t mRefIdleTime;
+ float mIdleTime;
+ FILE* mFd;
+};
+
+
+}; // namespace android
+
+#endif // ANDROID_CPUGAUGE_H
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
new file mode 100644
index 0000000..f14d7e9
--- /dev/null
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -0,0 +1,353 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include <cutils/properties.h>
+
+#include <utils/Log.h>
+
+#include <ui/EGLDisplaySurface.h>
+
+#include <GLES/gl.h>
+#include <EGL/eglext.h>
+
+
+#include "DisplayHardware/DisplayHardware.h"
+
+#include <hardware/copybit.h>
+#include <hardware/overlay.h>
+
+using namespace android;
+
+static __attribute__((noinline))
+const char *egl_strerror(EGLint err)
+{
+ switch (err){
+ case EGL_SUCCESS: return "EGL_SUCCESS";
+ case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
+ case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
+ case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
+ case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
+ case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
+ case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
+ case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
+ case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
+ case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
+ case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
+ case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
+ case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
+ case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
+ default: return "UNKNOWN";
+ }
+}
+
+static __attribute__((noinline))
+void checkGLErrors()
+{
+ GLenum error = glGetError();
+ if (error != GL_NO_ERROR)
+ LOGE("GL error 0x%04x", int(error));
+}
+
+static __attribute__((noinline))
+void checkEGLErrors(const char* token)
+{
+ EGLint error = eglGetError();
+ // GLESonGL seems to be returning 0 when there is no errors?
+ if (error && error != EGL_SUCCESS)
+ LOGE("%s error 0x%04x (%s)",
+ token, int(error), egl_strerror(error));
+}
+
+
+/*
+ * Initialize the display to the specified values.
+ *
+ */
+
+DisplayHardware::DisplayHardware(
+ const sp<SurfaceFlinger>& flinger,
+ uint32_t dpy)
+ : DisplayHardwareBase(flinger, dpy)
+{
+ 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; }
+
+void DisplayHardware::init(uint32_t dpy)
+{
+ // initialize EGL
+ const EGLint attribs[] = {
+ EGL_RED_SIZE, 5,
+ EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5,
+ EGL_DEPTH_SIZE, 0,
+ EGL_NONE
+ };
+ EGLint w, h, dummy;
+ EGLint numConfigs, n;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLContext context;
+ mFlags = 0;
+
+ // 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);
+ eglChooseConfig(display, attribs, &config, 1, &n);
+
+ /*
+ * Gather EGL extensions
+ */
+
+ const char* const egl_extensions = eglQueryString(
+ display, EGL_EXTENSIONS);
+
+ LOGI("EGL informations:");
+ LOGI("# of configs : %d", numConfigs);
+ LOGI("vendor : %s", eglQueryString(display, EGL_VENDOR));
+ LOGI("version : %s", eglQueryString(display, EGL_VERSION));
+ LOGI("extensions: %s", egl_extensions);
+ LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
+
+ // TODO: get this from the devfb driver (probably should be HAL module)
+ mFlags |= SWAP_RECTANGLE_EXTENSION;
+
+ // TODO: get the real "update_on_demand" behavior (probably should be HAL module)
+ mFlags |= UPDATE_ON_DEMAND;
+
+ if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
+ if (dummy == EGL_SLOW_CONFIG)
+ mFlags |= SLOW_CONFIG;
+ }
+
+ /*
+ * Create our main surface
+ */
+
+ mDisplaySurface = new EGLDisplaySurface();
+
+ surface = eglCreateWindowSurface(display, config, mDisplaySurface.get(), NULL);
+ //checkEGLErrors("eglCreateDisplaySurfaceANDROID");
+
+ if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
+ if (dummy == EGL_BUFFER_PRESERVED) {
+ mFlags |= BUFFER_PRESERVED;
+ }
+ }
+
+ GLint value = EGL_UNKNOWN;
+ eglQuerySurface(display, surface, EGL_HORIZONTAL_RESOLUTION, &value);
+ if (value == EGL_UNKNOWN) {
+ mDpiX = 160.0f;
+ } else {
+ mDpiX = 25.4f * float(value)/EGL_DISPLAY_SCALING;
+ }
+ value = EGL_UNKNOWN;
+ eglQuerySurface(display, surface, EGL_VERTICAL_RESOLUTION, &value);
+ if (value == EGL_UNKNOWN) {
+ mDpiY = 160.0f;
+ } else {
+ mDpiY = 25.4f * float(value)/EGL_DISPLAY_SCALING;
+ }
+ mRefreshRate = 60.f; // TODO: get the real refresh rate
+
+
+ char property[PROPERTY_VALUE_MAX];
+ 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");
+ }
+ mDensity = atoi(property) * (1.0f/160.0f);
+
+
+ /*
+ * Create our OpenGL ES context
+ */
+
+ context = eglCreateContext(display, config, NULL, NULL);
+ //checkEGLErrors("eglCreateContext");
+
+ eglQuerySurface(display, surface, EGL_WIDTH, &mWidth);
+ eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
+
+
+ /*
+ * Gather OpenGL ES extensions
+ */
+
+ eglMakeCurrent(display, surface, surface, context);
+ const char* const gl_extensions = (const char*)glGetString(GL_EXTENSIONS);
+ LOGI("OpenGL informations:");
+ LOGI("vendor : %s", glGetString(GL_VENDOR));
+ LOGI("renderer : %s", glGetString(GL_RENDERER));
+ LOGI("version : %s", glGetString(GL_VERSION));
+ LOGI("extensions: %s", gl_extensions);
+
+ if (strstr(gl_extensions, "GL_ARB_texture_non_power_of_two")) {
+ mFlags |= NPOT_EXTENSION;
+ }
+ if (strstr(gl_extensions, "GL_OES_draw_texture")) {
+ mFlags |= DRAW_TEXTURE_EXTENSION;
+ }
+ if (strstr(gl_extensions, "GL_ANDROID_direct_texture")) {
+ mFlags |= DIRECT_TEXTURE;
+ }
+
+ // Unbind the context from this thread
+ eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ mDisplay = display;
+ mConfig = config;
+ mSurface = surface;
+ mContext = context;
+ mFormat = GGL_PIXEL_FORMAT_RGB_565;
+
+ hw_module_t const* module;
+
+ mBlitEngine = NULL;
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+ copybit_open(module, &mBlitEngine);
+ }
+
+ mOverlayEngine = NULL;
+ if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
+ overlay_control_open(module, &mOverlayEngine);
+ }
+}
+
+/*
+ * 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);
+ copybit_close(mBlitEngine);
+ overlay_control_close(mOverlayEngine);
+}
+
+void DisplayHardware::releaseScreen() const
+{
+ DisplayHardwareBase::releaseScreen();
+}
+
+void DisplayHardware::acquireScreen() const
+{
+ DisplayHardwareBase::acquireScreen();
+}
+
+void DisplayHardware::getDisplaySurface(copybit_image_t* img) const
+{
+ img->w = mDisplaySurface->stride;
+ img->h = mDisplaySurface->height;
+ img->format = mDisplaySurface->format;
+ img->offset = mDisplaySurface->offset;
+ img->base = (void*)mDisplaySurface->base;
+ img->fd = mDisplaySurface->fd;
+}
+
+void DisplayHardware::getDisplaySurface(GGLSurface* fb) const
+{
+ fb->version= sizeof(GGLSurface);
+ fb->width = mDisplaySurface->width;
+ fb->height = mDisplaySurface->height;
+ fb->stride = mDisplaySurface->stride;
+ fb->format = mDisplaySurface->format;
+ fb->data = (GGLubyte*)mDisplaySurface->base + mDisplaySurface->offset;
+}
+
+uint32_t DisplayHardware::getPageFlipCount() const {
+ return mDisplaySurface->getPageFlipCount();
+}
+
+/*
+ * "Flip" the front and back buffers.
+ */
+
+void DisplayHardware::flip(const Region& dirty) const
+{
+ checkGLErrors();
+
+ EGLDisplay dpy = mDisplay;
+ EGLSurface surface = mSurface;
+
+ Region newDirty(dirty);
+ newDirty.andSelf(Rect(mWidth, mHeight));
+
+ if (mFlags & BUFFER_PRESERVED) {
+ const Region copyback(mDirty.subtract(newDirty));
+ mDirty = newDirty;
+ mDisplaySurface->copyFrontToBack(copyback);
+ }
+
+ if (mFlags & SWAP_RECTANGLE_EXTENSION) {
+ const Rect& b(newDirty.bounds());
+ mDisplaySurface->setSwapRectangle(
+ b.left, b.top, b.width(), b.height());
+ }
+
+ 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);
+}
+
+void DisplayHardware::copyFrontToImage(const copybit_image_t& front) const {
+ mDisplaySurface->copyFrontToImage(front);
+}
+
+void DisplayHardware::copyBackToImage(const copybit_image_t& front) const {
+ mDisplaySurface->copyBackToImage(front);
+}
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
new file mode 100644
index 0000000..550a4d1
--- /dev/null
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -0,0 +1,113 @@
+/*
+ * 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 <EGL/egl.h>
+
+#include "DisplayHardware/DisplayHardwareBase.h"
+
+struct overlay_control_device_t;
+struct copybit_device_t;
+struct copybit_image_t;
+struct copybit_t;
+
+namespace android {
+
+class EGLDisplaySurface;
+
+class DisplayHardware : public DisplayHardwareBase
+{
+public:
+ enum {
+ DIRECT_TEXTURE = 0x00000002,
+ SWAP_RECTANGLE_EXTENSION= 0x00000004,
+ COPY_BITS_EXTENSION = 0x00000008,
+ NPOT_EXTENSION = 0x00000100,
+ DRAW_TEXTURE_EXTENSION = 0x00000200,
+ BUFFER_PRESERVED = 0x00010000,
+ UPDATE_ON_DEMAND = 0x00020000, // video driver feature
+ SLOW_CONFIG = 0x00040000, // software
+ };
+
+ 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 getPageFlipCount() const;
+ void getDisplaySurface(copybit_image_t* img) const;
+ void getDisplaySurface(GGLSurface* fb) const;
+ EGLDisplay getEGLDisplay() const { return mDisplay; }
+ copybit_device_t* getBlitEngine() const { return mBlitEngine; }
+ overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
+
+ void copyFrontToImage(const copybit_image_t& front) const;
+ void copyBackToImage(const copybit_image_t& front) 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 Region mDirty;
+ sp<EGLDisplaySurface> mDisplaySurface;
+ copybit_device_t* mBlitEngine;
+ overlay_control_device_t* mOverlayEngine;
+};
+
+}; // namespace android
+
+#endif // ANDROID_DISPLAY_HARDWARE_H
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
new file mode 100644
index 0000000..f75e5c2
--- /dev/null
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -0,0 +1,403 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#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/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
new file mode 100644
index 0000000..8369bb8
--- /dev/null
+++ b/libs/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/libs/surfaceflinger/GPUHardware/GPUHardware.cpp b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
new file mode 100644
index 0000000..eb75f99
--- /dev/null
+++ b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
@@ -0,0 +1,581 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <utils/IBinder.h>
+#include <utils/MemoryDealer.h>
+#include <utils/MemoryBase.h>
+#include <utils/MemoryHeapPmem.h>
+#include <utils/MemoryHeapBase.h>
+#include <utils/IPCThreadState.h>
+#include <utils/StopWatch.h>
+
+#include <ui/ISurfaceComposer.h>
+
+#include "VRamHeap.h"
+#include "GPUHardware.h"
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+#include "GPUHardware/GPUHardware.h"
+
+
+/*
+ * Manage the GPU. This implementation is very specific to the G1.
+ * There are no abstraction here.
+ *
+ * All this code will soon go-away and be replaced by a new architecture
+ * for managing graphics accelerators.
+ *
+ * In the meantime, it is conceptually possible to instantiate a
+ * GPUHardwareInterface for another GPU (see GPUFactory at the bottom
+ * of this file); practically... doubtful.
+ *
+ */
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class GPUClientHeap;
+class GPUAreaHeap;
+
+class GPUHardware : public GPUHardwareInterface, public IBinder::DeathRecipient
+{
+public:
+ static const int GPU_RESERVED_SIZE;
+ static const int GPUR_SIZE;
+
+ GPUHardware();
+ virtual ~GPUHardware();
+
+ virtual void revoke(int pid);
+ virtual sp<MemoryDealer> request(int pid);
+ virtual status_t request(int pid,
+ const sp<IGPUCallback>& callback,
+ ISurfaceComposer::gpu_info_t* gpu);
+
+ virtual status_t friendlyRevoke();
+ virtual void unconditionalRevoke();
+
+ virtual pid_t getOwner() const { return mOwner; }
+
+ // used for debugging only...
+ virtual sp<SimpleBestFitAllocator> getAllocator() const;
+
+private:
+
+
+ enum {
+ NO_OWNER = -1,
+ };
+
+ struct GPUArea {
+ sp<GPUAreaHeap> heap;
+ sp<MemoryHeapPmem> clientHeap;
+ sp<IMemory> map();
+ };
+
+ struct Client {
+ pid_t pid;
+ GPUArea smi;
+ GPUArea ebi;
+ GPUArea reg;
+ void createClientHeaps();
+ void revokeAllHeaps();
+ };
+
+ Client& getClientLocked(pid_t pid);
+ status_t requestLocked(int pid);
+ void releaseLocked();
+ void takeBackGPULocked();
+ void registerCallbackLocked(const sp<IGPUCallback>& callback,
+ Client& client);
+
+ virtual void binderDied(const wp<IBinder>& who);
+
+ mutable Mutex mLock;
+ sp<GPUAreaHeap> mSMIHeap;
+ sp<GPUAreaHeap> mEBIHeap;
+ sp<GPUAreaHeap> mREGHeap;
+
+ KeyedVector<pid_t, Client> mClients;
+ DefaultKeyedVector< wp<IBinder>, pid_t > mRegisteredClients;
+
+ pid_t mOwner;
+
+ sp<MemoryDealer> mCurrentAllocator;
+ sp<IGPUCallback> mCallback;
+
+ sp<SimpleBestFitAllocator> mAllocator;
+
+ Condition mCondition;
+};
+
+// size reserved for GPU surfaces
+// 1200 KB fits exactly:
+// - two 320*480 16-bits double-buffered surfaces
+// - one 320*480 32-bits double-buffered surface
+// - one 320*240 16-bits double-buffered, 4x anti-aliased surface
+const int GPUHardware::GPU_RESERVED_SIZE = 1200 * 1024;
+const int GPUHardware::GPUR_SIZE = 1 * 1024 * 1024;
+
+// ---------------------------------------------------------------------------
+
+/*
+ * GPUHandle is a special IMemory given to the client. It represents their
+ * handle to the GPU. Once they give it up, they loose GPU access, or if
+ * they explicitly revoke their access through the binder code 1000.
+ * In both cases, this triggers a callback to revoke()
+ * first, and then actually powers down the chip.
+ *
+ * In the case of a misbehaving app, GPUHardware can ask for an immediate
+ * release of the GPU to the target process which should answer by calling
+ * code 1000 on GPUHandle. If it doesn't in a timely manner, the GPU will
+ * be revoked from under their feet.
+ *
+ * We should never hold a strong reference on GPUHandle. In practice this
+ * shouldn't be a big issue though because clients should use code 1000 and
+ * not rely on the dtor being called.
+ *
+ */
+
+class GPUClientHeap : public MemoryHeapPmem
+{
+public:
+ GPUClientHeap(const wp<GPUHardware>& gpu,
+ const sp<MemoryHeapBase>& heap)
+ : MemoryHeapPmem(heap), mGPU(gpu) { }
+protected:
+ wp<GPUHardware> mGPU;
+};
+
+class GPUAreaHeap : public MemoryHeapBase
+{
+public:
+ GPUAreaHeap(const wp<GPUHardware>& gpu,
+ const char* const vram, size_t size=0, size_t reserved=0)
+ : MemoryHeapBase(vram, size), mGPU(gpu) {
+ if (base() != MAP_FAILED) {
+ if (reserved == 0)
+ reserved = virtualSize();
+ mAllocator = new SimpleBestFitAllocator(reserved);
+ }
+ }
+ virtual sp<MemoryHeapPmem> createClientHeap() {
+ sp<MemoryHeapBase> parentHeap(this);
+ return new GPUClientHeap(mGPU, parentHeap);
+ }
+ virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
+ return mAllocator;
+ }
+private:
+ sp<SimpleBestFitAllocator> mAllocator;
+protected:
+ wp<GPUHardware> mGPU;
+};
+
+class GPURegisterHeap : public GPUAreaHeap
+{
+public:
+ GPURegisterHeap(const sp<GPUHardware>& gpu)
+ : GPUAreaHeap(gpu, "/dev/hw3d", GPUHardware::GPUR_SIZE) { }
+ virtual sp<MemoryHeapPmem> createClientHeap() {
+ sp<MemoryHeapBase> parentHeap(this);
+ return new MemoryHeapRegs(mGPU, parentHeap);
+ }
+private:
+ class MemoryHeapRegs : public GPUClientHeap {
+ public:
+ MemoryHeapRegs(const wp<GPUHardware>& gpu,
+ const sp<MemoryHeapBase>& heap)
+ : GPUClientHeap(gpu, heap) { }
+ sp<MemoryHeapPmem::MemoryPmem> createMemory(size_t offset, size_t size);
+ virtual void revoke();
+ private:
+ class GPUHandle : public MemoryHeapPmem::MemoryPmem {
+ public:
+ GPUHandle(const sp<GPUHardware>& gpu,
+ const sp<MemoryHeapPmem>& heap)
+ : MemoryHeapPmem::MemoryPmem(heap),
+ mGPU(gpu), mOwner(gpu->getOwner()) { }
+ virtual ~GPUHandle();
+ virtual sp<IMemoryHeap> getMemory(
+ ssize_t* offset, size_t* size) const;
+ virtual void revoke() { };
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags);
+ private:
+ void revokeNotification();
+ wp<GPUHardware> mGPU;
+ pid_t mOwner;
+ };
+ };
+};
+
+GPURegisterHeap::MemoryHeapRegs::GPUHandle::~GPUHandle() {
+ //LOGD("GPUHandle %p released, revoking GPU", this);
+ revokeNotification();
+}
+void GPURegisterHeap::MemoryHeapRegs::GPUHandle::revokeNotification() {
+ sp<GPUHardware> hw(mGPU.promote());
+ if (hw != 0) {
+ hw->revoke(mOwner);
+ }
+}
+sp<IMemoryHeap> GPURegisterHeap::MemoryHeapRegs::GPUHandle::getMemory(
+ ssize_t* offset, size_t* size) const
+{
+ sp<MemoryHeapPmem> heap = getHeap();
+ if (offset) *offset = 0;
+ if (size) *size = heap !=0 ? heap->virtualSize() : 0;
+ return heap;
+}
+status_t GPURegisterHeap::MemoryHeapRegs::GPUHandle::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ status_t err = BnMemory::onTransact(code, data, reply, flags);
+ if (err == UNKNOWN_TRANSACTION && code == 1000) {
+ int callingPid = IPCThreadState::self()->getCallingPid();
+ //LOGD("pid %d voluntarily revoking gpu", callingPid);
+ if (callingPid == mOwner) {
+ revokeNotification();
+ // we've revoked the GPU, don't do it again later when we
+ // are destroyed.
+ mGPU.clear();
+ } else {
+ LOGW("%d revoking someone else's gpu? (owner=%d)",
+ callingPid, mOwner);
+ }
+ err = NO_ERROR;
+ }
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+
+
+sp<MemoryHeapPmem::MemoryPmem> GPURegisterHeap::MemoryHeapRegs::createMemory(
+ size_t offset, size_t size)
+{
+ sp<GPUHandle> memory;
+ sp<GPUHardware> gpu = mGPU.promote();
+ if (heapID()>0 && gpu!=0) {
+#if HAVE_ANDROID_OS
+ /* this is where the GPU is powered on and the registers are mapped
+ * in the client */
+ //LOGD("ioctl(HW3D_GRANT_GPU)");
+ int err = ioctl(heapID(), HW3D_GRANT_GPU, base());
+ if (err) {
+ // it can happen if the master heap has been closed already
+ // in which case the GPU already is revoked (app crash for
+ // instance).
+ LOGW("HW3D_GRANT_GPU failed (%s), mFD=%d, base=%p",
+ strerror(errno), heapID(), base());
+ }
+ memory = new GPUHandle(gpu, this);
+#endif
+ }
+ return memory;
+}
+
+void GPURegisterHeap::MemoryHeapRegs::revoke()
+{
+ MemoryHeapPmem::revoke();
+#if HAVE_ANDROID_OS
+ if (heapID() > 0) {
+ //LOGD("ioctl(HW3D_REVOKE_GPU)");
+ int err = ioctl(heapID(), HW3D_REVOKE_GPU, base());
+ LOGE_IF(err, "HW3D_REVOKE_GPU failed (%s), mFD=%d, base=%p",
+ strerror(errno), heapID(), base());
+ }
+#endif
+}
+
+/*****************************************************************************/
+
+GPUHardware::GPUHardware()
+ : mOwner(NO_OWNER)
+{
+}
+
+GPUHardware::~GPUHardware()
+{
+}
+
+status_t GPUHardware::requestLocked(int pid)
+{
+ const int self_pid = getpid();
+ if (pid == self_pid) {
+ // can't use GPU from surfaceflinger's process
+ return PERMISSION_DENIED;
+ }
+
+ if (mOwner != pid) {
+ if (mREGHeap != 0) {
+ if (mOwner != NO_OWNER) {
+ // someone already has the gpu.
+ takeBackGPULocked();
+ releaseLocked();
+ }
+ } else {
+ // first time, initialize the stuff.
+ if (mSMIHeap == 0)
+ mSMIHeap = new GPUAreaHeap(this, "/dev/pmem_gpu0");
+ if (mEBIHeap == 0)
+ mEBIHeap = new GPUAreaHeap(this,
+ "/dev/pmem_gpu1", 0, GPU_RESERVED_SIZE);
+ mREGHeap = new GPURegisterHeap(this);
+ mAllocator = mEBIHeap->getAllocator();
+ if (mAllocator == NULL) {
+ // something went terribly wrong.
+ mSMIHeap.clear();
+ mEBIHeap.clear();
+ mREGHeap.clear();
+ return INVALID_OPERATION;
+ }
+ }
+ Client& client = getClientLocked(pid);
+ mCurrentAllocator = new MemoryDealer(client.ebi.clientHeap, mAllocator);
+ mOwner = pid;
+ }
+ return NO_ERROR;
+}
+
+sp<MemoryDealer> GPUHardware::request(int pid)
+{
+ sp<MemoryDealer> dealer;
+ Mutex::Autolock _l(mLock);
+ Client* client;
+ LOGD("pid %d requesting gpu surface (current owner = %d)", pid, mOwner);
+ if (requestLocked(pid) == NO_ERROR) {
+ dealer = mCurrentAllocator;
+ LOGD_IF(dealer!=0, "gpu surface granted to pid %d", mOwner);
+ }
+ return dealer;
+}
+
+status_t GPUHardware::request(int pid, const sp<IGPUCallback>& callback,
+ ISurfaceComposer::gpu_info_t* gpu)
+{
+ if (callback == 0)
+ return BAD_VALUE;
+
+ sp<IMemory> gpuHandle;
+ LOGD("pid %d requesting gpu core (owner = %d)", pid, mOwner);
+ Mutex::Autolock _l(mLock);
+ status_t err = requestLocked(pid);
+ if (err == NO_ERROR) {
+ // it's guaranteed to be there, be construction
+ Client& client = mClients.editValueFor(pid);
+ registerCallbackLocked(callback, client);
+ gpu->count = 2;
+ gpu->regions[0].region = client.smi.map();
+ gpu->regions[1].region = client.ebi.map();
+ gpu->regs = client.reg.map();
+ gpu->regions[0].reserved = 0;
+ gpu->regions[1].reserved = GPU_RESERVED_SIZE;
+ if (gpu->regs != 0) {
+ //LOGD("gpu core granted to pid %d, handle base=%p",
+ // mOwner, gpu->regs->pointer());
+ }
+ mCallback = callback;
+ } else {
+ LOGW("couldn't grant gpu core to pid %d", pid);
+ }
+ return err;
+}
+
+void GPUHardware::revoke(int pid)
+{
+ Mutex::Autolock _l(mLock);
+ if (mOwner > 0) {
+ if (pid != mOwner) {
+ LOGW("GPU owned by %d, revoke from %d", mOwner, pid);
+ return;
+ }
+ //LOGD("revoke pid=%d, owner=%d", pid, mOwner);
+ // mOwner could be <0 if the same process acquired the GPU
+ // several times without releasing it first.
+ mCondition.signal();
+ releaseLocked();
+ }
+}
+
+status_t GPUHardware::friendlyRevoke()
+{
+ Mutex::Autolock _l(mLock);
+ //LOGD("friendlyRevoke owner=%d", mOwner);
+ takeBackGPULocked();
+ releaseLocked();
+ return NO_ERROR;
+}
+
+void GPUHardware::takeBackGPULocked()
+{
+ sp<IGPUCallback> callback = mCallback;
+ mCallback.clear();
+ if (callback != 0) {
+ callback->gpuLost(); // one-way
+ mCondition.waitRelative(mLock, ms2ns(250));
+ }
+}
+
+void GPUHardware::releaseLocked()
+{
+ //LOGD("revoking gpu from pid %d", mOwner);
+ if (mOwner != NO_OWNER) {
+ // this may fail because the client might have died, and have
+ // been removed from the list.
+ ssize_t index = mClients.indexOfKey(mOwner);
+ if (index >= 0) {
+ Client& client(mClients.editValueAt(index));
+ client.revokeAllHeaps();
+ }
+ mOwner = NO_OWNER;
+ mCurrentAllocator.clear();
+ mCallback.clear();
+ }
+}
+
+GPUHardware::Client& GPUHardware::getClientLocked(pid_t pid)
+{
+ ssize_t index = mClients.indexOfKey(pid);
+ if (index < 0) {
+ Client client;
+ client.pid = pid;
+ client.smi.heap = mSMIHeap;
+ client.ebi.heap = mEBIHeap;
+ client.reg.heap = mREGHeap;
+ index = mClients.add(pid, client);
+ }
+ Client& client(mClients.editValueAt(index));
+ client.createClientHeaps();
+ return client;
+}
+
+// ----------------------------------------------------------------------------
+// for debugging / testing ...
+
+sp<SimpleBestFitAllocator> GPUHardware::getAllocator() const {
+ Mutex::Autolock _l(mLock);
+ return mAllocator;
+}
+
+void GPUHardware::unconditionalRevoke()
+{
+ Mutex::Autolock _l(mLock);
+ releaseLocked();
+}
+
+// ---------------------------------------------------------------------------
+
+sp<IMemory> GPUHardware::GPUArea::map() {
+ sp<IMemory> memory;
+ if (clientHeap != 0 && heap != 0) {
+ memory = clientHeap->mapMemory(0, heap->virtualSize());
+ }
+ return memory;
+}
+
+void GPUHardware::Client::createClientHeaps()
+{
+ if (smi.clientHeap == 0)
+ smi.clientHeap = smi.heap->createClientHeap();
+ if (ebi.clientHeap == 0)
+ ebi.clientHeap = ebi.heap->createClientHeap();
+ if (reg.clientHeap == 0)
+ reg.clientHeap = reg.heap->createClientHeap();
+}
+
+void GPUHardware::Client::revokeAllHeaps()
+{
+ if (smi.clientHeap != 0)
+ smi.clientHeap->revoke();
+ if (ebi.clientHeap != 0)
+ ebi.clientHeap->revoke();
+ if (reg.clientHeap != 0)
+ reg.clientHeap->revoke();
+}
+
+void GPUHardware::registerCallbackLocked(const sp<IGPUCallback>& callback,
+ Client& client)
+{
+ sp<IBinder> binder = callback->asBinder();
+ if (mRegisteredClients.add(binder, client.pid) >= 0) {
+ binder->linkToDeath(this);
+ }
+}
+
+void GPUHardware::binderDied(const wp<IBinder>& who)
+{
+ Mutex::Autolock _l(mLock);
+ pid_t pid = mRegisteredClients.valueFor(who);
+ if (pid != 0) {
+ ssize_t index = mClients.indexOfKey(pid);
+ if (index >= 0) {
+ //LOGD("*** removing client at %d", index);
+ Client& client(mClients.editValueAt(index));
+ client.revokeAllHeaps(); // not really needed in theory
+ mClients.removeItemsAt(index);
+ if (mClients.size() == 0) {
+ //LOGD("*** was last client closing everything");
+ mCallback.clear();
+ mAllocator.clear();
+ mCurrentAllocator.clear();
+ mSMIHeap.clear();
+ mREGHeap.clear();
+
+ // NOTE: we cannot clear the EBI heap because surfaceflinger
+ // itself may be using it, since this is where surfaces
+ // are allocated. if we're in the middle of compositing
+ // a surface (even if its process just died), we cannot
+ // rip the heap under our feet.
+
+ mOwner = NO_OWNER;
+ }
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+sp<GPUHardwareInterface> GPUFactory::getGPU()
+{
+ return new GPUHardware();
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.h b/libs/surfaceflinger/GPUHardware/GPUHardware.h
new file mode 100644
index 0000000..3354528
--- /dev/null
+++ b/libs/surfaceflinger/GPUHardware/GPUHardware.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008 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_GPU_HARDWARE_H
+#define ANDROID_GPU_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+
+#include <ui/ISurfaceComposer.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class IGPUCallback;
+
+class GPUHardwareInterface : public virtual RefBase
+{
+public:
+ virtual void revoke(int pid) = 0;
+ virtual sp<MemoryDealer> request(int pid) = 0;
+ virtual status_t request(int pid, const sp<IGPUCallback>& callback,
+ ISurfaceComposer::gpu_info_t* gpu) = 0;
+
+ virtual status_t friendlyRevoke() = 0;
+
+ // used for debugging only...
+ virtual sp<SimpleBestFitAllocator> getAllocator() const = 0;
+ virtual pid_t getOwner() const = 0;
+ virtual void unconditionalRevoke() = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+class GPUFactory
+{
+public:
+ // the gpu factory
+ static sp<GPUHardwareInterface> getGPU();
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GPU_HARDWARE_H
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
new file mode 100644
index 0000000..f65d669
--- /dev/null
+++ b/libs/surfaceflinger/Layer.cpp
@@ -0,0 +1,568 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/properties.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/StopWatch.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/EGLDisplaySurface.h>
+
+#include "clz.h"
+#include "Layer.h"
+#include "LayerBitmap.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+
+#define DEBUG_RESIZE 0
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+const uint32_t Layer::typeInfo = LayerBaseClient::typeInfo | 4;
+const char* const Layer::typeID = "Layer";
+
+// ---------------------------------------------------------------------------
+
+Layer::Layer(SurfaceFlinger* flinger, DisplayID display, Client* c, int32_t i)
+ : LayerBaseClient(flinger, display, c, i),
+ mSecure(false),
+ mFrontBufferIndex(1),
+ mNeedsBlending(true),
+ mResizeTransactionDone(false),
+ mTextureName(-1U), mTextureWidth(0), mTextureHeight(0)
+{
+ // no OpenGL operation is possible here, since we might not be
+ // in the OpenGL thread.
+}
+
+Layer::~Layer()
+{
+ client->free(clientIndex());
+ // this should always be called from the OpenGL thread
+ if (mTextureName != -1U) {
+ //glDeleteTextures(1, &mTextureName);
+ deletedTextures.add(mTextureName);
+ }
+}
+
+void Layer::initStates(uint32_t w, uint32_t h, uint32_t flags)
+{
+ LayerBase::initStates(w,h,flags);
+
+ if (flags & ISurfaceComposer::eDestroyBackbuffer)
+ lcblk->flags |= eNoCopyBack;
+}
+
+sp<LayerBaseClient::Surface> Layer::getSurface() const
+{
+ return mSurface;
+}
+
+status_t Layer::setBuffers( Client* client,
+ uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t flags)
+{
+ PixelFormatInfo info;
+ status_t err = getPixelFormatInfo(format, &info);
+ if (err) return err;
+
+ // TODO: if eHardware is explicitly requested, we should fail
+ // on systems where we can't allocate memory that can be used with
+ // DMA engines for instance.
+
+ // FIXME: we always ask for hardware for now (this should come from copybit)
+ flags |= ISurfaceComposer::eHardware;
+
+ const uint32_t memory_flags = flags &
+ (ISurfaceComposer::eGPU |
+ ISurfaceComposer::eHardware |
+ ISurfaceComposer::eSecure);
+
+ // pixel-alignment. the final alignment may be bigger because
+ // we always force a 4-byte aligned bpr.
+ uint32_t alignment = 1;
+
+ if (flags & ISurfaceComposer::eGPU) {
+ // FIXME: this value should come from the h/w
+ alignment = 8;
+ // FIXME: this is msm7201A specific, as its GPU only supports
+ // BGRA_8888.
+ if (format == PIXEL_FORMAT_RGBA_8888) {
+ format = PIXEL_FORMAT_BGRA_8888;
+ }
+ }
+
+ mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
+ mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
+ sp<MemoryDealer> allocators[2];
+ for (int i=0 ; i<2 ; i++) {
+ allocators[i] = client->createAllocator(memory_flags);
+ if (allocators[i] == 0)
+ return NO_MEMORY;
+ mBuffers[i].init(allocators[i]);
+ int err = mBuffers[i].setBits(w, h, alignment, format, LayerBitmap::SECURE_BITS);
+ if (err != NO_ERROR)
+ return err;
+ mBuffers[i].clear(); // clear the bits for security
+ mBuffers[i].getInfo(lcblk->surface + i);
+ }
+
+ mSurface = new Surface(clientIndex(),
+ allocators[0]->getMemoryHeap(),
+ allocators[1]->getMemoryHeap(),
+ mIdentity);
+
+ return NO_ERROR;
+}
+
+void Layer::reloadTexture(const Region& dirty)
+{
+ if (UNLIKELY(mTextureName == -1U)) {
+ // create the texture name the first time
+ // can't do that in the ctor, because it runs in another thread.
+ mTextureName = createTexture();
+ }
+ const GGLSurface& t(frontBuffer().surface());
+ loadTexture(dirty, mTextureName, t, mTextureWidth, mTextureHeight);
+}
+
+
+void Layer::onDraw(const Region& clip) const
+{
+ if (UNLIKELY(mTextureName == -1LU)) {
+ //LOGW("Layer %p doesn't have a texture", this);
+ // the texture has not been created yet, this Layer has
+ // in fact never been drawn into. this happens frequently with
+ // SurfaceView.
+ clearWithOpenGL(clip);
+ return;
+ }
+
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const LayerBitmap& front(frontBuffer());
+ const GGLSurface& t(front.surface());
+
+ status_t err = NO_ERROR;
+ const int can_use_copybit = canUseCopybit();
+ if (can_use_copybit) {
+ // StopWatch watch("copybit");
+ const State& s(drawingState());
+
+ copybit_image_t dst;
+ hw.getDisplaySurface(&dst);
+ const copybit_rect_t& drect
+ = reinterpret_cast<const copybit_rect_t&>(mTransformedBounds);
+
+ copybit_image_t src;
+ front.getBitmapSurface(&src);
+ copybit_rect_t srect = { 0, 0, t.width, t.height };
+
+ copybit_device_t* copybit = mFlinger->getBlitEngine();
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, getOrientation());
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
+ copybit->set_parameter(copybit, COPYBIT_DITHER,
+ s.flags & ISurfaceComposer::eLayerDither ?
+ COPYBIT_ENABLE : COPYBIT_DISABLE);
+
+ region_iterator it(clip);
+ err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ }
+
+ if (!can_use_copybit || err) {
+ drawWithOpenGL(clip, mTextureName, t);
+ }
+}
+
+status_t Layer::reallocateBuffer(int32_t index, uint32_t w, uint32_t h)
+{
+ LOGD_IF(DEBUG_RESIZE,
+ "reallocateBuffer (layer=%p), "
+ "requested (%dx%d), "
+ "index=%d, (%dx%d), (%dx%d)",
+ this,
+ int(w), int(h),
+ int(index),
+ int(mBuffers[0].width()), int(mBuffers[0].height()),
+ int(mBuffers[1].width()), int(mBuffers[1].height()));
+
+ status_t err = mBuffers[index].resize(w, h);
+ if (err == NO_ERROR) {
+ mBuffers[index].getInfo(lcblk->surface + index);
+ } else {
+ LOGE("resizing buffer %d to (%u,%u) failed [%08x] %s",
+ index, w, h, err, strerror(err));
+ // XXX: what to do, what to do? We could try to free some
+ // hidden surfaces, instead of killing this one?
+ }
+ return err;
+}
+
+uint32_t Layer::doTransaction(uint32_t flags)
+{
+ const Layer::State& front(drawingState());
+ const Layer::State& temp(currentState());
+
+ // the test front.{w|h} != temp.{w|h} is not enough because it is possible
+ // that the size changed back to its previous value before the buffer
+ // was resized (in the eLocked case below), in which case, we still
+ // need to execute the code below so the clients have a chance to be
+ // release. resze() deals with the fact that the size can be the same.
+
+ /*
+ * Various states we could be in...
+
+ resize = state & eResizeRequested;
+ if (backbufferChanged) {
+ if (resize == 0) {
+ // ERROR, the resized buffer doesn't have its resize flag set
+ } else if (resize == mask) {
+ // ERROR one of the buffer has already been resized
+ } else if (resize == mask ^ eResizeRequested) {
+ // ERROR, the resized buffer doesn't have its resize flag set
+ } else if (resize == eResizeRequested) {
+ // OK, Normal case, proceed with resize
+ }
+ } else {
+ if (resize == 0) {
+ // OK, nothing special, do nothing
+ } else if (resize == mask) {
+ // restarted transaction, do nothing
+ } else if (resize == mask ^ eResizeRequested) {
+ // restarted transaction, do nothing
+ } else if (resize == eResizeRequested) {
+ // OK, size reset to previous value, proceed with resize
+ }
+ }
+ */
+
+ // Index of the back buffer
+ const bool backbufferChanged = (front.w != temp.w) || (front.h != temp.h);
+ const uint32_t state = lcblk->swapState;
+ const int32_t clientBackBufferIndex = layer_cblk_t::backBuffer(state);
+ const uint32_t mask = clientBackBufferIndex ? eResizeBuffer1 : eResizeBuffer0;
+ uint32_t resizeFlags = state & eResizeRequested;
+
+ if (UNLIKELY(backbufferChanged && (resizeFlags != eResizeRequested))) {
+ LOGE( "backbuffer size changed, but both resize flags are not set! "
+ "(layer=%p), state=%08x, requested (%dx%d), drawing (%d,%d), "
+ "index=%d, (%dx%d), (%dx%d)",
+ this, state,
+ int(temp.w), int(temp.h),
+ int(drawingState().w), int(drawingState().h),
+ int(clientBackBufferIndex),
+ int(mBuffers[0].width()), int(mBuffers[0].height()),
+ int(mBuffers[1].width()), int(mBuffers[1].height()));
+ // if we get there we're pretty screwed. the only reasonable
+ // thing to do is to pretend we should do the resize since
+ // backbufferChanged is set (this also will give a chance to
+ // client to get unblocked)
+ resizeFlags = eResizeRequested;
+ }
+
+ if (resizeFlags == eResizeRequested) {
+ // NOTE: asserting that clientBackBufferIndex!=mFrontBufferIndex
+ // here, would be wrong and misleading because by this point
+ // mFrontBufferIndex has not been updated yet.
+
+ LOGD_IF(DEBUG_RESIZE,
+ "resize (layer=%p), state=%08x, "
+ "requested (%dx%d), "
+ "drawing (%d,%d), "
+ "index=%d, (%dx%d), (%dx%d)",
+ this, state,
+ int(temp.w), int(temp.h),
+ int(drawingState().w), int(drawingState().h),
+ int(clientBackBufferIndex),
+ int(mBuffers[0].width()), int(mBuffers[0].height()),
+ int(mBuffers[1].width()), int(mBuffers[1].height()));
+
+ if (state & eLocked) {
+ // if the buffer is locked, we can't resize anything because
+ // - the backbuffer is currently in use by the user
+ // - the front buffer is being shown
+ // We just act as if the transaction didn't happen and we
+ // reschedule it later...
+ flags |= eRestartTransaction;
+ } else {
+ // This buffer needs to be resized
+ status_t err =
+ resize(clientBackBufferIndex, temp.w, temp.h, "transaction");
+ if (err == NO_ERROR) {
+ const uint32_t mask = clientBackBufferIndex ? eResizeBuffer1 : eResizeBuffer0;
+ android_atomic_and(~mask, &(lcblk->swapState));
+ // since a buffer became available, we can let the client go...
+ mFlinger->scheduleBroadcast(client);
+ mResizeTransactionDone = true;
+
+ // 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();
+ }
+ }
+ }
+ }
+ }
+
+ 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);
+}
+
+status_t Layer::resize(
+ int32_t clientBackBufferIndex,
+ uint32_t width, uint32_t height,
+ const char* what)
+{
+ /*
+ * handle resize (backbuffer and frontbuffer reallocation)
+ */
+
+ const LayerBitmap& clientBackBuffer(mBuffers[clientBackBufferIndex]);
+
+ // if the new (transaction) size is != from the the backbuffer
+ // then we need to reallocate the backbuffer
+ bool backbufferChanged = (clientBackBuffer.width() != width) ||
+ (clientBackBuffer.height() != height);
+
+ LOGD_IF(!backbufferChanged,
+ "(%s) eResizeRequested (layer=%p), but size not changed: "
+ "requested (%dx%d), drawing (%d,%d), current (%d,%d),"
+ "state=%08lx, index=%d, (%dx%d), (%dx%d)",
+ what, this,
+ int(width), int(height),
+ int(drawingState().w), int(drawingState().h),
+ int(currentState().w), int(currentState().h),
+ long(lcblk->swapState),
+ int(clientBackBufferIndex),
+ int(mBuffers[0].width()), int(mBuffers[0].height()),
+ int(mBuffers[1].width()), int(mBuffers[1].height()));
+
+ // this can happen when changing the size back and forth quickly
+ status_t err = NO_ERROR;
+ if (backbufferChanged) {
+ err = reallocateBuffer(clientBackBufferIndex, width, height);
+ }
+ if (UNLIKELY(err != NO_ERROR)) {
+ // couldn't reallocate the surface
+ android_atomic_write(eInvalidSurface, &lcblk->swapState);
+ memset(lcblk->surface+clientBackBufferIndex, 0, sizeof(surface_info_t));
+ }
+ return err;
+}
+
+void Layer::setSizeChanged(uint32_t w, uint32_t h)
+{
+ LOGD_IF(DEBUG_RESIZE,
+ "setSizeChanged w=%d, h=%d (old: w=%d, h=%d)",
+ w, h, mCurrentState.w, mCurrentState.h);
+ android_atomic_or(eResizeRequested, &(lcblk->swapState));
+}
+
+// ----------------------------------------------------------------------------
+// pageflip handling...
+// ----------------------------------------------------------------------------
+
+void Layer::lockPageFlip(bool& recomputeVisibleRegions)
+{
+ uint32_t state = android_atomic_or(eBusy, &(lcblk->swapState));
+ // preemptively block the client, because he might set
+ // eFlipRequested at any time and want to use this buffer
+ // for the next frame. This will be unset below if it
+ // turns out we didn't need it.
+
+ uint32_t mask = eInvalidSurface | eFlipRequested | eResizeRequested;
+ if (!(state & mask))
+ return;
+
+ if (UNLIKELY(state & eInvalidSurface)) {
+ // if eInvalidSurface is set, this means the surface
+ // became invalid during a transaction (NO_MEMORY for instance)
+ mFlinger->scheduleBroadcast(client);
+ return;
+ }
+
+ if (UNLIKELY(state & eFlipRequested)) {
+ uint32_t oldState;
+ mPostedDirtyRegion = post(&oldState, recomputeVisibleRegions);
+ if (oldState & eNextFlipPending) {
+ // Process another round (we know at least a buffer
+ // is ready for that client).
+ mFlinger->signalEvent();
+ }
+ }
+}
+
+Region Layer::post(uint32_t* previousSate, bool& recomputeVisibleRegions)
+{
+ // atomically swap buffers and (re)set eFlipRequested
+ int32_t oldValue, newValue;
+ layer_cblk_t * const lcblk = this->lcblk;
+ do {
+ oldValue = lcblk->swapState;
+ // get the current value
+
+ LOG_ASSERT(oldValue&eFlipRequested,
+ "eFlipRequested not set, yet we're flipping! (state=0x%08lx)",
+ long(oldValue));
+
+ newValue = (oldValue ^ eIndex);
+ // swap buffers
+
+ newValue &= ~(eFlipRequested | eNextFlipPending);
+ // clear eFlipRequested and eNextFlipPending
+
+ if (oldValue & eNextFlipPending)
+ newValue |= eFlipRequested;
+ // if eNextFlipPending is set (second buffer already has something
+ // in it) we need to reset eFlipRequested because the client
+ // might never do it
+
+ } while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState)));
+ *previousSate = oldValue;
+
+ const int32_t index = (newValue & eIndex) ^ 1;
+ mFrontBufferIndex = index;
+
+ // ... post the new front-buffer
+ Region dirty(lcblk->region + index);
+ dirty.andSelf(frontBuffer().bounds());
+
+ //LOGI("Did post oldValue=%08lx, newValue=%08lx, mFrontBufferIndex=%u\n",
+ // oldValue, newValue, mFrontBufferIndex);
+ //dirty.dump("dirty");
+
+ if (UNLIKELY(oldValue & eResizeRequested)) {
+
+ LOGD_IF(DEBUG_RESIZE,
+ "post (layer=%p), state=%08x, "
+ "index=%d, (%dx%d), (%dx%d)",
+ this, newValue,
+ int(1-index),
+ int(mBuffers[0].width()), int(mBuffers[0].height()),
+ int(mBuffers[1].width()), int(mBuffers[1].height()));
+
+ // here, we just posted the surface and we have resolved
+ // the front/back buffer indices. The client is blocked, so
+ // it cannot start using the new backbuffer.
+
+ // If the backbuffer was resized in THIS round, we actually cannot
+ // resize the frontbuffer because it has *just* been drawn (and we
+ // would have nothing to draw). In this case we just skip the resize
+ // it'll happen after the next page flip or during the next
+ // transaction.
+
+ const uint32_t mask = (1-index) ? eResizeBuffer1 : eResizeBuffer0;
+ if (mResizeTransactionDone && (newValue & mask)) {
+ // Resize the layer's second buffer only if the transaction
+ // happened. It may not have happened yet if eResizeRequested
+ // was set immediately after the "transactionRequested" test,
+ // in which case the drawing state's size would be wrong.
+ mFreezeLock.clear();
+ const Layer::State& s(drawingState());
+ if (resize(1-index, s.w, s.h, "post") == NO_ERROR) {
+ do {
+ oldValue = lcblk->swapState;
+ if ((oldValue & eResizeRequested) == eResizeRequested) {
+ // ugh, another resize was requested since we processed
+ // the first buffer, don't free the client, and let
+ // the next transaction handle everything.
+ break;
+ }
+ newValue = oldValue & ~mask;
+ } while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState)));
+ }
+ mResizeTransactionDone = false;
+ recomputeVisibleRegions = true;
+ this->contentDirty = true;
+ }
+ }
+
+ reloadTexture(dirty);
+
+ return dirty;
+}
+
+Point Layer::getPhysicalSize() const
+{
+ const LayerBitmap& front(frontBuffer());
+ return Point(front.width(), front.height());
+}
+
+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);
+
+ // client could be blocked, so signal them so they get a
+ // chance to reevaluate their condition.
+ mFlinger->scheduleBroadcast(client);
+ }
+}
+
+void Layer::finishPageFlip()
+{
+ if (LIKELY(!(lcblk->swapState & eInvalidSurface))) {
+ LOGE_IF(!(lcblk->swapState & eBusy),
+ "layer %p wasn't locked!", this);
+ android_atomic_and(~eBusy, &(lcblk->swapState));
+ }
+ mFlinger->scheduleBroadcast(client);
+}
+
+
+// ---------------------------------------------------------------------------
+
+
+}; // namespace android
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
new file mode 100644
index 0000000..2867f2b
--- /dev/null
+++ b/libs/surfaceflinger/Layer.h
@@ -0,0 +1,120 @@
+/*
+ * 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/PixelFormat.h>
+
+#include <private/ui/SharedState.h>
+#include <private/ui/LayerState.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "LayerBitmap.h"
+#include "LayerBase.h"
+#include "Transform.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class Client;
+class LayerBitmap;
+class MemoryDealer;
+class FreezeLock;
+
+// ---------------------------------------------------------------------------
+
+class Layer : public LayerBaseClient
+{
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ Layer(SurfaceFlinger* flinger, DisplayID display,
+ Client* c, int32_t i);
+
+ virtual ~Layer();
+
+ inline PixelFormat pixelFormat() const {
+ return frontBuffer().pixelFormat();
+ }
+
+ status_t setBuffers( Client* client,
+ uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t flags=0);
+
+ virtual void onDraw(const Region& clip) const;
+ virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
+ virtual void setSizeChanged(uint32_t w, uint32_t h);
+ virtual uint32_t doTransaction(uint32_t transactionFlags);
+ virtual Point getPhysicalSize() const;
+ virtual void lockPageFlip(bool& recomputeVisibleRegions);
+ virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+ virtual void finishPageFlip();
+ virtual bool needsBlending() const { return mNeedsBlending; }
+ virtual bool isSecure() const { return mSecure; }
+ virtual GLuint getTextureName() const { return mTextureName; }
+ virtual sp<Surface> getSurface() const;
+
+ const LayerBitmap& getBuffer(int i) const { return mBuffers[i]; }
+ LayerBitmap& getBuffer(int i) { return mBuffers[i]; }
+
+ // only for debugging
+ const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; }
+
+private:
+ inline const LayerBitmap&
+ frontBuffer() const { return getBuffer(mFrontBufferIndex); }
+ inline LayerBitmap&
+ frontBuffer() { return getBuffer(mFrontBufferIndex); }
+ inline const LayerBitmap&
+ backBuffer() const { return getBuffer(1-mFrontBufferIndex); }
+ inline LayerBitmap&
+ backBuffer() { return getBuffer(1-mFrontBufferIndex); }
+
+ void reloadTexture(const Region& dirty);
+
+ status_t resize(int32_t index, uint32_t w, uint32_t h, const char* what);
+ Region post(uint32_t* oldState, bool& recomputeVisibleRegions);
+ status_t reallocateBuffer(int32_t index, uint32_t w, uint32_t h);
+
+ sp<Surface> mSurface;
+
+ bool mSecure;
+ LayerBitmap mBuffers[2];
+ int32_t mFrontBufferIndex;
+ bool mNeedsBlending;
+ bool mResizeTransactionDone;
+ Region mPostedDirtyRegion;
+ sp<FreezeLock> mFreezeLock;
+
+ GLuint mTextureName;
+ GLuint mTextureWidth;
+ GLuint mTextureHeight;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_H
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
new file mode 100644
index 0000000..0cf53f7
--- /dev/null
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -0,0 +1,740 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#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 <hardware/hardware.h>
+
+#include "clz.h"
+#include "LayerBase.h"
+#include "LayerBlur.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+
+// We don't honor the premultiplied alpha flags, which means that
+// premultiplied surface may be composed using a non-premultiplied
+// equation. We do this because it may be a lot faster on some hardware
+// The correct value is HONOR_PREMULTIPLIED_ALPHA = 1
+#define HONOR_PREMULTIPLIED_ALPHA 0
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerBase::typeInfo = 1;
+const char* const LayerBase::typeID = "LayerBase";
+
+const uint32_t LayerBaseClient::typeInfo = LayerBase::typeInfo | 2;
+const char* const LayerBaseClient::typeID = "LayerBaseClient";
+
+// ---------------------------------------------------------------------------
+
+Vector<GLuint> LayerBase::deletedTextures;
+
+int32_t LayerBase::sIdentity = 0;
+
+LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
+ : dpy(display), contentDirty(false),
+ mFlinger(flinger),
+ mTransformed(false),
+ mOrientation(0),
+ mCanUseCopyBit(false),
+ mTransactionFlags(0),
+ mPremultipliedAlpha(true),
+ mIdentity(uint32_t(android_atomic_inc(&sIdentity))),
+ mInvalidate(0)
+{
+ const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
+ mFlags = hw.getFlags();
+}
+
+LayerBase::~LayerBase()
+{
+}
+
+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.alpha = 0xFF;
+ mCurrentState.flags = layerFlags;
+ mCurrentState.sequence = 0;
+ mCurrentState.transform.set(0, 0);
+
+ // drawing state & current state are identical
+ mDrawingState = mCurrentState;
+}
+
+void LayerBase::commitTransaction(bool skipSize) {
+ const uint32_t w = mDrawingState.w;
+ const uint32_t h = mDrawingState.h;
+ mDrawingState = mCurrentState;
+ if (skipSize) {
+ mDrawingState.w = w;
+ mDrawingState.h = h;
+ }
+}
+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);
+}
+
+void LayerBase::setSizeChanged(uint32_t w, uint32_t h) {
+}
+
+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.w == w && mCurrentState.h == h)
+ return false;
+ setSizeChanged(w, h);
+ mCurrentState.w = w;
+ mCurrentState.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) {
+ // TODO: check the matrix has changed
+ mCurrentState.sequence++;
+ mCurrentState.transform.set(
+ matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy);
+ requestTransaction();
+ return true;
+}
+bool LayerBase::setTransparentRegionHint(const Region& transparent) {
+ // TODO: check the region has changed
+ 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 (temp.sequence != front.sequence) {
+ // invalidate and recompute the visible regions if needed
+ flags |= eVisibleRegion;
+ this->contentDirty = true;
+ }
+
+ // Commit the transaction
+ commitTransaction(flags & eRestartTransaction);
+ return flags;
+}
+
+Point LayerBase::getPhysicalSize() const
+{
+ const Layer::State& front(drawingState());
+ return Point(front.w, front.h);
+}
+
+void LayerBase::validateVisibility(const Transform& planeTransform)
+{
+ const Layer::State& s(drawingState());
+ const Transform tr(planeTransform * s.transform);
+ const bool transformed = tr.transformed();
+
+ const Point size(getPhysicalSize());
+ uint32_t w = size.x;
+ uint32_t h = size.y;
+ 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);
+ mTransformed = transformed;
+ mLeft = tr.tx();
+ mTop = tr.ty();
+
+ // see if we can/should use 2D h/w with the new configuration
+ mCanUseCopyBit = false;
+ copybit_device_t* copybit = mFlinger->getBlitEngine();
+ if (copybit) {
+ const int step = copybit->get(copybit, COPYBIT_ROTATION_STEP_DEG);
+ const int scaleBits = copybit->get(copybit, COPYBIT_SCALING_FRAC_BITS);
+ mCanUseCopyBit = true;
+ if ((mOrientation < 0) && (step > 1)) {
+ // arbitrary orientations not supported
+ mCanUseCopyBit = false;
+ } else if ((mOrientation > 0) && (step > 90)) {
+ // 90 deg rotations not supported
+ mCanUseCopyBit = false;
+ } else if ((tr.getType() & SkMatrix::kScale_Mask) && (scaleBits < 12)) {
+ // arbitrary scaling not supported
+ mCanUseCopyBit = false;
+ }
+#if HONOR_PREMULTIPLIED_ALPHA
+ else if (needsBlending() && mPremultipliedAlpha) {
+ // pre-multiplied alpha not supported
+ mCanUseCopyBit = false;
+ }
+#endif
+ else {
+ // here, we determined we can use copybit
+ if (tr.getType() & SkMatrix::kScale_Mask) {
+ // and we have scaling
+ if (!transparentRegionScreen.isRect()) {
+ // we punt because blending is cheap (h/w) and the region is
+ // complex, which may causes artifacts when copying
+ // scaled content
+ transparentRegionScreen.clear();
+ }
+ }
+ }
+ }
+}
+
+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::iterator iterator(reg);
+ if (iterator) {
+ 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 (iterator.iterate(&r)) {
+ 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);
+
+ /*
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_DITHER);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4x(0, 0x8000, 0, 0x10000);
+ drawRegion(transparentRegionScreen);
+ glDisable(GL_BLEND);
+ */
+}
+
+GLuint LayerBase::createTexture() const
+{
+ GLuint textureName = -1;
+ glGenTextures(1, &textureName);
+ glBindTexture(GL_TEXTURE_2D, textureName);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ if (mFlags & DisplayHardware::SLOW_CONFIG) {
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ } else {
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
+ return textureName;
+}
+
+void LayerBase::clearWithOpenGL(const Region& clip) const
+{
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t fbHeight = hw.getHeight();
+ glColor4x(0,0,0,0);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ Rect r;
+ Region::iterator iterator(clip);
+ if (iterator) {
+ glEnable(GL_SCISSOR_TEST);
+ glVertexPointer(2, GL_FIXED, 0, mVertices);
+ while (iterator.iterate(&r)) {
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ }
+}
+
+void LayerBase::drawWithOpenGL(const Region& clip,
+ GLint textureName, const GGLSurface& t, int transform) const
+{
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t fbHeight = hw.getHeight();
+ const State& s(drawingState());
+
+ // bind our texture
+ validateTexture(textureName);
+ glEnable(GL_TEXTURE_2D);
+
+ // Dithering...
+ if (s.flags & ISurfaceComposer::eLayerDither) {
+ glEnable(GL_DITHER);
+ } else {
+ glDisable(GL_DITHER);
+ }
+
+ if (UNLIKELY(s.alpha < 0xFF)) {
+ // We have an alpha-modulation. We need to modulate all
+ // texture components by alpha because we're always using
+ // premultiplied alpha.
+
+ // If the texture doesn't have an alpha channel we can
+ // use REPLACE and switch to non premultiplied alpha
+ // blending (SRCA/ONE_MINUS_SRCA).
+
+ GLenum env, src;
+ if (needsBlending()) {
+ env = GL_MODULATE;
+ src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
+ } else {
+ env = GL_REPLACE;
+ src = GL_SRC_ALPHA;
+ }
+ const GGLfixed alpha = (s.alpha << 16)/255;
+ glColor4x(alpha, alpha, alpha, alpha);
+ glEnable(GL_BLEND);
+ glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env);
+ } else {
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
+ if (needsBlending()) {
+ GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
+ glEnable(GL_BLEND);
+ glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ glDisable(GL_BLEND);
+ }
+ }
+
+ if (UNLIKELY(transformed()
+ || !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) ))
+ {
+ //StopWatch watch("GL transformed");
+ Region::iterator iterator(clip);
+ if (iterator) {
+ // always use high-quality filtering with fast configurations
+ bool fast = !(mFlags & DisplayHardware::SLOW_CONFIG);
+ if (!fast && s.flags & ISurfaceComposer::eLayerFilter) {
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
+ const GLfixed texCoords[4][2] = {
+ { 0, 0 },
+ { 0, 0x10000 },
+ { 0x10000, 0x10000 },
+ { 0x10000, 0 }
+ };
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+
+ if (transform == HAL_TRANSFORM_ROT_90) {
+ glTranslatef(0, 1, 0);
+ glRotatef(-90, 0, 0, 1);
+ }
+
+ if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
+ // find the smallest power-of-two that will accommodate our surface
+ GLuint tw = 1 << (31 - clz(t.width));
+ GLuint th = 1 << (31 - clz(t.height));
+ if (tw < t.width) tw <<= 1;
+ if (th < t.height) th <<= 1;
+ // this divide should be relatively fast because it's
+ // a power-of-two (optimized path in libgcc)
+ GLfloat ws = GLfloat(t.width) /tw;
+ GLfloat hs = GLfloat(t.height)/th;
+ glScalef(ws, hs, 1.0f);
+ }
+
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FIXED, 0, mVertices);
+ glTexCoordPointer(2, GL_FIXED, 0, texCoords);
+
+ Rect r;
+ while (iterator.iterate(&r)) {
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+
+ if (!fast && s.flags & ISurfaceComposer::eLayerFilter) {
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+ } else {
+ Region::iterator iterator(clip);
+ if (iterator) {
+ Rect r;
+ GLint crop[4] = { 0, t.height, t.width, -t.height };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ int x = tx();
+ int y = ty();
+ y = fbHeight - (y + t.height);
+ while (iterator.iterate(&r)) {
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawTexiOES(x, y, 0, t.width, t.height);
+ }
+ }
+ }
+}
+
+void LayerBase::validateTexture(GLint textureName) const
+{
+ glBindTexture(GL_TEXTURE_2D, textureName);
+ // TODO: reload the texture if needed
+ // this is currently done in loadTexture() below
+}
+
+void LayerBase::loadTexture(const Region& dirty,
+ GLint textureName, const GGLSurface& t,
+ GLuint& textureWidth, GLuint& textureHeight) const
+{
+ // TODO: defer the actual texture reload until LayerBase::validateTexture
+ // is called.
+
+ uint32_t flags = mFlags;
+ glBindTexture(GL_TEXTURE_2D, textureName);
+
+ GLuint tw = t.width;
+ GLuint th = t.height;
+
+ /*
+ * In OpenGL ES we can't specify a stride with glTexImage2D (however,
+ * GL_UNPACK_ALIGNMENT is 4, which in essence allows 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
+ */
+
+ tw += (((t.stride - tw) * bytesPerPixel(t.format)) / 4);
+
+ /*
+ * round to POT if needed
+ */
+
+ GLuint texture_w = tw;
+ GLuint texture_h = th;
+ if (!(flags & DisplayHardware::NPOT_EXTENSION)) {
+ // find the smallest power-of-two that will accommodate our surface
+ texture_w = 1 << (31 - clz(t.width));
+ texture_h = 1 << (31 - clz(t.height));
+ if (texture_w < t.width) texture_w <<= 1;
+ if (texture_h < t.height) texture_h <<= 1;
+ if (texture_w != tw || texture_h != th) {
+ // we can't use DIRECT_TEXTURE since we changed the size
+ // of the texture
+ flags &= ~DisplayHardware::DIRECT_TEXTURE;
+ }
+ }
+
+ if (flags & DisplayHardware::DIRECT_TEXTURE) {
+ // here we're guaranteed that texture_{w|h} == t{w|h}
+ if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
+ glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
+ GL_RGB, tw, th, 0,
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t.data);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
+ glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
+ GL_RGBA, tw, th, 0,
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t.data);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+ glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
+ GL_RGBA, tw, th, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, t.data);
+ } else if (t.format == GGL_PIXEL_FORMAT_BGRA_8888) {
+ // TODO: add GL_BGRA extension
+ } else {
+ // oops, we don't handle this format, try the regular path
+ goto regular;
+ }
+ textureWidth = tw;
+ textureHeight = th;
+ } else {
+regular:
+ Rect bounds(dirty.bounds());
+ GLvoid* data = 0;
+ if (texture_w!=textureWidth || texture_h!=textureHeight) {
+ // texture size changed, we need to create a new one
+
+ if (!textureWidth || !textureHeight) {
+ // this is the first time, load the whole texture
+ if (texture_w==tw && texture_h==th) {
+ // we can do it one pass
+ data = t.data;
+ } else {
+ // we have to create the texture first because it
+ // doesn't match the size of the buffer
+ bounds.set(Rect(tw, th));
+ }
+ }
+
+ if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGB, texture_w, texture_h, 0,
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGBA, texture_w, texture_h, 0,
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGBA, texture_w, texture_h, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, data);
+ } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
+ t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
+ // just show the Y plane of YUV buffers
+ data = t.data;
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_LUMINANCE, texture_w, texture_h, 0,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
+ } else {
+ // oops, we don't handle this format!
+ LOGE("layer %p, texture=%d, using format %d, which is not "
+ "supported by the GL", this, textureName, t.format);
+ textureName = -1;
+ }
+ textureWidth = texture_w;
+ textureHeight = texture_h;
+ }
+ if (!data && textureName>=0) {
+ if (t.format == GGL_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.width*2);
+ } else if (t.format == GGL_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.width*2);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_RGBA, GL_UNSIGNED_BYTE,
+ t.data + bounds.top*t.width*4);
+ }
+ }
+ }
+}
+
+bool LayerBase::canUseCopybit() const
+{
+ return mCanUseCopyBit;
+}
+
+// ---------------------------------------------------------------------------
+
+LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
+ Client* c, int32_t i)
+ : LayerBase(flinger, display), client(c),
+ lcblk( c ? &(c->ctrlblk->layers[i]) : 0 ),
+ mIndex(i)
+{
+ if (client) {
+ client->bindLayer(this, i);
+
+ // Initialize this layer's control block
+ memset(this->lcblk, 0, sizeof(layer_cblk_t));
+ this->lcblk->identity = mIdentity;
+ Region::writeEmpty(&(this->lcblk->region[0]), sizeof(flat_region_t));
+ Region::writeEmpty(&(this->lcblk->region[1]), sizeof(flat_region_t));
+ }
+}
+
+LayerBaseClient::~LayerBaseClient()
+{
+ if (client) {
+ client->free(mIndex);
+ }
+}
+
+int32_t LayerBaseClient::serverIndex() const {
+ if (client) {
+ return (client->cid<<16)|mIndex;
+ }
+ return 0xFFFF0000 | mIndex;
+}
+
+sp<LayerBaseClient::Surface> LayerBaseClient::getSurface() const
+{
+ return new Surface(clientIndex(), mIdentity);
+}
+
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
new file mode 100644
index 0000000..a020f44
--- /dev/null
+++ b/libs/surfaceflinger/LayerBase.h
@@ -0,0 +1,356 @@
+/*
+ * 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 <private/ui/LayerState.h>
+
+#include <ui/Region.h>
+#include <ui/Overlay.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "Transform.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class SurfaceFlinger;
+class DisplayHardware;
+class GraphicPlane;
+class Client;
+
+// ---------------------------------------------------------------------------
+
+class LayerBase
+{
+ // poor man's dynamic_cast below
+ template<typename T>
+ struct getTypeInfoOfAnyType {
+ static uint32_t get() { return T::typeInfo; }
+ };
+
+ template<typename T>
+ struct getTypeInfoOfAnyType<T*> {
+ static uint32_t get() { return getTypeInfoOfAnyType<T>::get(); }
+ };
+
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ template<typename T>
+ static T dynamicCast(LayerBase* base) {
+ uint32_t mostDerivedInfo = base->getTypeInfo();
+ uint32_t castToInfo = getTypeInfoOfAnyType<T>::get();
+ if ((mostDerivedInfo & castToInfo) == castToInfo)
+ return static_cast<T>(base);
+ return 0;
+ }
+
+
+ static Vector<GLuint> deletedTextures;
+
+ LayerBase(SurfaceFlinger* flinger, DisplayID display);
+ virtual ~LayerBase();
+
+ DisplayID dpy;
+ mutable bool contentDirty;
+ Region visibleRegionScreen;
+ Region transparentRegionScreen;
+ Region coveredRegionScreen;
+
+ struct State {
+ uint32_t w;
+ uint32_t 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;
+ };
+
+ // 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 skipSize);
+ 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();
+
+ /**
+ * 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);
+
+ /**
+ * setSizeChanged - called when the *current* state's size is changed.
+ */
+ virtual void setSizeChanged(uint32_t w, uint32_t h);
+
+ /**
+ * 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 correspond to any area of the surface that is covered
+ * (transparently or not) by another surface.
+ */
+ virtual void setCoveredRegion(const Region& coveredRegion);
+
+ /**
+ * getPhysicalSize - returns the physical size of the drawing state of
+ * the surface. If the surface is backed by a bitmap, this is the size of
+ * the bitmap (as opposed to the size of the drawing state).
+ */
+ virtual Point getPhysicalSize() const;
+
+ /**
+ * 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; }
+
+ /**
+ * transformed -- true is this surface needs a to be transformed
+ */
+ virtual bool transformed() const { return mTransformed; }
+
+ /**
+ * isSecure - true if this surface is secure, that is if it prevents
+ * screenshots or vns servers.
+ */
+ virtual bool isSecure() const { return false; }
+
+ enum { // flags for doTransaction()
+ eVisibleRegion = 0x00000002,
+ eRestartTransaction = 0x00000008
+ };
+
+
+ inline const State& drawingState() const { return mDrawingState; }
+ inline const State& currentState() const { return mCurrentState; }
+ inline State& currentState() { return mCurrentState; }
+
+ static int compareCurrentStateZ(LayerBase*const* layerA, 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);
+
+ GLuint createTexture() const;
+
+ void drawWithOpenGL(const Region& clip,
+ GLint textureName,
+ const GGLSurface& surface,
+ int transform = 0) const;
+
+ void clearWithOpenGL(const Region& clip) const;
+
+ void loadTexture(const Region& dirty,
+ GLint textureName, const GGLSurface& t,
+ GLuint& textureWidth, GLuint& textureHeight) const;
+
+ bool canUseCopybit() const;
+
+ SurfaceFlinger* mFlinger;
+ uint32_t mFlags;
+
+ // cached during validateVisibility()
+ bool mTransformed;
+ int32_t mOrientation;
+ GLfixed mVertices[4][2];
+ Rect mTransformedBounds;
+ bool mCanUseCopyBit;
+ 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;
+
+ // only read
+ const uint32_t mIdentity;
+
+ // atomic
+ volatile int32_t mInvalidate;
+
+
+private:
+ void validateTexture(GLint textureName) const;
+ static int32_t sIdentity;
+};
+
+
+// ---------------------------------------------------------------------------
+
+class LayerBaseClient : public LayerBase
+{
+public:
+ class Surface;
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
+ Client* client, int32_t i);
+ virtual ~LayerBaseClient();
+
+
+ Client* const client;
+ layer_cblk_t* const lcblk;
+
+ inline int32_t clientIndex() const { return mIndex; }
+ int32_t serverIndex() const;
+
+ virtual sp<Surface> getSurface() const;
+
+ uint32_t getIdentity() const { return mIdentity; }
+
+ class Surface : public BnSurface
+ {
+ public:
+ Surface(SurfaceID id, int identity) {
+ mParams.token = id;
+ mParams.identity = identity;
+ }
+ Surface(SurfaceID id,
+ const sp<IMemoryHeap>& heap0,
+ const sp<IMemoryHeap>& heap1,
+ int identity)
+ {
+ mParams.token = id;
+ mParams.identity = identity;
+ mParams.heap[0] = heap0;
+ mParams.heap[1] = heap1;
+ }
+ virtual ~Surface() {
+ // TODO: We now have a point here were we can clean-up the
+ // client's mess.
+ // This is also where surface id should be recycled.
+ //LOGD("Surface %d, heaps={%p, %p} destroyed",
+ // mId, mHeap[0].get(), mHeap[1].get());
+ }
+
+ virtual void getSurfaceData(
+ ISurfaceFlingerClient::surface_data_t* params) const {
+ *params = mParams;
+ }
+
+ virtual status_t registerBuffers(const ISurface::BufferHeap& buffers)
+ { return INVALID_OPERATION; }
+ virtual void postBuffer(ssize_t offset) { }
+ virtual void unregisterBuffers() { };
+ virtual sp<OverlayRef> createOverlay(
+ uint32_t w, uint32_t h, int32_t format) {
+ return NULL;
+ };
+
+ private:
+ ISurfaceFlingerClient::surface_data_t mParams;
+ };
+
+private:
+ int32_t mIndex;
+
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BASE_H
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
new file mode 100644
index 0000000..e844350
--- /dev/null
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/memory.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/MemoryDealer.h>
+#include <utils/IMemory.h>
+#include <ui/PixelFormat.h>
+#include <pixelflinger/pixelflinger.h>
+
+#include "LayerBitmap.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+LayerBitmap::LayerBitmap()
+ : mAllocFlags(0), mOffset(0), mSize(-1U), mAlignment(2)
+{
+ memset(&mSurface, 0, sizeof(mSurface));
+}
+
+LayerBitmap::~LayerBitmap()
+{
+ mSurface.data = 0;
+}
+
+status_t LayerBitmap::init(const sp<MemoryDealer>& allocator)
+{
+ if (mAllocator != NULL)
+ return BAD_VALUE;
+ mAllocator = allocator;
+ return NO_ERROR;
+}
+
+status_t LayerBitmap::setBits(uint32_t w, uint32_t h, uint32_t alignment,
+ PixelFormat format, uint32_t flags)
+{
+ const sp<MemoryDealer>& allocator(mAllocator);
+ if (allocator == NULL)
+ return NO_INIT;
+
+ if (UNLIKELY(w == mSurface.width && h == mSurface.height &&
+ format == mSurface.format))
+ { // same format and size, do nothing.
+ return NO_ERROR;
+ }
+
+ PixelFormatInfo info;
+ getPixelFormatInfo(format, &info);
+
+ uint32_t allocFlags = MemoryDealer::PAGE_ALIGNED;
+ const uint32_t align = 4; // must match GL_UNPACK_ALIGNMENT
+ const uint32_t Bpp = info.bytesPerPixel;
+ uint32_t stride = (w + (alignment-1)) & ~(alignment-1);
+ stride = ((stride * Bpp + (align-1)) & ~(align-1)) / Bpp;
+ size_t size = info.getScanlineSize(stride) * h;
+ if (allocFlags & MemoryDealer::PAGE_ALIGNED) {
+ size_t pagesize = getpagesize();
+ size = (size + (pagesize-1)) & ~(pagesize-1);
+ }
+
+ /* FIXME: we should be able to have a h/v stride because the user of the
+ * surface might have stride limitation (for instance h/w codecs often do)
+ */
+ int32_t vstride = 0;
+
+ mAlignment = alignment;
+ mAllocFlags = allocFlags;
+ mOffset = 0;
+ if (mSize != size) {
+ // would be nice to have a reallocate() api
+ mBitsMemory.clear(); // free-memory
+ mBitsMemory = allocator->allocate(size, allocFlags);
+ mSize = size;
+ } else {
+ // don't erase memory if we didn't have to reallocate
+ flags &= ~SECURE_BITS;
+ }
+ if (mBitsMemory != 0) {
+ mOffset = mBitsMemory->offset();
+ mSurface.data = static_cast<GGLubyte*>(mBitsMemory->pointer());
+ mSurface.version = sizeof(GGLSurface);
+ mSurface.width = w;
+ mSurface.height = h;
+ mSurface.stride = stride;
+ mSurface.vstride = vstride;
+ mSurface.format = format;
+ if (flags & SECURE_BITS)
+ clear();
+ }
+
+ if (mBitsMemory==0 || mSurface.data==0) {
+ LOGE("not enough memory for layer bitmap size=%u", size);
+ allocator->dump("LayerBitmap");
+ mSurface.data = 0;
+ mSize = -1U;
+ return NO_MEMORY;
+ }
+ return NO_ERROR;
+}
+
+void LayerBitmap::clear()
+{
+ // NOTE: this memset should not be necessary, at least for
+ // opaque surface. However, for security reasons it's better to keep it
+ // (in the case of pmem, it's possible that the memory contains old
+ // data)
+ if (mSurface.data) {
+ memset(mSurface.data, 0, mSize);
+ //if (bytesPerPixel(mSurface.format) == 4) {
+ // android_memset32((uint32_t*)mSurface.data, 0xFF0000FF, mSize);
+ //} else {
+ // android_memset16((uint16_t*)mSurface.data, 0xF800, mSize);
+ //}
+ }
+}
+
+status_t LayerBitmap::getInfo(surface_info_t* info) const
+{
+ if (mSurface.data == 0) {
+ memset(info, 0, sizeof(surface_info_t));
+ info->bits_offset = NO_MEMORY;
+ return NO_MEMORY;
+ }
+ info->w = uint16_t(width());
+ info->h = uint16_t(height());
+ info->stride= uint16_t(stride());
+ info->bpr = uint16_t(stride() * bytesPerPixel(pixelFormat()));
+ info->format= uint8_t(pixelFormat());
+ info->flags = surface_info_t::eBufferDirty;
+ info->bits_offset = ssize_t(mOffset);
+ return NO_ERROR;
+}
+
+status_t LayerBitmap::resize(uint32_t w, uint32_t h)
+{
+ int err = setBits(w, h, mAlignment, pixelFormat(), SECURE_BITS);
+ return err;
+}
+
+size_t LayerBitmap::size() const
+{
+ return mSize;
+}
+
+void LayerBitmap::getBitmapSurface(copybit_image_t* img) const
+{
+ const sp<IMemoryHeap>& mh(getAllocator()->getMemoryHeap());
+ void* sbase = mh->base();
+ const GGLSurface& t(surface());
+ img->w = t.stride ?: t.width;
+ img->h = t.vstride ?: t.height;
+ img->format = t.format;
+ img->offset = intptr_t(t.data) - intptr_t(sbase);
+ img->base = sbase;
+ img->fd = mh->heapID();
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerBitmap.h b/libs/surfaceflinger/LayerBitmap.h
new file mode 100644
index 0000000..9ad64c4
--- /dev/null
+++ b/libs/surfaceflinger/LayerBitmap.h
@@ -0,0 +1,84 @@
+/*
+ * 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_BITMAP_H
+#define ANDROID_LAYER_BITMAP_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Atomic.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <private/ui/SharedState.h>
+#include <pixelflinger/pixelflinger.h>
+
+class copybit_image_t;
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class IMemory;
+class MemoryDealer;
+class LayerBitmap;
+
+// ---------------------------------------------------------------------------
+
+class LayerBitmap
+{
+public:
+
+ enum {
+ // erase memory to ensure security when necessary
+ SECURE_BITS = 0x00000001
+ };
+
+ LayerBitmap();
+ ~LayerBitmap();
+ status_t init(const sp<MemoryDealer>& allocator);
+
+ status_t setBits(uint32_t w, uint32_t h, uint32_t alignment,
+ PixelFormat format, uint32_t flags = 0);
+ void clear();
+
+ status_t getInfo(surface_info_t* info) const;
+ status_t resize(uint32_t w, uint32_t h);
+
+ const GGLSurface& surface() const { return mSurface; }
+ Rect bounds() const { return Rect(width(), height()); }
+ uint32_t width() const { return surface().width; }
+ uint32_t height() const { return surface().height; }
+ uint32_t stride() const { return surface().stride; }
+ PixelFormat pixelFormat() const { return surface().format; }
+ void* serverBits() const { return surface().data; }
+ size_t size() const;
+ const sp<MemoryDealer>& getAllocator() const { return mAllocator; }
+ void getBitmapSurface(copybit_image_t* img) const;
+
+private:
+ sp<MemoryDealer> mAllocator;
+ sp<IMemory> mBitsMemory;
+ uint32_t mAllocFlags;
+ ssize_t mOffset;
+ GGLSurface mSurface;
+ size_t mSize;
+ uint32_t mAlignment;
+};
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BITMAP_H
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
new file mode 100644
index 0000000..d3e456f
--- /dev/null
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#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 "BlurFilter.h"
+#include "LayerBlur.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerBlur::typeInfo = LayerBaseClient::typeInfo | 8;
+const char* const LayerBlur::typeID = "LayerBlur";
+
+// ---------------------------------------------------------------------------
+
+LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
+ Client* client, int32_t i)
+ : LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
+ mRefreshCache(true), mCacheAge(0), mTextureName(-1U)
+{
+}
+
+LayerBlur::~LayerBlur()
+{
+ if (mTextureName != -1U) {
+ //glDeleteTextures(1, &mTextureName);
+ deletedTextures.add(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->signalDelayedEvent(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);
+ }
+
+ Region::iterator iterator(clip);
+ if (iterator) {
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, mTextureName);
+
+ if (mRefreshCache) {
+ mRefreshCache = false;
+ mAutoRefreshPending = false;
+
+ // allocate enough memory for 4-bytes (2 pixels) aligned data
+ const int32_t s = (w + 1) & ~1;
+ uint16_t* const pixels = (uint16_t*)malloc(s*h*2);
+
+ // 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, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+
+ // blur that texture.
+ GGLSurface bl;
+ bl.version = sizeof(GGLSurface);
+ bl.width = w;
+ bl.height = h;
+ bl.stride = s;
+ bl.format = GGL_PIXEL_FORMAT_RGB_565;
+ bl.data = (GGLubyte*)pixels;
+ blurFilter(&bl, 8, 2);
+
+ // NOTE: this works only because we have POT. we'd have to round the
+ // texture size up, otherwise.
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+
+ free((void*)pixels);
+ }
+
+ const State& s = drawingState();
+ if (UNLIKELY(s.alpha < 0xFF)) {
+ const GGLfixed alpha = (s.alpha << 16)/255;
+ glColor4x(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);
+ }
+
+ glDisable(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);
+
+ if (UNLIKELY(transformed()
+ || !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) )) {
+ // This is a very rare scenario.
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glScalef(1.0f/w, -1.0f/h, 1);
+ glTranslatef(-x, -y, 0);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FIXED, 0, mVertices);
+ glTexCoordPointer(2, GL_FIXED, 0, mVertices);
+ Rect r;
+ while (iterator.iterate(&r)) {
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ } else {
+ Region::iterator iterator(clip);
+ if (iterator) {
+ // NOTE: this is marginally faster with the software gl, because
+ // glReadPixels() reads the fb bottom-to-top, however we'll
+ // skip all the jaccobian computations.
+ Rect r;
+ GLint crop[4] = { 0, 0, w, h };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ y = fbHeight - (y + h);
+ while (iterator.iterate(&r)) {
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawTexiOES(x, y, 0, w, h);
+ }
+ }
+ }
+ }
+
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h
new file mode 100644
index 0000000..24b1156
--- /dev/null
+++ b/libs/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 <private/ui/LayerState.h>
+
+#include <ui/Region.h>
+
+#include "LayerBase.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class LayerBlur : public LayerBaseClient
+{
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ LayerBlur(SurfaceFlinger* flinger, DisplayID display,
+ Client* client, int32_t i);
+ virtual ~LayerBlur();
+
+ virtual void onDraw(const Region& clip) const;
+ virtual bool needsBlending() const { return true; }
+ virtual bool isSecure() const { return false; }
+
+ 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;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BLUR_H
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
new file mode 100644
index 0000000..00fab70
--- /dev/null
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -0,0 +1,655 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#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 <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/EGLDisplaySurface.h>
+
+#include "LayerBuffer.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerBuffer::typeInfo = LayerBaseClient::typeInfo | 0x20;
+const char* const LayerBuffer::typeID = "LayerBuffer";
+
+// ---------------------------------------------------------------------------
+
+LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
+ Client* client, int32_t i)
+ : LayerBaseClient(flinger, display, client, i),
+ mNeedsBlending(false)
+{
+}
+
+LayerBuffer::~LayerBuffer()
+{
+ sp<SurfaceBuffer> s(getClientSurface());
+ if (s != 0) {
+ s->disown();
+ mClientSurface.clear();
+ }
+}
+
+sp<LayerBuffer::SurfaceBuffer> LayerBuffer::getClientSurface() const
+{
+ Mutex::Autolock _l(mLock);
+ return mClientSurface.promote();
+}
+
+sp<LayerBaseClient::Surface> LayerBuffer::getSurface() const
+{
+ sp<SurfaceBuffer> s;
+ Mutex::Autolock _l(mLock);
+ s = mClientSurface.promote();
+ if (s == 0) {
+ s = new SurfaceBuffer(clientIndex(),
+ const_cast<LayerBuffer *>(this));
+ mClientSurface = s;
+ }
+ return s;
+}
+
+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);
+ return LayerBase::doTransaction(flags);
+}
+
+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);
+ }
+}
+
+bool LayerBuffer::transformed() const
+{
+ sp<Source> source(getSource());
+ if (LIKELY(source != 0))
+ return source->transformed();
+ return false;
+}
+
+/**
+ * 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)
+{
+ sp<OverlayRef> result;
+ Mutex::Autolock _l(mLock);
+ if (mSource != 0)
+ return result;
+
+ sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f);
+ 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::SurfaceBuffer
+// ============================================================================
+
+LayerBuffer::SurfaceBuffer::SurfaceBuffer(SurfaceID id, LayerBuffer* owner)
+: LayerBaseClient::Surface(id, owner->getIdentity()), mOwner(owner)
+{
+}
+
+LayerBuffer::SurfaceBuffer::~SurfaceBuffer()
+{
+ unregisterBuffers();
+ mOwner = 0;
+}
+
+status_t LayerBuffer::SurfaceBuffer::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case REGISTER_BUFFERS:
+ case UNREGISTER_BUFFERS:
+ case CREATE_OVERLAY:
+ {
+ // codes that require permission check
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int self_pid = getpid();
+ if (LIKELY(pid != self_pid)) {
+ // we're called from a different process, do the real check
+ if (!checkCallingPermission(
+ String16("android.permission.ACCESS_SURFACE_FLINGER")))
+ {
+ const int uid = ipc->getCallingUid();
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ }
+ }
+ }
+ return LayerBaseClient::Surface::onTransact(code, data, reply, flags);
+}
+
+status_t LayerBuffer::SurfaceBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
+{
+ LayerBuffer* owner(getOwner());
+ if (owner)
+ return owner->registerBuffers(buffers);
+ return NO_INIT;
+}
+
+void LayerBuffer::SurfaceBuffer::postBuffer(ssize_t offset)
+{
+ LayerBuffer* owner(getOwner());
+ if (owner)
+ owner->postBuffer(offset);
+}
+
+void LayerBuffer::SurfaceBuffer::unregisterBuffers()
+{
+ LayerBuffer* owner(getOwner());
+ if (owner)
+ owner->unregisterBuffers();
+}
+
+sp<OverlayRef> LayerBuffer::SurfaceBuffer::createOverlay(
+ uint32_t w, uint32_t h, int32_t format) {
+ sp<OverlayRef> result;
+ LayerBuffer* owner(getOwner());
+ if (owner)
+ result = owner->createOverlay(w, h, format);
+ return result;
+}
+
+void LayerBuffer::SurfaceBuffer::disown()
+{
+ Mutex::Autolock _l(mLock);
+ mOwner = 0;
+}
+
+// ============================================================================
+// LayerBuffer::Buffer
+// ============================================================================
+
+LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset)
+ : mBufferHeap(buffers)
+{
+ 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.offset = offset;
+ src.img.base = buffers.heap->base();
+ src.img.fd = buffers.heap->heapID();
+}
+
+LayerBuffer::Buffer::~Buffer()
+{
+}
+
+// ============================================================================
+// 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() {
+}
+bool LayerBuffer::Source::transformed() const {
+ return mLayer.mTransformed;
+}
+
+// ---------------------------------------------------------------------------
+
+LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
+ const ISurface::BufferHeap& buffers)
+ : Source(layer), mStatus(NO_ERROR),
+ mBufferSize(0), mTextureName(-1U)
+{
+ 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()
+{
+ if (mTextureName != -1U) {
+ LayerBase::deletedTextures.add(mTextureName);
+ }
+}
+
+void LayerBuffer::BufferSource::postBuffer(ssize_t offset)
+{
+ ISurface::BufferHeap buffers;
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+ 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);
+ if (buffer->getStatus() != NO_ERROR)
+ buffer.clear();
+ setBuffer(buffer);
+ mLayer.invalidate();
+ }
+}
+
+void LayerBuffer::BufferSource::unregisterBuffers()
+{
+ Mutex::Autolock _l(mLock);
+ mBufferHeap.heap.clear();
+ mBuffer.clear();
+ mLayer.invalidate();
+}
+
+sp<LayerBuffer::Buffer> LayerBuffer::BufferSource::getBuffer() const
+{
+ Mutex::Autolock _l(mLock);
+ return mBuffer;
+}
+
+void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer)
+{
+ Mutex::Autolock _l(mLock);
+ mBuffer = buffer;
+}
+
+bool LayerBuffer::BufferSource::transformed() const
+{
+ return mBufferHeap.transform ? true : Source::transformed();
+}
+
+void LayerBuffer::BufferSource::onDraw(const Region& clip) const
+{
+ sp<Buffer> buffer(getBuffer());
+ if (UNLIKELY(buffer == 0)) {
+ // nothing to do, we don't have a buffer
+ mLayer.clearWithOpenGL(clip);
+ return;
+ }
+
+ status_t err = NO_ERROR;
+ NativeBuffer src(buffer->getBuffer());
+ const Rect& transformedBounds = mLayer.getTransformedBounds();
+ const int can_use_copybit = mLayer.canUseCopybit();
+
+ if (can_use_copybit) {
+ const int src_width = src.crop.r - src.crop.l;
+ const int src_height = src.crop.b - src.crop.t;
+ int W = transformedBounds.width();
+ int H = transformedBounds.height();
+ if (mLayer.getOrientation() & Transform::ROT_90) {
+ int t(W); W=H; H=t;
+ }
+
+ /* With LayerBuffer, it is likely that we'll have to rescale the
+ * surface, because this is often used for video playback or
+ * camera-preview. Since we want these operation as fast as possible
+ * we make sure we can use the 2D H/W even if it doesn't support
+ * the requested scale factor, in which case we perform the scaling
+ * in several passes. */
+
+ copybit_device_t* copybit = mLayer.mFlinger->getBlitEngine();
+ const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
+ const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
+
+ float xscale = 1.0f;
+ if (src_width > W*min) xscale = 1.0f / min;
+ else if (src_width*mag < W) xscale = mag;
+
+ float yscale = 1.0f;
+ if (src_height > H*min) yscale = 1.0f / min;
+ else if (src_height*mag < H) yscale = mag;
+
+ if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) {
+ if (UNLIKELY(mTemporaryDealer == 0)) {
+ // allocate a memory-dealer for this the first time
+ mTemporaryDealer = mLayer.mFlinger->getSurfaceHeapManager()
+ ->createHeap(ISurfaceComposer::eHardware);
+ mTempBitmap.init(mTemporaryDealer);
+ }
+
+ const int tmp_w = floorf(src_width * xscale);
+ const int tmp_h = floorf(src_height * yscale);
+ err = mTempBitmap.setBits(tmp_w, tmp_h, 1, src.img.format);
+
+ if (LIKELY(err == NO_ERROR)) {
+ NativeBuffer tmp;
+ mTempBitmap.getBitmapSurface(&tmp.img);
+ tmp.crop.l = 0;
+ tmp.crop.t = 0;
+ tmp.crop.r = tmp.img.w;
+ tmp.crop.b = tmp.img.h;
+
+ region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b)));
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+ err = copybit->stretch(copybit,
+ &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it);
+ src = tmp;
+ }
+ }
+
+ const DisplayHardware& hw(mLayer.graphicPlane(0).displayHardware());
+ copybit_image_t dst;
+ hw.getDisplaySurface(&dst);
+ const copybit_rect_t& drect
+ = reinterpret_cast<const copybit_rect_t&>(transformedBounds);
+ const State& s(mLayer.drawingState());
+ region_iterator it(clip);
+
+ // pick the right orientation for this buffer
+ int orientation = mLayer.getOrientation();
+ if (UNLIKELY(mBufferHeap.transform)) {
+ Transform rot90;
+ GraphicPlane::orientationToTransfrom(
+ ISurfaceComposer::eOrientation90, 0, 0, &rot90);
+ const Transform& planeTransform(mLayer.graphicPlane(0).transform());
+ const Layer::State& s(mLayer.drawingState());
+ Transform tr(planeTransform * s.transform * rot90);
+ orientation = tr.getOrientation();
+ }
+
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+
+ err = copybit->stretch(copybit,
+ &dst, &src.img, &drect, &src.crop, &it);
+ if (err != NO_ERROR) {
+ LOGE("copybit failed (%s)", strerror(err));
+ }
+ }
+
+ if (!can_use_copybit || err) {
+ if (UNLIKELY(mTextureName == -1LU)) {
+ mTextureName = mLayer.createTexture();
+ }
+ GLuint w = 0;
+ GLuint h = 0;
+ 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*)(intptr_t(src.img.base) + src.img.offset);
+ const Region dirty(Rect(t.width, t.height));
+ mLayer.loadTexture(dirty, mTextureName, t, w, h);
+ mLayer.drawWithOpenGL(clip, mTextureName, t, mBufferHeap.transform);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+
+LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer,
+ sp<OverlayRef>* overlayRef,
+ uint32_t w, uint32_t h, int32_t format)
+ : Source(layer), mVisibilityChanged(false),
+ mOverlay(0), mOverlayHandle(0), mOverlayDevice(0)
+{
+ overlay_control_device_t* overlay_dev = mLayer.mFlinger->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;
+
+ mOverlayHandle = overlay->getHandleRef(overlay);
+
+ // NOTE: here it's okay to acquire a reference to "this"m as long as
+ // the reference is not released before we leave the ctor.
+ sp<OverlayChannel> channel = new OverlayChannel(this);
+
+ *overlayRef = new OverlayRef(mOverlayHandle, channel,
+ mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
+}
+
+LayerBuffer::OverlaySource::~OverlaySource()
+{
+ if (mOverlay && mOverlayDevice) {
+ overlay_control_device_t* overlay_dev = mOverlayDevice;
+ overlay_dev->destroyOverlay(overlay_dev, mOverlay);
+ }
+}
+
+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) {
+ mVisibilityChanged = false;
+ 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(mLock);
+ if (mOverlay) {
+ overlay_control_device_t* overlay_dev = mOverlayDevice;
+ overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h);
+ overlay_dev->setParameter(overlay_dev, mOverlay,
+ OVERLAY_TRANSFORM, mLayer.getOrientation());
+ }
+ }
+ }
+}
+
+void LayerBuffer::OverlaySource::serverDestroy()
+{
+ mLayer.clearSource();
+ destroyOverlay();
+}
+
+void LayerBuffer::OverlaySource::destroyOverlay()
+{
+ // we need a lock here to protect "onVisibilityResolved"
+ Mutex::Autolock _l(mLock);
+ if (mOverlay) {
+ overlay_control_device_t* overlay_dev = mOverlayDevice;
+ overlay_dev->destroyOverlay(overlay_dev, mOverlay);
+ mOverlay = 0;
+ }
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
new file mode 100644
index 0000000..2dc77f1
--- /dev/null
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -0,0 +1,216 @@
+/*
+ * 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 <utils/IMemory.h>
+#include <private/ui/LayerState.h>
+#include <EGL/eglnatives.h>
+
+#include "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MemoryDealer;
+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 bool transformed() const;
+ protected:
+ LayerBuffer& mLayer;
+ };
+
+
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
+ Client* client, int32_t i);
+ virtual ~LayerBuffer();
+
+ virtual bool needsBlending() const;
+
+ virtual sp<LayerBaseClient::Surface> getSurface() const;
+ virtual void onDraw(const Region& clip) const;
+ virtual uint32_t doTransaction(uint32_t flags);
+ virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+ virtual bool transformed() const;
+
+ 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);
+
+ sp<Source> getSource() const;
+ sp<Source> clearSource();
+ void setNeedsBlending(bool blending);
+ const Rect& getTransformedBounds() const {
+ return mTransformedBounds;
+ }
+
+private:
+ struct NativeBuffer {
+ copybit_image_t img;
+ copybit_rect_t crop;
+ };
+
+ class Buffer : public LightRefBase<Buffer> {
+ public:
+ Buffer(const ISurface::BufferHeap& buffers, ssize_t offset);
+ 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;
+ };
+
+ 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 bool transformed() const;
+ private:
+ mutable Mutex mLock;
+ sp<Buffer> mBuffer;
+ status_t mStatus;
+ ISurface::BufferHeap mBufferHeap;
+ size_t mBufferSize;
+ mutable sp<MemoryDealer> mTemporaryDealer;
+ mutable LayerBitmap mTempBitmap;
+ mutable GLuint mTextureName;
+ };
+
+ class OverlaySource : public Source {
+ public:
+ OverlaySource(LayerBuffer& layer,
+ sp<OverlayRef>* overlayRef,
+ uint32_t w, uint32_t h, int32_t format);
+ virtual ~OverlaySource();
+ virtual void onTransaction(uint32_t flags);
+ virtual void onVisibilityResolved(const Transform& planeTransform);
+ private:
+ void serverDestroy();
+ void destroyOverlay();
+ class OverlayChannel : public BnOverlay {
+ mutable Mutex mLock;
+ sp<OverlaySource> mSource;
+ virtual void destroy() {
+ sp<OverlaySource> source;
+ { // scope for the lock;
+ Mutex::Autolock _l(mLock);
+ source = mSource;
+ mSource.clear();
+ }
+ if (source != 0) {
+ source->serverDestroy();
+ }
+ }
+ public:
+ OverlayChannel(const sp<OverlaySource>& source)
+ : mSource(source) {
+ }
+ };
+ 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;
+ mutable Mutex mLock;
+ };
+
+
+ class SurfaceBuffer : public LayerBaseClient::Surface
+ {
+ public:
+ SurfaceBuffer(SurfaceID id, LayerBuffer* owner);
+ virtual ~SurfaceBuffer();
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+ 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);
+ void disown();
+ private:
+ LayerBuffer* getOwner() const {
+ Mutex::Autolock _l(mLock);
+ return mOwner;
+ }
+ mutable Mutex mLock;
+ LayerBuffer* mOwner;
+ };
+
+ friend class SurfaceFlinger;
+ sp<SurfaceBuffer> getClientSurface() const;
+
+ mutable Mutex mLock;
+ sp<Source> mSource;
+
+ bool mInvalidate;
+ bool mNeedsBlending;
+ mutable wp<SurfaceBuffer> mClientSurface;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BUFFER_H
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
new file mode 100644
index 0000000..0c347cc
--- /dev/null
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "LayerDim.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerDim::typeInfo = LayerBaseClient::typeInfo | 0x10;
+const char* const LayerDim::typeID = "LayerDim";
+sp<MemoryDealer> LayerDim::mDimmerDealer;
+LayerBitmap LayerDim::mDimmerBitmap;
+
+// ---------------------------------------------------------------------------
+
+LayerDim::LayerDim(SurfaceFlinger* flinger, DisplayID display,
+ Client* client, int32_t i)
+ : LayerBaseClient(flinger, display, client, i)
+{
+}
+
+void LayerDim::initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h)
+{
+ // must only be called once.
+ mDimmerDealer = flinger->getSurfaceHeapManager()
+ ->createHeap(ISurfaceComposer::eHardware);
+ if (mDimmerDealer != 0) {
+ mDimmerBitmap.init(mDimmerDealer);
+ mDimmerBitmap.setBits(w, h, 1, PIXEL_FORMAT_RGB_565);
+ mDimmerBitmap.clear();
+ }
+}
+
+LayerDim::~LayerDim()
+{
+}
+
+void LayerDim::onDraw(const Region& clip) const
+{
+ const State& s(drawingState());
+
+ Region::iterator iterator(clip);
+ if (s.alpha>0 && iterator) {
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+
+ status_t err = NO_ERROR;
+ const int can_use_copybit = canUseCopybit();
+ if (can_use_copybit) {
+ // StopWatch watch("copybit");
+ copybit_image_t dst;
+ hw.getDisplaySurface(&dst);
+ const copybit_rect_t& drect
+ = reinterpret_cast<const copybit_rect_t&>(mTransformedBounds);
+
+ copybit_image_t src;
+ mDimmerBitmap.getBitmapSurface(&src);
+ const copybit_rect_t& srect(drect);
+
+ copybit_device_t* copybit = mFlinger->getBlitEngine();
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+ region_iterator it(clip);
+ err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ }
+
+ if (!can_use_copybit || err) {
+ const GGLfixed alpha = (s.alpha << 16)/255;
+ const uint32_t fbHeight = hw.getHeight();
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_DITHER);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4x(0, 0, 0, alpha);
+ glVertexPointer(2, GL_FIXED, 0, mVertices);
+ Rect r;
+ while (iterator.iterate(&r)) {
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerDim.h b/libs/surfaceflinger/LayerDim.h
new file mode 100644
index 0000000..3e37a47
--- /dev/null
+++ b/libs/surfaceflinger/LayerDim.h
@@ -0,0 +1,57 @@
+/*
+ * 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 "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class LayerDim : public LayerBaseClient
+{
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ LayerDim(SurfaceFlinger* flinger, DisplayID display,
+ Client* client, int32_t i);
+ virtual ~LayerDim();
+
+ virtual void onDraw(const Region& clip) const;
+ virtual bool needsBlending() const { return true; }
+ virtual bool isSecure() const { return false; }
+
+ static void initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h);
+
+private:
+ static sp<MemoryDealer> mDimmerDealer;
+ static LayerBitmap mDimmerBitmap;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_DIM_H
diff --git a/libs/surfaceflinger/LayerOrientationAnim.cpp b/libs/surfaceflinger/LayerOrientationAnim.cpp
new file mode 100644
index 0000000..2b72d7c
--- /dev/null
+++ b/libs/surfaceflinger/LayerOrientationAnim.cpp
@@ -0,0 +1,287 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <core/SkBitmap.h>
+
+#include <ui/EGLDisplaySurface.h>
+
+#include "LayerBase.h"
+#include "LayerOrientationAnim.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "OrientationAnimation.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerOrientationAnim::typeInfo = LayerBase::typeInfo | 0x80;
+const char* const LayerOrientationAnim::typeID = "LayerOrientationAnim";
+
+// ---------------------------------------------------------------------------
+
+LayerOrientationAnim::LayerOrientationAnim(
+ SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const LayerBitmap& bitmap,
+ const LayerBitmap& bitmapIn)
+ : LayerBase(flinger, display), mAnim(anim),
+ mBitmap(bitmap), mBitmapIn(bitmapIn),
+ mTextureName(-1), mTextureNameIn(-1)
+{
+ mStartTime = systemTime();
+ mFinishTime = 0;
+ mOrientationCompleted = false;
+ mFirstRedraw = false;
+ mLastNormalizedTime = 0;
+ mLastScale = 0;
+ mNeedsBlending = false;
+}
+
+LayerOrientationAnim::~LayerOrientationAnim()
+{
+ if (mTextureName != -1U) {
+ LayerBase::deletedTextures.add(mTextureName);
+ }
+ if (mTextureNameIn != -1U) {
+ LayerBase::deletedTextures.add(mTextureNameIn);
+ }
+}
+
+bool LayerOrientationAnim::needsBlending() const
+{
+ return mNeedsBlending;
+}
+
+Point LayerOrientationAnim::getPhysicalSize() const
+{
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ return Point(hw.getWidth(), hw.getHeight());
+}
+
+void LayerOrientationAnim::validateVisibility(const Transform&)
+{
+ const Layer::State& s(drawingState());
+ const Transform tr(s.transform);
+ const Point size(getPhysicalSize());
+ uint32_t w = size.x;
+ uint32_t h = size.y;
+ mTransformedBounds = tr.makeBounds(w, h);
+ mLeft = tr.tx();
+ mTop = tr.ty();
+ transparentRegionScreen.clear();
+ mTransformed = true;
+ mCanUseCopyBit = false;
+ copybit_device_t* copybit = mFlinger->getBlitEngine();
+ if (copybit) {
+ mCanUseCopyBit = true;
+ }
+}
+
+void LayerOrientationAnim::onOrientationCompleted()
+{
+ mFinishTime = systemTime();
+ mOrientationCompleted = true;
+ mFirstRedraw = true;
+ mNeedsBlending = true;
+ mFlinger->invalidateLayerVisibility(this);
+}
+
+void LayerOrientationAnim::onDraw(const Region& clip) const
+{
+ // Animation...
+ const float MIN_SCALE = 0.5f;
+ const float DURATION = ms2ns(200);
+ const float BOUNCES_PER_SECOND = 1.618f;
+ const float BOUNCES_AMPLITUDE = 1.0f/32.0f;
+
+ const nsecs_t now = systemTime();
+ float scale, alpha;
+
+ if (mOrientationCompleted) {
+ if (mFirstRedraw) {
+ mFirstRedraw = false;
+
+ // make a copy of what's on screen
+ copybit_image_t image;
+ mBitmapIn.getBitmapSurface(&image);
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ hw.copyBackToImage(image);
+
+ // and erase the screen for this round
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // FIXME: code below is gross
+ mNeedsBlending = false;
+ LayerOrientationAnim* self(const_cast<LayerOrientationAnim*>(this));
+ mFlinger->invalidateLayerVisibility(self);
+ }
+
+ // make sure pick-up where we left off
+ const float duration = DURATION * mLastNormalizedTime;
+ const float normalizedTime = (float(now - mFinishTime) / duration);
+ if (normalizedTime <= 1.0f) {
+ const float squaredTime = normalizedTime*normalizedTime;
+ scale = (1.0f - mLastScale)*squaredTime + mLastScale;
+ alpha = (1.0f - normalizedTime);
+ alpha *= alpha;
+ alpha *= alpha;
+ } else {
+ mAnim->onAnimationFinished();
+ scale = 1.0f;
+ alpha = 0.0f;
+ }
+ } else {
+ const float normalizedTime = float(now - mStartTime) / DURATION;
+ if (normalizedTime <= 1.0f) {
+ mLastNormalizedTime = normalizedTime;
+ const float squaredTime = normalizedTime*normalizedTime;
+ scale = (MIN_SCALE-1.0f)*squaredTime + 1.0f;
+ alpha = 1.0f;
+ } else {
+ mLastNormalizedTime = 1.0f;
+ const float to_seconds = DURATION / seconds(1);
+ const float phi = BOUNCES_PER_SECOND *
+ (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
+ scale = MIN_SCALE + BOUNCES_AMPLITUDE * (1.0f - cosf(phi));
+ alpha = 1.0f;
+ }
+ mLastScale = scale;
+ }
+ drawScaled(scale, alpha);
+}
+
+void LayerOrientationAnim::drawScaled(float f, float alpha) const
+{
+ copybit_image_t dst;
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ hw.getDisplaySurface(&dst);
+
+ // clear screen
+ // TODO: with update on demand, we may be able
+ // to not erase the screen at all during the animation
+ if (!mOrientationCompleted) {
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ const int w = dst.w*f;
+ const int h = dst.h*f;
+ const int xc = uint32_t(dst.w-w)/2;
+ const int yc = uint32_t(dst.h-h)/2;
+ const copybit_rect_t drect = { xc, yc, xc+w, yc+h };
+
+ copybit_image_t src;
+ mBitmap.getBitmapSurface(&src);
+ const copybit_rect_t srect = { 0, 0, src.w, src.h };
+
+ int err = NO_ERROR;
+ const int can_use_copybit = canUseCopybit();
+ if (can_use_copybit) {
+ copybit_device_t* copybit = mFlinger->getBlitEngine();
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+
+ if (alpha < 1.0f) {
+ copybit_image_t srcIn;
+ mBitmapIn.getBitmapSurface(&srcIn);
+ region_iterator it(Region(Rect( drect.l, drect.t, drect.r, drect.b )));
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+ err = copybit->stretch(copybit, &dst, &srcIn, &drect, &srect, &it);
+ }
+
+ if (!err && alpha > 0.0f) {
+ region_iterator it(Region(Rect( drect.l, drect.t, drect.r, drect.b )));
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, int(alpha*255));
+ err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ }
+ LOGE_IF(err != NO_ERROR, "copybit failed (%s)", strerror(err));
+ }
+ if (!can_use_copybit || err) {
+ GGLSurface t;
+ t.version = sizeof(GGLSurface);
+ t.width = src.w;
+ t.height = src.h;
+ t.stride = src.w;
+ t.vstride= src.h;
+ t.format = src.format;
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+
+ Transform tr;
+ tr.set(f,0,0,f);
+ tr.set(xc, yc);
+
+ // FIXME: we should not access mVertices and mDrawingState like that,
+ // but since we control the animation, we know it's going to work okay.
+ // eventually we'd need a more formal way of doing things like this.
+ LayerOrientationAnim& self(const_cast<LayerOrientationAnim&>(*this));
+ tr.transform(self.mVertices[0], 0, 0);
+ tr.transform(self.mVertices[1], 0, src.h);
+ tr.transform(self.mVertices[2], src.w, src.h);
+ tr.transform(self.mVertices[3], src.w, 0);
+ if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+ // Too slow to do this in software
+ self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
+ }
+
+ if (alpha < 1.0f) {
+ copybit_image_t src;
+ mBitmapIn.getBitmapSurface(&src);
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+ if (UNLIKELY(mTextureNameIn == -1LU)) {
+ mTextureNameIn = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureNameIn, t, w, h);
+ }
+ self.mDrawingState.alpha = 255;
+ const Region clip(Rect( drect.l, drect.t, drect.r, drect.b ));
+ drawWithOpenGL(clip, mTextureName, t);
+ }
+
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+ if (UNLIKELY(mTextureName == -1LU)) {
+ mTextureName = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureName, t, w, h);
+ }
+ self.mDrawingState.alpha = int(alpha*255);
+ const Region clip(Rect( drect.l, drect.t, drect.r, drect.b ));
+ drawWithOpenGL(clip, mTextureName, t);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerOrientationAnim.h b/libs/surfaceflinger/LayerOrientationAnim.h
new file mode 100644
index 0000000..7367685
--- /dev/null
+++ b/libs/surfaceflinger/LayerOrientationAnim.h
@@ -0,0 +1,75 @@
+/*
+ * 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_ORIENTATION_ANIM_H
+#define ANDROID_LAYER_ORIENTATION_ANIM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+#include <utils/Parcel.h>
+
+#include "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+class OrientationAnimation;
+
+class LayerOrientationAnim : public LayerBase
+{
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ LayerOrientationAnim(SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const LayerBitmap& zoomOut,
+ const LayerBitmap& zoomIn);
+ virtual ~LayerOrientationAnim();
+
+ void onOrientationCompleted();
+
+ virtual void onDraw(const Region& clip) const;
+ virtual Point getPhysicalSize() const;
+ virtual void validateVisibility(const Transform& globalTransform);
+ virtual bool needsBlending() const;
+ virtual bool isSecure() const { return false; }
+private:
+ void drawScaled(float scale, float alpha) const;
+
+ OrientationAnimation* mAnim;
+ LayerBitmap mBitmap;
+ LayerBitmap mBitmapIn;
+ nsecs_t mStartTime;
+ nsecs_t mFinishTime;
+ bool mOrientationCompleted;
+ mutable bool mFirstRedraw;
+ mutable float mLastNormalizedTime;
+ mutable float mLastScale;
+ mutable GLuint mTextureName;
+ mutable GLuint mTextureNameIn;
+ mutable bool mNeedsBlending;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_ORIENTATION_ANIM_H
diff --git a/libs/surfaceflinger/MODULE_LICENSE_APACHE2 b/libs/surfaceflinger/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/surfaceflinger/MODULE_LICENSE_APACHE2
diff --git a/libs/surfaceflinger/OrientationAnimation.cpp b/libs/surfaceflinger/OrientationAnimation.cpp
new file mode 100644
index 0000000..f6f1326
--- /dev/null
+++ b/libs/surfaceflinger/OrientationAnimation.cpp
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include "LayerOrientationAnim.h"
+#include "OrientationAnimation.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+OrientationAnimation::OrientationAnimation(const sp<SurfaceFlinger>& flinger)
+ : mFlinger(flinger), mLayerOrientationAnim(NULL), mState(DONE)
+{
+ // allocate a memory-dealer for this the first time
+ mTemporaryDealer = mFlinger->getSurfaceHeapManager()->createHeap(
+ ISurfaceComposer::eHardware);
+}
+
+OrientationAnimation::~OrientationAnimation()
+{
+}
+
+void OrientationAnimation::onOrientationChanged()
+{
+ if (mState == DONE)
+ mState = PREPARE;
+}
+
+void OrientationAnimation::onAnimationFinished()
+{
+ if (mState != DONE)
+ mState = FINISH;
+}
+
+bool OrientationAnimation::run_impl()
+{
+ bool skip_frame;
+ switch (mState) {
+ default:
+ case DONE:
+ skip_frame = done();
+ break;
+ case PREPARE:
+ skip_frame = prepare();
+ break;
+ case PHASE1:
+ skip_frame = phase1();
+ break;
+ case PHASE2:
+ skip_frame = phase2();
+ break;
+ case FINISH:
+ skip_frame = finished();
+ break;
+ }
+ return skip_frame;
+}
+
+bool OrientationAnimation::done()
+{
+ if (mFlinger->isFrozen()) {
+ // we are not allowed to draw, but pause a bit to make sure
+ // apps don't end up using the whole CPU, if they depend on
+ // surfaceflinger for synchronization.
+ usleep(8333); // 8.3ms ~ 120fps
+ return true;
+ }
+ return false;
+}
+
+bool OrientationAnimation::prepare()
+{
+ mState = PHASE1;
+
+ const GraphicPlane& plane(mFlinger->graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ const uint32_t w = hw.getWidth();
+ const uint32_t h = hw.getHeight();
+
+ LayerBitmap bitmap;
+ bitmap.init(mTemporaryDealer);
+ bitmap.setBits(w, h, 1, hw.getFormat());
+
+ LayerBitmap bitmapIn;
+ bitmapIn.init(mTemporaryDealer);
+ bitmapIn.setBits(w, h, 1, hw.getFormat());
+
+ copybit_image_t front;
+ bitmap.getBitmapSurface(&front);
+ hw.copyFrontToImage(front);
+
+ LayerOrientationAnim* l = new LayerOrientationAnim(
+ mFlinger.get(), 0, this, bitmap, bitmapIn);
+ l->initStates(w, h, 0);
+ l->setLayer(INT_MAX-1);
+ mFlinger->addLayer(l);
+ mLayerOrientationAnim = l;
+ return true;
+}
+
+bool OrientationAnimation::phase1()
+{
+ if (mFlinger->isFrozen() == false) {
+ // start phase 2
+ mState = PHASE2;
+ mLayerOrientationAnim->onOrientationCompleted();
+ mLayerOrientationAnim->invalidate();
+ return true;
+
+ }
+ mLayerOrientationAnim->invalidate();
+ return false;
+}
+
+bool OrientationAnimation::phase2()
+{
+ // do the 2nd phase of the animation
+ mLayerOrientationAnim->invalidate();
+ return false;
+}
+
+bool OrientationAnimation::finished()
+{
+ mState = DONE;
+ mFlinger->removeLayer(mLayerOrientationAnim);
+ mLayerOrientationAnim = NULL;
+ return true;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/OrientationAnimation.h b/libs/surfaceflinger/OrientationAnimation.h
new file mode 100644
index 0000000..ba33fce
--- /dev/null
+++ b/libs/surfaceflinger/OrientationAnimation.h
@@ -0,0 +1,73 @@
+/*
+ * 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_ORIENTATION_ANIMATION_H
+#define ANDROID_ORIENTATION_ANIMATION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class SurfaceFlinger;
+class MemoryDealer;
+class LayerOrientationAnim;
+
+class OrientationAnimation
+{
+public:
+ OrientationAnimation(const sp<SurfaceFlinger>& flinger);
+ virtual ~OrientationAnimation();
+
+ void onOrientationChanged();
+ void onAnimationFinished();
+ inline bool run() {
+ if (LIKELY(mState == DONE))
+ return false;
+ return run_impl();
+ }
+
+private:
+ enum {
+ DONE = 0,
+ PREPARE,
+ PHASE1,
+ PHASE2,
+ FINISH
+ };
+
+ bool run_impl();
+ bool done();
+ bool prepare();
+ bool phase1();
+ bool phase2();
+ bool finished();
+
+ sp<SurfaceFlinger> mFlinger;
+ sp<MemoryDealer> mTemporaryDealer;
+ LayerOrientationAnim* mLayerOrientationAnim;
+ int mState;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ORIENTATION_ANIMATION_H
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
new file mode 100644
index 0000000..900282a
--- /dev/null
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -0,0 +1,1840 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+#include <utils/MemoryDealer.h>
+#include <utils/MemoryBase.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/StopWatch.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/DisplayInfo.h>
+#include <ui/EGLDisplaySurface.h>
+
+#include <pixelflinger/pixelflinger.h>
+#include <GLES/gl.h>
+
+#include "clz.h"
+#include "CPUGauge.h"
+#include "Layer.h"
+#include "LayerBlur.h"
+#include "LayerBuffer.h"
+#include "LayerDim.h"
+#include "LayerBitmap.h"
+#include "LayerOrientationAnim.h"
+#include "OrientationAnimation.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+
+#include "DisplayHardware/DisplayHardware.h"
+#include "GPUHardware/GPUHardware.h"
+
+
+#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(
+ 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);
+ LOG_ASSERT(layers[idx]==key,
+ "LayerVector[%p]: layers[%d]=%p, key=%p",
+ this, int(idx), layers[idx], key);
+ return idx;
+ }
+ return i;
+}
+
+ssize_t SurfaceFlinger::LayerVector::add(
+ LayerBase* layer,
+ Vector<LayerBase*>::compar_t cmp)
+{
+ size_t count = layers.size();
+ ssize_t l = 0;
+ ssize_t h = count-1;
+ ssize_t mid;
+ 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(LayerBase* layer)
+{
+ const ssize_t keyIndex = lookup.indexOfKey(layer);
+ if (keyIndex >= 0) {
+ const size_t index = lookup.valueAt(keyIndex);
+ LOG_ASSERT(layers[index]==layer,
+ "LayerVector[%p]: layers[%u]=%p, layer=%p",
+ this, int(index), layers[index], layer);
+ 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(
+ LayerBase* layer,
+ Vector<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),
+ mBootTime(systemTime()),
+ mLastScheduledBroadcast(NULL),
+ mVisibleRegionsDirty(false),
+ mDeferReleaseConsole(false),
+ mFreezeDisplay(false),
+ mFreezeCount(0),
+ mDebugRegion(0),
+ mDebugCpu(0),
+ mDebugFps(0),
+ mDebugBackground(0),
+ mDebugNoBootAnimation(0),
+ mSyncObject(),
+ mDeplayedTransactionPending(0),
+ 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.showcpu", value, "0");
+ mDebugCpu = atoi(value);
+ property_get("debug.sf.showbackground", value, "0");
+ mDebugBackground = atoi(value);
+ property_get("debug.sf.showfps", value, "0");
+ mDebugFps = atoi(value);
+ property_get("debug.sf.nobootanimation", value, "0");
+ mDebugNoBootAnimation = atoi(value);
+
+ LOGI_IF(mDebugRegion, "showupdates enabled");
+ LOGI_IF(mDebugCpu, "showcpu enabled");
+ LOGI_IF(mDebugBackground, "showbackground enabled");
+ LOGI_IF(mDebugFps, "showfps enabled");
+ LOGI_IF(mDebugNoBootAnimation, "boot animation disabled");
+}
+
+SurfaceFlinger::~SurfaceFlinger()
+{
+ glDeleteTextures(1, &mWormholeTexName);
+ delete mOrientationAnimation;
+}
+
+copybit_device_t* SurfaceFlinger::getBlitEngine() const
+{
+ return graphicPlane(0).displayHardware().getBlitEngine();
+}
+
+overlay_control_device_t* SurfaceFlinger::getOverlayEngine() const
+{
+ return graphicPlane(0).displayHardware().getOverlayEngine();
+}
+
+sp<IMemory> SurfaceFlinger::getCblk() const
+{
+ return mServerCblkMemory;
+}
+
+status_t SurfaceFlinger::requestGPU(const sp<IGPUCallback>& callback,
+ gpu_info_t* gpu)
+{
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ status_t err = mGPU->request(pid, callback, gpu);
+ return err;
+}
+
+status_t SurfaceFlinger::revokeGPU()
+{
+ return mGPU->friendlyRevoke();
+}
+
+sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection()
+{
+ Mutex::Autolock _l(mStateLock);
+ uint32_t token = mTokens.acquire();
+
+ Client* client = new Client(token, this);
+ if ((client == 0) || (client->ctrlblk == 0)) {
+ mTokens.release(token);
+ return 0;
+ }
+ status_t err = mClientsMap.add(token, client);
+ if (err < 0) {
+ delete client;
+ mTokens.release(token);
+ return 0;
+ }
+ sp<BClient> bclient =
+ new BClient(this, token, client->controlBlockMemory());
+ return bclient;
+}
+
+void SurfaceFlinger::destroyConnection(ClientID cid)
+{
+ Mutex::Autolock _l(mStateLock);
+ Client* const client = mClientsMap.valueFor(cid);
+ if (client) {
+ // free all the layers this client owns
+ const Vector<LayerBaseClient*>& layers = client->getLayers();
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ LayerBaseClient* const layer = layers[i];
+ removeLayer_l(layer);
+ }
+
+ // the resources associated with this client will be freed
+ // during the next transaction, after these surfaces have been
+ // properly removed from the screen
+
+ // remove this client from our ClientID->Client mapping.
+ mClientsMap.removeItem(cid);
+
+ // and add it to the list of disconnected clients
+ mDisconnectedClients.add(client);
+
+ // request a transaction
+ setTransactionFlags(eTransactionNeeded);
+ }
+}
+
+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)) );
+ if (mBootAnimation != 0) {
+ mBootAnimation->requestExit();
+ mBootAnimation.clear();
+ }
+}
+
+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;
+}
+
+// this is defined in libGLES_CM.so
+extern ISurfaceComposer* GLES_localSurfaceManager;
+
+status_t SurfaceFlinger::readyToRun()
+{
+ LOGI( "SurfaceFlinger's main thread ready to run. "
+ "Initializing graphics H/W...");
+
+ // create the shared control-block
+ mServerHeap = new MemoryDealer(4096, MemoryDealer::READ_ONLY);
+ LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
+
+ mServerCblkMemory = mServerHeap->allocate(4096);
+ LOGE_IF(mServerCblkMemory==0, "can't create shared control block");
+
+ mServerCblk = static_cast<surface_flinger_cblk_t *>(mServerCblkMemory->pointer());
+ LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
+ new(mServerCblk) surface_flinger_cblk_t;
+
+ // get a reference to the GPU if we have one
+ mGPU = GPUFactory::getGPU();
+
+ // create the surface Heap manager, which manages the heaps
+ // (be it in RAM or VRAM) where surfaces are allocated
+ // We give 8 MB per client.
+ mSurfaceHeapManager = new SurfaceHeapManager(this, 8 << 20);
+
+
+ GLES_localSurfaceManager = static_cast<ISurfaceComposer*>(this);
+
+ // 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);
+ }
+
+ // 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 = w;
+ dcblk->h = h;
+ dcblk->format = f;
+ dcblk->orientation = ISurfaceComposer::eOrientationDefault;
+ dcblk->xdpi = hw.getDpiX();
+ dcblk->ydpi = hw.getDpiY();
+ dcblk->fps = hw.getRefreshRate();
+ dcblk->density = hw.getDensity();
+ asm volatile ("":::"memory");
+
+ // Initialize OpenGL|ES
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ 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...
+ */
+
+ mOrientationAnimation = new OrientationAnimation(this);
+
+ // start CPU gauge display
+ if (mDebugCpu)
+ mCpuGauge = new CPUGauge(this, ms2ns(500));
+
+ // the boot animation!
+ if (mDebugNoBootAnimation == false)
+ mBootAnimation = new BootAnimation(this);
+
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Events Handler
+#endif
+
+void SurfaceFlinger::waitForEvent()
+{
+ // wait for something to do
+ if (UNLIKELY(isFrozen())) {
+ // wait 5 seconds
+ int err = mSyncObject.wait(ms2ns(5000));
+ if (err != NO_ERROR) {
+ if (isFrozen()) {
+ // we timed out and are still frozen
+ LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d",
+ mFreezeDisplay, mFreezeCount);
+ mFreezeCount = 0;
+ }
+ }
+ } else {
+ mSyncObject.wait();
+ }
+}
+
+void SurfaceFlinger::signalEvent() {
+ mSyncObject.open();
+}
+
+void SurfaceFlinger::signal() const {
+ mSyncObject.open();
+}
+
+void SurfaceFlinger::signalDelayedEvent(nsecs_t delay)
+{
+ if (android_atomic_or(1, &mDeplayedTransactionPending) == 0) {
+ sp<DelayedTransaction> delayedEvent(new DelayedTransaction(this, delay));
+ delayedEvent->run("DelayedeEvent", PRIORITY_URGENT_DISPLAY);
+ }
+}
+
+// ----------------------------------------------------------------------------
+#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())) {
+ // repaint the framebuffer (if needed)
+ handleRepaint();
+
+ // release the clients before we flip ('cause flip might block)
+ unlockClients();
+ executeScheduledBroadcasts();
+
+ // sample the cpu gauge
+ if (UNLIKELY(mDebugCpu)) {
+ handleDebugCpu();
+ }
+
+ postFramebuffer();
+ } else {
+ // pretend we did the post
+ unlockClients();
+ executeScheduledBroadcasts();
+ usleep(16667); // 60 fps period
+ }
+ return true;
+}
+
+void SurfaceFlinger::postFramebuffer()
+{
+ const bool skip = mOrientationAnimation->run();
+ if (UNLIKELY(skip)) {
+ return;
+ }
+
+ if (!mInvalidRegion.isEmpty()) {
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+
+ if (UNLIKELY(mDebugFps)) {
+ debugShowFPS();
+ }
+
+ hw.flip(mInvalidRegion);
+
+ mInvalidRegion.clear();
+
+ if (Layer::deletedTextures.size()) {
+ glDeleteTextures(
+ Layer::deletedTextures.size(),
+ Layer::deletedTextures.array());
+ Layer::deletedTextures.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 aquire signal
+ mDeferReleaseConsole = false;
+ revokeGPU();
+ hw.releaseScreen();
+ }
+
+ if (what & eConsoleReleased) {
+ if (hw.canDraw()) {
+ revokeGPU();
+ hw.releaseScreen();
+ } else {
+ mDeferReleaseConsole = true;
+ }
+ }
+
+ mDirtyRegion.set(hw.bounds());
+}
+
+void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
+{
+ Mutex::Autolock _l(mStateLock);
+
+ 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++) {
+ LayerBase* const 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;
+
+ if (flags & Layer::eRestartTransaction) {
+ // restart the transaction, but back-off a little
+ layer->setTransactionFlags(eTransactionNeeded);
+ setTransactionFlags(eTraversalNeeded, ms2ns(8));
+ }
+ }
+ }
+
+ /*
+ * 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;
+ 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;
+ if (orientation & eOrientationSwapMask) {
+ // 90 or 270 degrees orientation
+ dcblk->w = hw.getHeight();
+ dcblk->h = hw.getWidth();
+ } else {
+ dcblk->w = hw.getWidth();
+ dcblk->h = hw.getHeight();
+ }
+
+ mVisibleRegionsDirty = true;
+ mDirtyRegion.set(hw.bounds());
+
+ mOrientationAnimation->onOrientationChanged();
+ }
+
+ if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
+ // freezing or unfreezing the display -> trigger animation if needed
+ mFreezeDisplay = mCurrentState.freezeDisplay;
+ const nsecs_t now = systemTime();
+ if (mFreezeDisplay) {
+ mFreezeDisplayTime = now;
+ } else {
+ //LOGD("Screen was frozen for %llu us",
+ // ns2us(now-mFreezeDisplayTime));
+ }
+ }
+
+ // some layers might have been removed, so
+ // we need to update the regions they're exposing.
+ size_t c = mRemovedLayers.size();
+ if (c) {
+ mVisibleRegionsDirty = true;
+ }
+
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
+ // layers have been added
+ mVisibleRegionsDirty = true;
+ }
+
+ // get rid of all resources we don't need anymore
+ // (layers and clients)
+ free_resources_l();
+ }
+
+ 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());
+
+ Region aboveOpaqueLayers;
+ Region aboveCoveredLayers;
+ Region dirty;
+
+ bool secureFrameBuffer = false;
+
+ size_t i = currentLayers.size();
+ while (i--) {
+ LayerBase* const layer = currentLayers[i];
+ layer->validateVisibility(planeTransform);
+
+ // start with the whole surface at its current location
+ const Layer::State& s = layer->drawingState();
+ const Rect bounds(layer->visibleBounds());
+
+ // handle hidden surfaces by setting the visible region to empty
+ Region opaqueRegion;
+ Region visibleRegion;
+ Region coveredRegion;
+ if (UNLIKELY((s.flags & ISurfaceComposer::eLayerHidden) || !s.alpha)) {
+ visibleRegion.clear();
+ } else {
+ const bool translucent = layer->needsBlending();
+ visibleRegion.set(bounds);
+ coveredRegion = visibleRegion;
+
+ // Remove the transparent area from the visible region
+ if (translucent) {
+ visibleRegion.subtractSelf(layer->transparentRegionScreen);
+ }
+
+ // compute the opaque region
+ if (s.alpha==255 && !translucent && layer->getOrientation()>=0) {
+ // the opaque region is the visible region
+ opaqueRegion = visibleRegion;
+ }
+ }
+
+ // subtract the opaque region covered by the layers above us
+ visibleRegion.subtractSelf(aboveOpaqueLayers);
+ coveredRegion.andSelf(aboveCoveredLayers);
+
+ // 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
+ // dirty = what's visible now - what's wasn't covered before
+ // = what's visible now & what's was covered before
+ dirty = visibleRegion.intersect(layer->coveredRegionScreen);
+ }
+ dirty.subtractSelf(aboveOpaqueLayers);
+
+ // accumulate to the screen dirty region
+ dirtyRegion.orSelf(dirty);
+
+ // updade aboveOpaqueLayers/aboveCoveredLayers for next (lower) layer
+ aboveOpaqueLayers.orSelf(opaqueRegion);
+ aboveCoveredLayers.orSelf(bounds);
+
+ // Store the visible region is screen space
+ layer->setVisibleRegion(visibleRegion);
+ layer->setCoveredRegion(coveredRegion);
+
+ // If a secure layer is partially visible, lockdown the screen!
+ if (layer->isSecure() && !visibleRegion.isEmpty()) {
+ secureFrameBuffer = true;
+ }
+ }
+
+ mSecureFrameBuffer = secureFrameBuffer;
+ opaqueRegion = aboveOpaqueLayers;
+}
+
+
+void SurfaceFlinger::commitTransaction()
+{
+ mDrawingState = mCurrentState;
+ mTransactionCV.signal();
+}
+
+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();
+ LayerBase* const* layers = currentLayers.array();
+ for (size_t i=0 ; i<count ; i++) {
+ LayerBase* const 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();
+ LayerBase* const* layers = currentLayers.array();
+ for (size_t i=0 ; i<count ; i++) {
+ LayerBase* const layer = layers[i];
+ layer->unlockPageFlip(planeTransform, mDirtyRegion);
+ }
+}
+
+void SurfaceFlinger::handleRepaint()
+{
+ // set the frame buffer
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ if (UNLIKELY(mDebugRegion)) {
+ debugFlashRegions();
+ }
+
+ // compute the invalid region
+ mInvalidRegion.orSelf(mDirtyRegion);
+
+ uint32_t flags = hw.getFlags();
+ if (flags & DisplayHardware::BUFFER_PRESERVED) {
+ // here we assume DisplayHardware::flip()'s implementation
+ // performs the copy-back optimization.
+ } else {
+ if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
+ // we need to fully redraw the part that will be updated
+ mDirtyRegion.set(mInvalidRegion.bounds());
+ } else {
+ // we need to redraw everything
+ 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();
+ LayerBase const* const* const layers = drawingLayers.array();
+ for (size_t i=0 ; i<count ; ++i) {
+ LayerBase const * const 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();
+ LayerBase* const* const layers = drawingLayers.array();
+ for (size_t i=0 ; i<count ; ++i) {
+ LayerBase* const layer = layers[i];
+ layer->finishPageFlip();
+ }
+}
+
+void SurfaceFlinger::scheduleBroadcast(Client* client)
+{
+ if (mLastScheduledBroadcast != client) {
+ mLastScheduledBroadcast = client;
+ mScheduledBroadcasts.add(client);
+ }
+}
+
+void SurfaceFlinger::executeScheduledBroadcasts()
+{
+ SortedVector<Client*>& list = mScheduledBroadcasts;
+ size_t count = list.size();
+ while (count--) {
+ per_client_cblk_t* const cblk = list[count]->ctrlblk;
+ if (cblk->lock.tryLock() == NO_ERROR) {
+ cblk->cv.broadcast();
+ list.removeAt(count);
+ cblk->lock.unlock();
+ } else {
+ // schedule another round
+ LOGW("executeScheduledBroadcasts() skipped, "
+ "contention on the client. We'll try again later...");
+ signalDelayedEvent(ms2ns(4));
+ }
+ }
+ mLastScheduledBroadcast = 0;
+}
+
+void SurfaceFlinger::handleDebugCpu()
+{
+ Mutex::Autolock _l(mDebugLock);
+ if (mCpuGauge != 0)
+ mCpuGauge->sample();
+}
+
+void SurfaceFlinger::debugFlashRegions()
+{
+ if (UNLIKELY(!mDirtyRegion.isRect())) {
+ // TODO: do this only if we don't have preserving
+ // swapBuffer. If we don't have update-on-demand,
+ // redraw everything.
+ composeSurfaces(Region(mDirtyRegion.bounds()));
+ }
+
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+
+ glColor4x(0x10000, 0, 0x10000, 0x10000);
+
+ Rect r;
+ Region::iterator iterator(mDirtyRegion);
+ while (iterator.iterate(&r)) {
+ 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);
+ }
+
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ hw.flip(mDirtyRegion.merge(mInvalidRegion));
+ mInvalidRegion.clear();
+
+ 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)) {
+ glClearColorx(0,0,0,0);
+ Rect r;
+ Region::iterator iterator(region);
+ while (iterator.iterate(&r)) {
+ 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);
+ 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);
+ Rect r;
+ Region::iterator iterator(region);
+ while (iterator.iterate(&r)) {
+ 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(LayerBase* layer)
+{
+ Mutex::Autolock _l(mStateLock);
+ addLayer_l(layer);
+ setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeLayer(LayerBase* layer)
+{
+ Mutex::Autolock _l(mStateLock);
+ removeLayer_l(layer);
+ setTransactionFlags(eTransactionNeeded);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::invalidateLayerVisibility(LayerBase* layer)
+{
+ layer->forceVisibilityTransaction();
+ setTransactionFlags(eTraversalNeeded);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::addLayer_l(LayerBase* layer)
+{
+ ssize_t i = mCurrentState.layersSortedByZ.add(
+ layer, &LayerBase::compareCurrentStateZ);
+ LayerBaseClient* lbc = LayerBase::dynamicCast<LayerBaseClient*>(layer);
+ if (lbc) {
+ mLayerMap.add(lbc->serverIndex(), lbc);
+ }
+ mRemovedLayers.remove(layer);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeLayer_l(LayerBase* layerBase)
+{
+ ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase);
+ if (index >= 0) {
+ mRemovedLayers.add(layerBase);
+ LayerBaseClient* layer = LayerBase::dynamicCast<LayerBaseClient*>(layerBase);
+ if (layer) {
+ mLayerMap.removeItem(layer->serverIndex());
+ }
+ return NO_ERROR;
+ }
+ // 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 destroySurface,
+ // destroyclient and destroySurface-from-a-transaction.
+ return (index == NAME_NOT_FOUND) ? status_t(NO_ERROR) : index;
+}
+
+void SurfaceFlinger::free_resources_l()
+{
+ // Destroy layers that were removed
+ destroy_all_removed_layers_l();
+
+ // free resources associated with disconnected clients
+ SortedVector<Client*>& scheduledBroadcasts(mScheduledBroadcasts);
+ Vector<Client*>& disconnectedClients(mDisconnectedClients);
+ const size_t count = disconnectedClients.size();
+ for (size_t i=0 ; i<count ; i++) {
+ Client* client = disconnectedClients[i];
+ // if this client is the scheduled broadcast list,
+ // remove it from there (and we don't need to signal it
+ // since it is dead).
+ int32_t index = scheduledBroadcasts.indexOf(client);
+ if (index >= 0) {
+ scheduledBroadcasts.removeItemsAt(index);
+ }
+ mTokens.release(client->cid);
+ delete client;
+ }
+ disconnectedClients.clear();
+}
+
+void SurfaceFlinger::destroy_all_removed_layers_l()
+{
+ size_t c = mRemovedLayers.size();
+ while (c--) {
+ LayerBase* const removed_layer = mRemovedLayers[c];
+
+ LOGE_IF(mCurrentState.layersSortedByZ.indexOf(removed_layer) >= 0,
+ "layer %p removed but still in the current state list",
+ removed_layer);
+
+ delete removed_layer;
+ }
+ mRemovedLayers.clear();
+}
+
+
+uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
+{
+ return android_atomic_and(~flags, &mTransactionFlags) & flags;
+}
+
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, nsecs_t delay)
+{
+ uint32_t old = android_atomic_or(flags, &mTransactionFlags);
+ if ((old & flags)==0) { // wake the server up
+ if (delay > 0) {
+ signalDelayedEvent(delay);
+ } else {
+ signalEvent();
+ }
+ }
+ return old;
+}
+
+void SurfaceFlinger::openGlobalTransaction()
+{
+ android_atomic_inc(&mTransactionCount);
+}
+
+void SurfaceFlinger::closeGlobalTransaction()
+{
+ if (android_atomic_dec(&mTransactionCount) == 1) {
+ signalEvent();
+ }
+}
+
+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 fadding)
+ 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 fadding)
+ return NO_ERROR;
+}
+
+int SurfaceFlinger::setOrientation(DisplayID dpy, int orientation)
+{
+ 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.orientation = orientation;
+ setTransactionFlags(eTransactionNeeded);
+ mTransactionCV.wait(mStateLock);
+ } else {
+ orientation = BAD_VALUE;
+ }
+ }
+ return orientation;
+}
+
+sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,
+ ISurfaceFlingerClient::surface_data_t* params,
+ DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags)
+{
+ LayerBaseClient* layer = 0;
+ sp<LayerBaseClient::Surface> surfaceHandle;
+ Mutex::Autolock _l(mStateLock);
+ Client* const c = mClientsMap.valueFor(clientId);
+ if (UNLIKELY(!c)) {
+ LOGE("createSurface() failed, client not found (id=%d)", clientId);
+ return surfaceHandle;
+ }
+
+ //LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
+ int32_t id = c->generateId(pid);
+ if (uint32_t(id) >= NUM_LAYERS_MAX) {
+ LOGE("createSurface() failed, generateId = %d", id);
+ return surfaceHandle;
+ }
+
+ switch (flags & eFXSurfaceMask) {
+ case eFXSurfaceNormal:
+ if (UNLIKELY(flags & ePushBuffers)) {
+ layer = createPushBuffersSurfaceLocked(c, d, id, w, h, flags);
+ } else {
+ layer = createNormalSurfaceLocked(c, d, id, w, h, format, flags);
+ }
+ break;
+ case eFXSurfaceBlur:
+ layer = createBlurSurfaceLocked(c, d, id, w, h, flags);
+ break;
+ case eFXSurfaceDim:
+ layer = createDimSurfaceLocked(c, d, id, w, h, flags);
+ break;
+ }
+
+ if (layer) {
+ setTransactionFlags(eTransactionNeeded);
+ surfaceHandle = layer->getSurface();
+ if (surfaceHandle != 0)
+ surfaceHandle->getSurfaceData(params);
+ }
+
+ return surfaceHandle;
+}
+
+LayerBaseClient* SurfaceFlinger::createNormalSurfaceLocked(
+ Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
+{
+ // 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:
+ format = PIXEL_FORMAT_RGB_565;
+ break;
+ }
+
+ Layer* layer = new Layer(this, display, client, id);
+ status_t err = layer->setBuffers(client, w, h, format, flags);
+ if (LIKELY(err == NO_ERROR)) {
+ layer->initStates(w, h, flags);
+ addLayer_l(layer);
+ } else {
+ LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err));
+ delete layer;
+ return 0;
+ }
+ return layer;
+}
+
+LayerBaseClient* SurfaceFlinger::createBlurSurfaceLocked(
+ Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags)
+{
+ LayerBlur* layer = new LayerBlur(this, display, client, id);
+ layer->initStates(w, h, flags);
+ addLayer_l(layer);
+ return layer;
+}
+
+LayerBaseClient* SurfaceFlinger::createDimSurfaceLocked(
+ Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags)
+{
+ LayerDim* layer = new LayerDim(this, display, client, id);
+ layer->initStates(w, h, flags);
+ addLayer_l(layer);
+ return layer;
+}
+
+LayerBaseClient* SurfaceFlinger::createPushBuffersSurfaceLocked(
+ Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags)
+{
+ LayerBuffer* layer = new LayerBuffer(this, display, client, id);
+ layer->initStates(w, h, flags);
+ addLayer_l(layer);
+ return layer;
+}
+
+status_t SurfaceFlinger::destroySurface(SurfaceID index)
+{
+ Mutex::Autolock _l(mStateLock);
+ LayerBaseClient* const layer = getLayerUser_l(index);
+ status_t err = removeLayer_l(layer);
+ if (err < 0)
+ return err;
+ setTransactionFlags(eTransactionNeeded);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::setClientState(
+ ClientID cid,
+ int32_t count,
+ const layer_state_t* states)
+{
+ Mutex::Autolock _l(mStateLock);
+ uint32_t flags = 0;
+ cid <<= 16;
+ for (int i=0 ; i<count ; i++) {
+ const layer_state_t& s = states[i];
+ LayerBaseClient* layer = getLayerUser_l(s.surface | cid);
+ if (layer) {
+ const uint32_t what = s.what;
+ // check if it has been destroyed first
+ if (what & eDestroyed) {
+ if (removeLayer_l(layer) == NO_ERROR) {
+ flags |= eTransactionNeeded;
+ // we skip everything else... well, no, not really
+ // we skip ONLY that transaction.
+ continue;
+ }
+ }
+ 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;
+ }
+ 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;
+}
+
+LayerBaseClient* SurfaceFlinger::getLayerUser_l(SurfaceID s) const
+{
+ return mLayerMap.valueFor(s);
+}
+
+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 (checkCallingPermission(
+ String16("android.permission.DUMP")) == false)
+ { // not allowed
+ 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 {
+ Mutex::Autolock _l(mStateLock);
+ size_t s = mClientsMap.size();
+ char name[64];
+ for (size_t i=0 ; i<s ; i++) {
+ Client* client = mClientsMap.valueAt(i);
+ sprintf(name, " Client (id=0x%08x)", client->cid);
+ client->dump(name);
+ }
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ const size_t count = currentLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ /*** LayerBase ***/
+ LayerBase const * const layer = currentLayers[i];
+ const Layer::State& s = layer->drawingState();
+ snprintf(buffer, SIZE,
+ "+ %s %p\n"
+ " "
+ "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
+ "needsBlending=%1d, invalidate=%1d, "
+ "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
+ layer->getTypeID(), layer,
+ s.z, layer->tx(), layer->ty(), s.w, s.h,
+ layer->needsBlending(), layer->contentDirty,
+ s.alpha, s.flags,
+ s.transform[0], s.transform[1],
+ s.transform[2], s.transform[3]);
+ result.append(buffer);
+ buffer[0] = 0;
+ /*** LayerBaseClient ***/
+ LayerBaseClient* const lbc =
+ LayerBase::dynamicCast<LayerBaseClient*>((LayerBase*)layer);
+ if (lbc) {
+ snprintf(buffer, SIZE,
+ " "
+ "id=0x%08x, client=0x%08x, identity=%u\n",
+ lbc->clientIndex(), lbc->client ? lbc->client->cid : 0,
+ lbc->getIdentity());
+ }
+ result.append(buffer);
+ buffer[0] = 0;
+ /*** Layer ***/
+ Layer* const l = LayerBase::dynamicCast<Layer*>((LayerBase*)layer);
+ if (l) {
+ const LayerBitmap& buf0(l->getBuffer(0));
+ const LayerBitmap& buf1(l->getBuffer(1));
+ snprintf(buffer, SIZE,
+ " "
+ "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u], mTextureName=%d,"
+ " freezeLock=%p, swapState=0x%08x\n",
+ l->pixelFormat(),
+ buf0.width(), buf0.height(), buf0.stride(),
+ buf1.width(), buf1.height(), buf1.stride(),
+ l->getTextureName(), l->getFreezeLock().get(),
+ l->lcblk->swapState);
+ }
+ result.append(buffer);
+ buffer[0] = 0;
+ 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);
+
+ sp<AllocatorInterface> allocator;
+ if (mGPU != 0) {
+ snprintf(buffer, SIZE, " GPU owner: %d\n", mGPU->getOwner());
+ result.append(buffer);
+ allocator = mGPU->getAllocator();
+ if (allocator != 0) {
+ allocator->dump(result, "GPU Allocator");
+ }
+ }
+ allocator = mSurfaceHeapManager->getAllocator(NATIVE_MEMORY_TYPE_PMEM);
+ if (allocator != 0) {
+ allocator->dump(result, "PMEM Allocator");
+ }
+ }
+ 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:
+ case REVOKE_GPU:
+ {
+ // codes that require permission check
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int self_pid = getpid();
+ if (UNLIKELY(pid != self_pid)) {
+ // we're called from a different process, do the real check
+ if (!checkCallingPermission(
+ String16("android.permission.ACCESS_SURFACE_FLINGER")))
+ {
+ const int uid = ipc->getCallingUid();
+ 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) {
+ // HARDWARE_TEST stuff...
+ if (UNLIKELY(checkCallingPermission(
+ String16("android.permission.HARDWARE_TEST")) == false))
+ { // not allowed
+ LOGE("Permission Denial: pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ return PERMISSION_DENIED;
+ }
+ int n;
+ switch (code) {
+ case 1000: // SHOW_CPU
+ n = data.readInt32();
+ mDebugCpu = n ? 1 : 0;
+ if (mDebugCpu) {
+ if (mCpuGauge == 0) {
+ mCpuGauge = new CPUGauge(this, ms2ns(500));
+ }
+ } else {
+ if (mCpuGauge != 0) {
+ mCpuGauge->requestExitAndWait();
+ Mutex::Autolock _l(mDebugLock);
+ mCpuGauge.clear();
+ }
+ }
+ return NO_ERROR;
+ case 1001: // SHOW_FPS
+ n = data.readInt32();
+ mDebugFps = n ? 1 : 0;
+ 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: // ask GPU revoke
+ mGPU->friendlyRevoke();
+ return NO_ERROR;
+ case 1006: // revoke GPU
+ mGPU->unconditionalRevoke();
+ return NO_ERROR;
+ case 1007: // set mFreezeCount
+ mFreezeCount = data.readInt32();
+ return NO_ERROR;
+ case 1010: // interrogate.
+ reply->writeInt32(mDebugCpu);
+ 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;
+}
+
+// ---------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger)
+ : ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)
+{
+ mSharedHeapAllocator = getSurfaceHeapManager()->createHeap();
+ const int pgsize = getpagesize();
+ const int cblksize=((sizeof(per_client_cblk_t)+(pgsize-1))&~(pgsize-1));
+ mCblkHeap = new MemoryDealer(cblksize);
+ mCblkMemory = mCblkHeap->allocate(cblksize);
+ if (mCblkMemory != 0) {
+ ctrlblk = static_cast<per_client_cblk_t *>(mCblkMemory->pointer());
+ if (ctrlblk) { // construct the shared structure in-place.
+ new(ctrlblk) per_client_cblk_t;
+ }
+ }
+}
+
+Client::~Client() {
+ if (ctrlblk) {
+ const int pgsize = getpagesize();
+ ctrlblk->~per_client_cblk_t(); // destroy our shared-structure.
+ }
+}
+
+const sp<SurfaceHeapManager>& Client::getSurfaceHeapManager() const {
+ return mFlinger->getSurfaceHeapManager();
+}
+
+int32_t Client::generateId(int pid)
+{
+ const uint32_t i = clz( ~mBitmap );
+ if (i >= NUM_LAYERS_MAX) {
+ return NO_MEMORY;
+ }
+ mPid = pid;
+ mInUse.add(uint8_t(i));
+ mBitmap |= 1<<(31-i);
+ return i;
+}
+status_t Client::bindLayer(LayerBaseClient* layer, int32_t id)
+{
+ ssize_t idx = mInUse.indexOf(id);
+ if (idx < 0)
+ return NAME_NOT_FOUND;
+ return mLayers.insertAt(layer, idx);
+}
+void Client::free(int32_t id)
+{
+ ssize_t idx = mInUse.remove(uint8_t(id));
+ if (idx >= 0) {
+ mBitmap &= ~(1<<(31-id));
+ mLayers.removeItemsAt(idx);
+ }
+}
+
+sp<MemoryDealer> Client::createAllocator(uint32_t flags)
+{
+ sp<MemoryDealer> allocator;
+ allocator = getSurfaceHeapManager()->createHeap(
+ flags, getClientPid(), mSharedHeapAllocator);
+ return allocator;
+}
+
+bool Client::isValid(int32_t i) const {
+ return (uint32_t(i)<NUM_LAYERS_MAX) && (mBitmap & (1<<(31-i)));
+}
+const uint8_t* Client::inUseArray() const {
+ return mInUse.array();
+}
+size_t Client::numActiveLayers() const {
+ return mInUse.size();
+}
+LayerBaseClient* Client::getLayerUser(int32_t i) const {
+ ssize_t idx = mInUse.indexOf(uint8_t(i));
+ if (idx<0) return 0;
+ return mLayers[idx];
+}
+
+void Client::dump(const char* what)
+{
+}
+
+// ---------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+BClient::BClient(SurfaceFlinger *flinger, ClientID cid, const sp<IMemory>& cblk)
+ : mId(cid), mFlinger(flinger), mCblk(cblk)
+{
+}
+
+BClient::~BClient() {
+ // destroy all resources attached to this client
+ mFlinger->destroyConnection(mId);
+}
+
+void BClient::getControlBlocks(sp<IMemory>* ctrl) const {
+ *ctrl = mCblk;
+}
+
+sp<ISurface> BClient::createSurface(
+ ISurfaceFlingerClient::surface_data_t* params, int pid,
+ DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags)
+{
+ return mFlinger->createSurface(mId, pid, params, display, w, h, format, flags);
+}
+
+status_t BClient::destroySurface(SurfaceID sid)
+{
+ sid |= (mId << 16); // add the client-part to id
+ return mFlinger->destroySurface(sid);
+}
+
+status_t BClient::setState(int32_t count, const layer_state_t* states)
+{
+ return mFlinger->setClientState(mId, count, states);
+}
+
+// ---------------------------------------------------------------------------
+
+GraphicPlane::GraphicPlane()
+ : mHw(0)
+{
+}
+
+GraphicPlane::~GraphicPlane() {
+ delete mHw;
+}
+
+bool GraphicPlane::initialized() const {
+ return mHw ? true : false;
+}
+
+void GraphicPlane::setDisplayHardware(DisplayHardware *hw) {
+ mHw = hw;
+}
+
+void GraphicPlane::setTransform(const Transform& tr) {
+ mTransform = tr;
+ mGlobalTransform = mOrientationTransform * mTransform;
+}
+
+status_t GraphicPlane::orientationToTransfrom(
+ int orientation, int w, int h, Transform* tr)
+{
+ float a, b, c, d, x, y;
+ switch (orientation) {
+ case ISurfaceComposer::eOrientationDefault:
+ a=1; b=0; c=0; d=1; x=0; y=0;
+ break;
+ case ISurfaceComposer::eOrientation90:
+ a=0; b=-1; c=1; d=0; x=w; y=0;
+ break;
+ case ISurfaceComposer::eOrientation180:
+ a=-1; b=0; c=0; d=-1; x=w; y=h;
+ break;
+ case ISurfaceComposer::eOrientation270:
+ a=0; b=1; c=-1; d=0; x=0; y=h;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+ tr->set(a, b, c, d);
+ tr->set(x, y);
+ return NO_ERROR;
+}
+
+status_t GraphicPlane::setOrientation(int orientation)
+{
+ const DisplayHardware& hw(displayHardware());
+ const float w = hw.getWidth();
+ const float h = hw.getHeight();
+
+ if (orientation == ISurfaceComposer::eOrientationDefault) {
+ // make sure the default orientation is optimal
+ mOrientationTransform.reset();
+ mGlobalTransform = mTransform;
+ return NO_ERROR;
+ }
+
+ // If the rotation can be handled in hardware, this is where
+ // the magic should happen.
+ if (UNLIKELY(orientation == 42)) {
+ float a, b, c, d, x, y;
+ const float r = (3.14159265f / 180.0f) * 42.0f;
+ const float si = sinf(r);
+ const float co = cosf(r);
+ a=co; b=-si; c=si; d=co;
+ x = si*(h*0.5f) + (1-co)*(w*0.5f);
+ y =-si*(w*0.5f) + (1-co)*(h*0.5f);
+ mOrientationTransform.set(a, b, c, d);
+ mOrientationTransform.set(x, y);
+ } else {
+ GraphicPlane::orientationToTransfrom(orientation, w, h,
+ &mOrientationTransform);
+ }
+
+ mGlobalTransform = mOrientationTransform * mTransform;
+ return NO_ERROR;
+}
+
+const DisplayHardware& GraphicPlane::displayHardware() const {
+ return *mHw;
+}
+
+const Transform& GraphicPlane::transform() const {
+ return mGlobalTransform;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
new file mode 100644
index 0000000..f7d7764
--- /dev/null
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -0,0 +1,435 @@
+/*
+ * 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/MemoryDealer.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/ISurfaceComposer.h>
+#include <ui/ISurfaceFlingerClient.h>
+
+#include <private/ui/SharedState.h>
+#include <private/ui/LayerState.h>
+#include <private/ui/SurfaceFlingerSynchro.h>
+
+#include "Barrier.h"
+#include "BootAnimation.h"
+#include "CPUGauge.h"
+#include "Layer.h"
+#include "Tokenizer.h"
+
+struct copybit_device_t;
+struct overlay_device_t;
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class Client;
+class BClient;
+class DisplayHardware;
+class FreezeLock;
+class GPUHardwareInterface;
+class IGPUCallback;
+class Layer;
+class LayerBuffer;
+class LayerOrientationAnim;
+class OrientationAnimation;
+class SurfaceHeapManager;
+
+typedef int32_t ClientID;
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+// ---------------------------------------------------------------------------
+
+class Client
+{
+public:
+ Client(ClientID cid, const sp<SurfaceFlinger>& flinger);
+ ~Client();
+
+ int32_t generateId(int pid);
+ void free(int32_t id);
+ status_t bindLayer(LayerBaseClient* layer, int32_t id);
+ sp<MemoryDealer> createAllocator(uint32_t memory_type);
+
+ inline bool isValid(int32_t i) const;
+ inline const uint8_t* inUseArray() const;
+ inline size_t numActiveLayers() const;
+ LayerBaseClient* getLayerUser(int32_t i) const;
+ const Vector<LayerBaseClient*>& getLayers() const { return mLayers; }
+ const sp<IMemory>& controlBlockMemory() const { return mCblkMemory; }
+ void dump(const char* what);
+ const sp<SurfaceHeapManager>& getSurfaceHeapManager() const;
+
+ // pointer to this client's control block
+ per_client_cblk_t* ctrlblk;
+ ClientID cid;
+
+
+private:
+ int getClientPid() const { return mPid; }
+
+ int mPid;
+ uint32_t mBitmap;
+ SortedVector<uint8_t> mInUse;
+ Vector<LayerBaseClient*> mLayers;
+ sp<MemoryDealer> mCblkHeap;
+ sp<SurfaceFlinger> mFlinger;
+ sp<MemoryDealer> mSharedHeapAllocator;
+ sp<MemoryDealer> mPMemAllocator;
+ sp<IMemory> mCblkMemory;
+};
+
+// ---------------------------------------------------------------------------
+
+class GraphicPlane
+{
+public:
+ static status_t orientationToTransfrom(int orientation, int w, int h,
+ Transform* tr);
+
+ GraphicPlane();
+ ~GraphicPlane();
+
+ bool initialized() const;
+
+ void setDisplayHardware(DisplayHardware *);
+ void setTransform(const Transform& tr);
+ status_t setOrientation(int orientation);
+
+ const DisplayHardware& displayHardware() const;
+ const Transform& transform() const;
+private:
+ GraphicPlane(const GraphicPlane&);
+ GraphicPlane operator = (const GraphicPlane&);
+
+ DisplayHardware* mHw;
+ Transform mTransform;
+ Transform mOrientationTransform;
+ Transform mGlobalTransform;
+};
+
+// ---------------------------------------------------------------------------
+
+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<ISurfaceFlingerClient> createConnection();
+ virtual sp<IMemory> 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);
+ virtual void signal() const;
+ virtual status_t requestGPU(const sp<IGPUCallback>& callback,
+ gpu_info_t* gpu);
+ virtual status_t revokeGPU();
+
+ void screenReleased(DisplayID dpy);
+ void screenAcquired(DisplayID dpy);
+
+ const sp<SurfaceHeapManager>& getSurfaceHeapManager() const {
+ return mSurfaceHeapManager;
+ }
+
+ const sp<GPUHardwareInterface>& getGPU() const {
+ return mGPU;
+ }
+
+ copybit_device_t* getBlitEngine() const;
+ overlay_control_device_t* getOverlayEngine() const;
+
+
+ status_t removeLayer(LayerBase* layer);
+ status_t addLayer(LayerBase* layer);
+ status_t invalidateLayerVisibility(LayerBase* layer);
+
+private:
+ friend class BClient;
+ friend class LayerBase;
+ friend class LayerBuffer;
+ friend class LayerBaseClient;
+ friend class Layer;
+ friend class LayerBlur;
+
+ sp<ISurface> createSurface(ClientID client, int pid,
+ ISurfaceFlingerClient::surface_data_t* params,
+ DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags);
+
+ LayerBaseClient* createNormalSurfaceLocked(Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
+
+ LayerBaseClient* createBlurSurfaceLocked(Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags);
+
+ LayerBaseClient* createDimSurfaceLocked(Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags);
+
+ LayerBaseClient* createPushBuffersSurfaceLocked(Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags);
+
+ status_t destroySurface(SurfaceID surface_id);
+ status_t setClientState(ClientID cid, 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 LayerBase*const* array() const { return layers.array(); }
+ ssize_t add(LayerBase*, Vector<LayerBase*>::compar_t);
+ ssize_t remove(LayerBase*);
+ ssize_t reorder(LayerBase*, Vector<LayerBase*>::compar_t);
+ ssize_t indexOf(LayerBase* key, size_t guess=0) const;
+ inline LayerBase* operator [] (size_t i) const { return layers[i]; }
+ private:
+ KeyedVector<LayerBase*, size_t> lookup;
+ Vector<LayerBase*> layers;
+ };
+
+ struct State {
+ State() {
+ orientation = ISurfaceComposer::eOrientationDefault;
+ freezeDisplay = 0;
+ }
+ LayerVector layersSortedByZ;
+ uint8_t orientation;
+ uint8_t freezeDisplay;
+ };
+
+ class DelayedTransaction : public Thread
+ {
+ friend class SurfaceFlinger;
+ sp<SurfaceFlinger> mFlinger;
+ nsecs_t mDelay;
+ public:
+ DelayedTransaction(const sp<SurfaceFlinger>& flinger, nsecs_t delay)
+ : Thread(false), mFlinger(flinger), mDelay(delay) {
+ }
+ virtual bool threadLoop() {
+ usleep(mDelay / 1000);
+ if (android_atomic_and(~1,
+ &mFlinger->mDeplayedTransactionPending) == 1) {
+ mFlinger->signalEvent();
+ }
+ return false;
+ }
+ };
+
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+
+ const GraphicPlane& graphicPlane(int dpy) const;
+ GraphicPlane& graphicPlane(int dpy);
+
+ void waitForEvent();
+ void signalEvent();
+ void signalDelayedEvent(nsecs_t delay);
+
+ void handleConsoleEvents();
+ void handleTransaction(uint32_t transactionFlags);
+
+ void computeVisibleRegions(
+ LayerVector& currentLayers,
+ Region& dirtyRegion,
+ Region& wormholeRegion);
+
+ void handlePageFlip();
+ bool lockPageFlip(const LayerVector& currentLayers);
+ void unlockPageFlip(const LayerVector& currentLayers);
+ void handleRepaint();
+ void handleDebugCpu();
+ void scheduleBroadcast(Client* client);
+ void executeScheduledBroadcasts();
+ void postFramebuffer();
+ void composeSurfaces(const Region& dirty);
+ void unlockClients();
+
+
+ void destroyConnection(ClientID cid);
+ LayerBaseClient* getLayerUser_l(SurfaceID index) const;
+ status_t addLayer_l(LayerBase* layer);
+ status_t removeLayer_l(LayerBase* layer);
+ void destroy_all_removed_layers_l();
+ void free_resources_l();
+
+ uint32_t getTransactionFlags(uint32_t flags);
+ uint32_t setTransactionFlags(uint32_t flags, nsecs_t delay = 0);
+ void commitTransaction();
+
+
+ friend class FreezeLock;
+ sp<FreezeLock> getFreezeLock() const;
+ inline void incFreezeCount() { mFreezeCount++; }
+ inline void decFreezeCount() { if (mFreezeCount > 0) mFreezeCount--; }
+ inline bool hasFreezeRequest() const { return mFreezeDisplay; }
+ inline bool isFrozen() const {
+ return mFreezeDisplay || mFreezeCount>0;
+ }
+
+
+ void debugFlashRegions();
+ void debugShowFPS() const;
+ void drawWormhole() const;
+
+ // access must be protected by mStateLock
+ mutable Mutex mStateLock;
+ State mCurrentState;
+ State mDrawingState;
+ volatile int32_t mTransactionFlags;
+ volatile int32_t mTransactionCount;
+ Condition mTransactionCV;
+
+ // protected by mStateLock (but we could use another lock)
+ Tokenizer mTokens;
+ DefaultKeyedVector<ClientID, Client*> mClientsMap;
+ DefaultKeyedVector<SurfaceID, LayerBaseClient*> mLayerMap;
+ GraphicPlane mGraphicPlanes[1];
+ SortedVector<LayerBase*> mRemovedLayers;
+ Vector<Client*> mDisconnectedClients;
+
+ // constant members (no synchronization needed for access)
+ sp<MemoryDealer> mServerHeap;
+ sp<IMemory> mServerCblkMemory;
+ surface_flinger_cblk_t* mServerCblk;
+ sp<SurfaceHeapManager> mSurfaceHeapManager;
+ sp<GPUHardwareInterface> mGPU;
+ GLuint mWormholeTexName;
+ sp<BootAnimation> mBootAnimation;
+ nsecs_t mBootTime;
+
+ // Can only accessed from the main thread, these members
+ // don't need synchronization
+ Region mDirtyRegion;
+ Region mInvalidRegion;
+ Region mWormholeRegion;
+ Client* mLastScheduledBroadcast;
+ SortedVector<Client*> mScheduledBroadcasts;
+ bool mVisibleRegionsDirty;
+ bool mDeferReleaseConsole;
+ bool mFreezeDisplay;
+ int32_t mFreezeCount;
+ nsecs_t mFreezeDisplayTime;
+ friend class OrientationAnimation;
+ OrientationAnimation* mOrientationAnimation;
+
+ // access protected by mDebugLock
+ mutable Mutex mDebugLock;
+ sp<CPUGauge> mCpuGauge;
+
+ // don't use a lock for these, we don't care
+ int mDebugRegion;
+ int mDebugCpu;
+ int mDebugFps;
+ int mDebugBackground;
+ int mDebugNoBootAnimation;
+
+ // these are thread safe
+ mutable Barrier mReadyToRunBarrier;
+ mutable SurfaceFlingerSynchro mSyncObject;
+ volatile int32_t mDeplayedTransactionPending;
+
+ // 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();
+ }
+};
+
+// ---------------------------------------------------------------------------
+
+class BClient : public BnSurfaceFlingerClient
+{
+public:
+ BClient(SurfaceFlinger *flinger, ClientID cid,
+ const sp<IMemory>& cblk);
+ ~BClient();
+
+ // ISurfaceFlingerClient interface
+ virtual void getControlBlocks(sp<IMemory>* ctrl) const;
+
+ virtual sp<ISurface> createSurface(
+ surface_data_t* params, int pid,
+ 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);
+
+private:
+ ClientID mId;
+ SurfaceFlinger* mFlinger;
+ sp<IMemory> mCblk;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SURFACE_FLINGER_H
diff --git a/libs/surfaceflinger/Tokenizer.cpp b/libs/surfaceflinger/Tokenizer.cpp
new file mode 100644
index 0000000..ef51d6a
--- /dev/null
+++ b/libs/surfaceflinger/Tokenizer.cpp
@@ -0,0 +1,172 @@
+/*
+ * 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 <stdio.h>
+
+#include "Tokenizer.h"
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+ANDROID_BASIC_TYPES_TRAITS(Tokenizer::run_t)
+
+Tokenizer::Tokenizer()
+{
+}
+
+Tokenizer::Tokenizer(const Tokenizer& other)
+ : mRanges(other.mRanges)
+{
+}
+
+Tokenizer::~Tokenizer()
+{
+}
+
+uint32_t Tokenizer::acquire()
+{
+ if (!mRanges.size() || mRanges[0].first) {
+ _insertTokenAt(0,0);
+ return 0;
+ }
+
+ // just extend the first run
+ const run_t& run = mRanges[0];
+ uint32_t token = run.first + run.length;
+ _insertTokenAt(token, 1);
+ return token;
+}
+
+bool Tokenizer::isAcquired(uint32_t token) const
+{
+ return (_indexOrderOf(token) >= 0);
+}
+
+status_t Tokenizer::reserve(uint32_t token)
+{
+ size_t o;
+ const ssize_t i = _indexOrderOf(token, &o);
+ if (i >= 0) {
+ return BAD_VALUE; // this token is already taken
+ }
+ ssize_t err = _insertTokenAt(token, o);
+ return (err<0) ? err : status_t(NO_ERROR);
+}
+
+status_t Tokenizer::release(uint32_t token)
+{
+ const ssize_t i = _indexOrderOf(token);
+ if (i >= 0) {
+ const run_t& run = mRanges[i];
+ if ((token >= run.first) && (token < run.first+run.length)) {
+ // token in this range, we need to split
+ run_t& run = mRanges.editItemAt(i);
+ if ((token == run.first) || (token == run.first+run.length-1)) {
+ if (token == run.first) {
+ run.first += 1;
+ }
+ run.length -= 1;
+ if (run.length == 0) {
+ // XXX: should we systematically remove a run that's empty?
+ mRanges.removeItemsAt(i);
+ }
+ } else {
+ // split the run
+ run_t new_run;
+ new_run.first = token+1;
+ new_run.length = run.first+run.length - new_run.first;
+ run.length = token - run.first;
+ mRanges.insertAt(new_run, i+1);
+ }
+ return NO_ERROR;
+ }
+ }
+ return NAME_NOT_FOUND;
+}
+
+ssize_t Tokenizer::_indexOrderOf(uint32_t token, size_t* order) const
+{
+ // binary search
+ ssize_t err = NAME_NOT_FOUND;
+ ssize_t l = 0;
+ ssize_t h = mRanges.size()-1;
+ ssize_t mid;
+ const run_t* a = mRanges.array();
+ while (l <= h) {
+ mid = l + (h - l)/2;
+ const run_t* const curr = a + mid;
+ int c = 0;
+ if (token < curr->first) c = 1;
+ else if (token >= curr->first+curr->length) c = -1;
+ if (c == 0) {
+ err = l = mid;
+ break;
+ } else if (c < 0) {
+ l = mid + 1;
+ } else {
+ h = mid - 1;
+ }
+ }
+ if (order) *order = l;
+ return err;
+}
+
+ssize_t Tokenizer::_insertTokenAt(uint32_t token, size_t index)
+{
+ const size_t c = mRanges.size();
+
+ if (index >= 1) {
+ // do we need to merge with the previous run?
+ run_t& p = mRanges.editItemAt(index-1);
+ if (p.first+p.length == token) {
+ p.length += 1;
+ if (index < c) {
+ const run_t& n = mRanges[index];
+ if (token+1 == n.first) {
+ p.length += n.length;
+ mRanges.removeItemsAt(index);
+ }
+ }
+ return index;
+ }
+ }
+
+ if (index < c) {
+ // do we need to merge with the next run?
+ run_t& n = mRanges.editItemAt(index);
+ if (token+1 == n.first) {
+ n.first -= 1;
+ n.length += 1;
+ return index;
+ }
+ }
+
+ return mRanges.insertAt(run_t(token,1), index);
+}
+
+void Tokenizer::dump() const
+{
+ const run_t* ranges = mRanges.array();
+ const size_t c = mRanges.size();
+ printf("Tokenizer (%p, size = %lu)\n", this, c);
+ for (size_t i=0 ; i<c ; i++) {
+ printf("%lu: (%u, %u)\n", i, ranges[i].first, ranges[i].length);
+ }
+}
+
+}; // namespace android
+
diff --git a/libs/surfaceflinger/Tokenizer.h b/libs/surfaceflinger/Tokenizer.h
new file mode 100644
index 0000000..6b3057d
--- /dev/null
+++ b/libs/surfaceflinger/Tokenizer.h
@@ -0,0 +1,57 @@
+/*
+ * 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_TOKENIZER_H
+#define ANDROID_TOKENIZER_H
+
+#include <utils/Vector.h>
+#include <utils/Errors.h>
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+class Tokenizer
+{
+public:
+ Tokenizer();
+ Tokenizer(const Tokenizer& other);
+ ~Tokenizer();
+
+ uint32_t acquire();
+ status_t reserve(uint32_t token);
+ status_t release(uint32_t token);
+ bool isAcquired(uint32_t token) const;
+
+ void dump() const;
+
+ struct run_t {
+ run_t() {};
+ run_t(uint32_t f, uint32_t l) : first(f), length(l) {}
+ uint32_t first;
+ uint32_t length;
+ };
+private:
+ ssize_t _indexOrderOf(uint32_t token, size_t* order=0) const;
+ ssize_t _insertTokenAt(uint32_t token, size_t index);
+ Vector<run_t> mRanges;
+};
+
+}; // namespace android
+
+// ----------------------------------------------------------------------------
+
+#endif // ANDROID_TOKENIZER_H
diff --git a/libs/surfaceflinger/Transform.cpp b/libs/surfaceflinger/Transform.cpp
new file mode 100644
index 0000000..bec7a64
--- /dev/null
+++ b/libs/surfaceflinger/Transform.cpp
@@ -0,0 +1,204 @@
+/*
+ * 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 <ui/Region.h>
+
+#include <private/pixelflinger/ggl_fixed.h>
+
+#include "Transform.h"
+
+// ---------------------------------------------------------------------------
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+Transform::Transform()
+ : mType(0)
+{
+ mTransform.reset();
+}
+
+Transform::Transform(const Transform& other)
+ : mTransform(other.mTransform), mType(other.mType)
+{
+}
+
+Transform::~Transform() {
+}
+
+Transform Transform::operator * (const Transform& rhs) const
+{
+ if (LIKELY(mType == 0))
+ return rhs;
+
+ Transform r(*this);
+ r.mTransform.preConcat(rhs.mTransform);
+ r.mType |= rhs.mType;
+ return r;
+}
+
+float Transform::operator [] (int i) const
+{
+ float r = 0;
+ switch(i) {
+ case 0: r = SkScalarToFloat( mTransform[SkMatrix::kMScaleX] ); break;
+ case 1: r = SkScalarToFloat( mTransform[SkMatrix::kMSkewX] ); break;
+ case 2: r = SkScalarToFloat( mTransform[SkMatrix::kMSkewY] ); break;
+ case 3: r = SkScalarToFloat( mTransform[SkMatrix::kMScaleY] ); break;
+ }
+ return r;
+}
+
+uint8_t Transform::type() const
+{
+ if (UNLIKELY(mType & 0x80000000)) {
+ mType = mTransform.getType();
+ }
+ return uint8_t(mType & 0xFF);
+}
+
+bool Transform::transformed() const {
+ return type() > SkMatrix::kTranslate_Mask;
+}
+
+int Transform::tx() const {
+ return SkScalarRound( mTransform[SkMatrix::kMTransX] );
+}
+
+int Transform::ty() const {
+ return SkScalarRound( mTransform[SkMatrix::kMTransY] );
+}
+
+void Transform::reset() {
+ mTransform.reset();
+ mType = 0;
+}
+
+void Transform::set( float xx, float xy,
+ float yx, float yy)
+{
+ mTransform.set(SkMatrix::kMScaleX, SkFloatToScalar(xx));
+ mTransform.set(SkMatrix::kMSkewX, SkFloatToScalar(xy));
+ mTransform.set(SkMatrix::kMSkewY, SkFloatToScalar(yx));
+ mTransform.set(SkMatrix::kMScaleY, SkFloatToScalar(yy));
+ mType |= 0x80000000;
+}
+
+void Transform::set(int tx, int ty)
+{
+ if (tx | ty) {
+ mTransform.set(SkMatrix::kMTransX, SkIntToScalar(tx));
+ mTransform.set(SkMatrix::kMTransY, SkIntToScalar(ty));
+ mType |= SkMatrix::kTranslate_Mask;
+ } else {
+ mTransform.set(SkMatrix::kMTransX, 0);
+ mTransform.set(SkMatrix::kMTransY, 0);
+ mType &= ~SkMatrix::kTranslate_Mask;
+ }
+}
+
+void Transform::transform(GLfixed* point, int x, int y) const
+{
+ SkPoint s;
+ mTransform.mapXY(SkIntToScalar(x), SkIntToScalar(y), &s);
+ point[0] = SkScalarToFixed(s.fX);
+ point[1] = SkScalarToFixed(s.fY);
+}
+
+Rect Transform::makeBounds(int w, int h) const
+{
+ Rect r;
+ SkRect d, s;
+ s.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
+ mTransform.mapRect(&d, s);
+ r.left = SkScalarRound( d.fLeft );
+ r.top = SkScalarRound( d.fTop );
+ r.right = SkScalarRound( d.fRight );
+ r.bottom = SkScalarRound( d.fBottom );
+ return r;
+}
+
+Rect Transform::transform(const Rect& bounds) const
+{
+ Rect r;
+ SkRect d, s;
+ s.set( SkIntToScalar( bounds.left ),
+ SkIntToScalar( bounds.top ),
+ SkIntToScalar( bounds.right ),
+ SkIntToScalar( bounds.bottom ));
+ mTransform.mapRect(&d, s);
+ r.left = SkScalarRound( d.fLeft );
+ r.top = SkScalarRound( d.fTop );
+ r.right = SkScalarRound( d.fRight );
+ r.bottom = SkScalarRound( d.fBottom );
+ return r;
+}
+
+Region Transform::transform(const Region& reg) const
+{
+ Region out;
+ if (UNLIKELY(transformed())) {
+ if (LIKELY(preserveRects())) {
+ Rect r;
+ Region::iterator iterator(reg);
+ while (iterator.iterate(&r)) {
+ out.orSelf(transform(r));
+ }
+ } else {
+ out.set(transform(reg.bounds()));
+ }
+ } else {
+ out = reg.translate(tx(), ty());
+ }
+ return out;
+}
+
+int32_t Transform::getOrientation() const
+{
+ uint32_t flags = 0;
+ if (UNLIKELY(transformed())) {
+ SkScalar a = mTransform[SkMatrix::kMScaleX];
+ SkScalar b = mTransform[SkMatrix::kMSkewX];
+ SkScalar c = mTransform[SkMatrix::kMSkewY];
+ SkScalar d = mTransform[SkMatrix::kMScaleY];
+ if (b==0 && c==0 && a && d) {
+ if (a<0) flags |= FLIP_H;
+ if (d<0) flags |= FLIP_V;
+ } else if (b && c && a==0 && d==0) {
+ flags |= ROT_90;
+ if (b>0) flags |= FLIP_H;
+ if (c<0) flags |= FLIP_V;
+ } else {
+ flags = 0x80000000;
+ }
+ }
+ return flags;
+}
+
+bool Transform::preserveRects() const
+{
+ return mTransform.rectStaysRect();
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/Transform.h b/libs/surfaceflinger/Transform.h
new file mode 100644
index 0000000..0b4835e
--- /dev/null
+++ b/libs/surfaceflinger/Transform.h
@@ -0,0 +1,87 @@
+/*
+ * 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>
+
+#include <GLES/gl.h>
+
+#include <core/SkMatrix.h>
+
+namespace android {
+
+class Region;
+
+// ---------------------------------------------------------------------------
+
+class Transform
+{
+public:
+ Transform();
+ Transform(const Transform& other);
+ ~Transform();
+
+ 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 = 0x80000000
+ };
+
+ bool transformed() const;
+ int32_t getOrientation() const;
+ bool preserveRects() const;
+
+ int tx() const;
+ int ty() const;
+
+ void reset();
+ void set(float xx, float xy, float yx, float yy);
+ void set(int tx, int ty);
+
+ Rect makeBounds(int w, int h) const;
+ void transform(GLfixed* point, int x, int y) const;
+ Region transform(const Region& reg) const;
+ Rect transform(const Rect& bounds) const;
+
+ Transform operator * (const Transform& rhs) const;
+ float operator [] (int i) const;
+
+ inline uint32_t getType() const { return type(); }
+
+ inline Transform(bool) : mType(0xFF) { };
+
+private:
+ uint8_t type() const;
+
+private:
+ SkMatrix mTransform;
+ mutable uint32_t mType;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif /* ANDROID_TRANSFORM_H */
diff --git a/libs/surfaceflinger/VRamHeap.cpp b/libs/surfaceflinger/VRamHeap.cpp
new file mode 100644
index 0000000..0ccd71f
--- /dev/null
+++ b/libs/surfaceflinger/VRamHeap.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <utils/MemoryDealer.h>
+#include <utils/MemoryBase.h>
+#include <utils/MemoryHeapPmem.h>
+#include <utils/MemoryHeapBase.h>
+
+#include "GPUHardware/GPUHardware.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+/*
+ * Amount of memory we reserve for surface, per client in PMEM
+ * (PMEM is used for 2D acceleration)
+ * 8 MB of address space per client should be enough.
+ */
+static const int PMEM_SIZE = int(8 * 1024 * 1024);
+
+int SurfaceHeapManager::global_pmem_heap = 0;
+
+// ---------------------------------------------------------------------------
+
+SurfaceHeapManager::SurfaceHeapManager(const sp<SurfaceFlinger>& flinger,
+ size_t clientHeapSize)
+ : mFlinger(flinger), mClientHeapSize(clientHeapSize)
+{
+ SurfaceHeapManager::global_pmem_heap = 1;
+}
+
+SurfaceHeapManager::~SurfaceHeapManager()
+{
+}
+
+void SurfaceHeapManager::onFirstRef()
+{
+ if (global_pmem_heap) {
+ const char* device = "/dev/pmem";
+ mPMemHeap = new PMemHeap(device, PMEM_SIZE);
+ if (mPMemHeap->base() == MAP_FAILED) {
+ mPMemHeap.clear();
+ global_pmem_heap = 0;
+ }
+ }
+}
+
+sp<MemoryDealer> SurfaceHeapManager::createHeap(
+ uint32_t flags,
+ pid_t client_pid,
+ const sp<MemoryDealer>& defaultAllocator)
+{
+ sp<MemoryDealer> dealer;
+
+ if (flags & ISurfaceComposer::eGPU) {
+ // don't grant GPU memory if GPU is disabled
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.egl.hw", value, "1");
+ if (atoi(value) == 0) {
+ flags &= ~ISurfaceComposer::eGPU;
+ }
+ }
+
+ if (flags & ISurfaceComposer::eGPU) {
+ // FIXME: this is msm7201A specific, where gpu surfaces may not be secure
+ if (!(flags & ISurfaceComposer::eSecure)) {
+ // if GPU doesn't work, we try eHardware
+ flags |= ISurfaceComposer::eHardware;
+ // asked for GPU memory, try that first
+ dealer = mFlinger->getGPU()->request(client_pid);
+ }
+ }
+
+ if (dealer == NULL) {
+ if (defaultAllocator != NULL)
+ // if a default allocator is given, use that
+ dealer = defaultAllocator;
+ }
+
+ if (dealer == NULL) {
+ // always try h/w accelerated memory first
+ if (global_pmem_heap) {
+ const sp<PMemHeap>& heap(mPMemHeap);
+ if (dealer == NULL && heap != NULL) {
+ dealer = new MemoryDealer(
+ heap->createClientHeap(),
+ heap->getAllocator());
+ }
+ }
+ }
+
+ if (dealer == NULL) {
+ // return the ashmem allocator (software rendering)
+ dealer = new MemoryDealer(mClientHeapSize, 0, "SFNativeHeap");
+ }
+ return dealer;
+}
+
+sp<SimpleBestFitAllocator> SurfaceHeapManager::getAllocator(int type) const
+{
+ Mutex::Autolock _l(mLock);
+ sp<SimpleBestFitAllocator> allocator;
+
+ // this is only used for debugging
+ switch (type) {
+ case NATIVE_MEMORY_TYPE_PMEM:
+ if (mPMemHeap != 0) {
+ allocator = mPMemHeap->getAllocator();
+ }
+ break;
+ }
+ return allocator;
+}
+
+// ---------------------------------------------------------------------------
+
+PMemHeap::PMemHeap(const char* const device, size_t size, size_t reserved)
+ : MemoryHeapBase(device, size)
+{
+ //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
+ if (base() != MAP_FAILED) {
+ //LOGD("%s, %u bytes", device, virtualSize());
+ if (reserved == 0)
+ reserved = virtualSize();
+ mAllocator = new SimpleBestFitAllocator(reserved);
+ }
+}
+
+PMemHeap::~PMemHeap() {
+ //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
+}
+
+sp<MemoryHeapPmem> PMemHeap::createClientHeap() {
+ sp<MemoryHeapBase> parentHeap(this);
+ return new MemoryHeapPmem(parentHeap);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/surfaceflinger/VRamHeap.h b/libs/surfaceflinger/VRamHeap.h
new file mode 100644
index 0000000..9140167
--- /dev/null
+++ b/libs/surfaceflinger/VRamHeap.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2008 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_VRAM_HEAP_H
+#define ANDROID_VRAM_HEAP_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/MemoryDealer.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class PMemHeap;
+class MemoryHeapPmem;
+class SurfaceFlinger;
+
+// ---------------------------------------------------------------------------
+
+class SurfaceHeapManager : public RefBase
+{
+public:
+ SurfaceHeapManager(const sp<SurfaceFlinger>& flinger, size_t clientHeapSize);
+ virtual ~SurfaceHeapManager();
+ virtual void onFirstRef();
+ /* use ISurfaceComposer flags eGPU|eHArdware|eSecure */
+ sp<MemoryDealer> createHeap(uint32_t flags=0, pid_t client_pid = 0,
+ const sp<MemoryDealer>& defaultAllocator = 0);
+
+ // used for debugging only...
+ sp<SimpleBestFitAllocator> getAllocator(int type) const;
+
+private:
+ sp<PMemHeap> getHeap(int type) const;
+
+ sp<SurfaceFlinger> mFlinger;
+ mutable Mutex mLock;
+ size_t mClientHeapSize;
+ sp<PMemHeap> mPMemHeap;
+ static int global_pmem_heap;
+};
+
+// ---------------------------------------------------------------------------
+
+class PMemHeap : public MemoryHeapBase
+{
+public:
+ PMemHeap(const char* const vram,
+ size_t size=0, size_t reserved=0);
+ virtual ~PMemHeap();
+
+ virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
+ return mAllocator;
+ }
+ virtual sp<MemoryHeapPmem> createClientHeap();
+
+private:
+ sp<SimpleBestFitAllocator> mAllocator;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_VRAM_HEAP_H
diff --git a/libs/surfaceflinger/clz.cpp b/libs/surfaceflinger/clz.cpp
new file mode 100644
index 0000000..2456b86
--- /dev/null
+++ b/libs/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/libs/surfaceflinger/clz.h b/libs/surfaceflinger/clz.h
new file mode 100644
index 0000000..0ddf986
--- /dev/null
+++ b/libs/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/libs/surfaceflinger/tests/Android.mk b/libs/surfaceflinger/tests/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/libs/surfaceflinger/tests/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/libs/surfaceflinger/tests/overlays/Android.mk b/libs/surfaceflinger/tests/overlays/Android.mk
new file mode 100644
index 0000000..dc47e45
--- /dev/null
+++ b/libs/surfaceflinger/tests/overlays/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ overlays.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libui
+
+LOCAL_MODULE:= test-overlays
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libs/surfaceflinger/tests/overlays/overlays.cpp b/libs/surfaceflinger/tests/overlays/overlays.cpp
new file mode 100644
index 0000000..f3c046f
--- /dev/null
+++ b/libs/surfaceflinger/tests/overlays/overlays.cpp
@@ -0,0 +1,58 @@
+#include <utils/IPCThreadState.h>
+#include <utils/ProcessState.h>
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <ui/Surface.h>
+#include <ui/ISurface.h>
+#include <ui/Overlay.h>
+#include <ui/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;
+}