eclair snapshot
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 7bbe38b..84aec61 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -4,10 +4,13 @@
LOCAL_SRC_FILES:= \
Camera.cpp \
CameraParameters.cpp \
- EGLDisplaySurface.cpp \
- EGLNativeWindowSurface.cpp \
+ EGLUtils.cpp \
EventHub.cpp \
EventRecurrence.cpp \
+ FramebufferNativeWindow.cpp \
+ GraphicBuffer.cpp \
+ GraphicBufferAllocator.cpp \
+ GraphicBufferMapper.cpp \
KeyLayoutMap.cpp \
KeyCharacterMap.cpp \
ICamera.cpp \
@@ -22,18 +25,23 @@
PixelFormat.cpp \
Rect.cpp \
Region.cpp \
+ SharedBufferStack.cpp \
Surface.cpp \
- SurfaceComposerClient.cpp \
- SurfaceFlingerSynchro.cpp
+ SurfaceComposerClient.cpp
LOCAL_SHARED_LIBRARIES := \
- libcorecg \
libcutils \
libutils \
+ libEGL \
+ libbinder \
libpixelflinger \
libhardware \
libhardware_legacy
LOCAL_MODULE:= libui
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -lpthread
+endif
+
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 5015379..09a36f1 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -19,9 +19,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Camera"
#include <utils/Log.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/threads.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <ui/Surface.h>
#include <ui/Camera.h>
#include <ui/ICameraService.h>
@@ -242,6 +242,14 @@
return c->autoFocus();
}
+status_t Camera::cancelAutoFocus()
+{
+ LOGV("cancelAutoFocus");
+ sp <ICamera> c = mCamera;
+ if (c == 0) return NO_INIT;
+ return c->cancelAutoFocus();
+}
+
// take a picture
status_t Camera::takePicture()
{
@@ -270,6 +278,15 @@
return params;
}
+// send command to camera driver
+status_t Camera::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
+{
+ LOGD("sendCommand");
+ sp <ICamera> c = mCamera;
+ if (c == 0) return NO_INIT;
+ return c->sendCommand(cmd, arg1, arg2);
+}
+
void Camera::setListener(const sp<CameraListener>& listener)
{
Mutex::Autolock _l(mLock);
diff --git a/libs/ui/CameraParameters.cpp b/libs/ui/CameraParameters.cpp
index 6c25836..8f1749d 100644
--- a/libs/ui/CameraParameters.cpp
+++ b/libs/ui/CameraParameters.cpp
@@ -2,16 +2,16 @@
**
** Copyright 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
+** 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
+** 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
+** 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.
*/
@@ -23,6 +23,103 @@
#include <ui/CameraParameters.h>
namespace android {
+// Parameter keys to communicate between camera application and driver.
+const char CameraParameters::KEY_PREVIEW_SIZE[] = "preview-size";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES[] = "preview-size-values";
+const char CameraParameters::KEY_PREVIEW_FORMAT[] = "preview-format";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS[] = "preview-format-values";
+const char CameraParameters::KEY_PREVIEW_FRAME_RATE[] = "preview-frame-rate";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES[] = "preview-frame-rate-values";
+const char CameraParameters::KEY_PICTURE_SIZE[] = "picture-size";
+const char CameraParameters::KEY_SUPPORTED_PICTURE_SIZES[] = "picture-size-values";
+const char CameraParameters::KEY_PICTURE_FORMAT[] = "picture-format";
+const char CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS[] = "picture-format-values";
+const char CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH[] = "jpeg-thumbnail-width";
+const char CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT[] = "jpeg-thumbnail-height";
+const char CameraParameters::KEY_SUPPORTED_THUMBNAIL_SIZES[] = "jpeg-thumbnail-size-values";
+const char CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY[] = "jpeg-thumbnail-quality";
+const char CameraParameters::KEY_JPEG_QUALITY[] = "jpeg-quality";
+const char CameraParameters::KEY_ROTATION[] = "rotation";
+const char CameraParameters::KEY_GPS_LATITUDE[] = "gps-latitude";
+const char CameraParameters::KEY_GPS_LONGITUDE[] = "gps-longitude";
+const char CameraParameters::KEY_GPS_ALTITUDE[] = "gps-altitude";
+const char CameraParameters::KEY_GPS_TIMESTAMP[] = "gps-timestamp";
+const char CameraParameters::KEY_WHITE_BALANCE[] = "whitebalance";
+const char CameraParameters::KEY_SUPPORTED_WHITE_BALANCE[] = "whitebalance-values";
+const char CameraParameters::KEY_EFFECT[] = "effect";
+const char CameraParameters::KEY_SUPPORTED_EFFECTS[] = "effect-values";
+const char CameraParameters::KEY_ANTIBANDING[] = "antibanding";
+const char CameraParameters::KEY_SUPPORTED_ANTIBANDING[] = "antibanding-values";
+const char CameraParameters::KEY_SCENE_MODE[] = "scene-mode";
+const char CameraParameters::KEY_SUPPORTED_SCENE_MODES[] = "scene-mode-values";
+const char CameraParameters::KEY_FLASH_MODE[] = "flash-mode";
+const char CameraParameters::KEY_SUPPORTED_FLASH_MODES[] = "flash-mode-values";
+const char CameraParameters::KEY_FOCUS_MODE[] = "focus-mode";
+const char CameraParameters::KEY_SUPPORTED_FOCUS_MODES[] = "focus-mode-values";
+
+// Values for white balance settings.
+const char CameraParameters::WHITE_BALANCE_AUTO[] = "auto";
+const char CameraParameters::WHITE_BALANCE_INCANDESCENT[] = "incandescent";
+const char CameraParameters::WHITE_BALANCE_FLUORESCENT[] = "fluorescent";
+const char CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT[] = "warm-fluorescent";
+const char CameraParameters::WHITE_BALANCE_DAYLIGHT[] = "daylight";
+const char CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT[] = "cloudy-daylight";
+const char CameraParameters::WHITE_BALANCE_TWILIGHT[] = "twilight";
+const char CameraParameters::WHITE_BALANCE_SHADE[] = "shade";
+
+// Values for effect settings.
+const char CameraParameters::EFFECT_NONE[] = "none";
+const char CameraParameters::EFFECT_MONO[] = "mono";
+const char CameraParameters::EFFECT_NEGATIVE[] = "negative";
+const char CameraParameters::EFFECT_SOLARIZE[] = "solarize";
+const char CameraParameters::EFFECT_SEPIA[] = "sepia";
+const char CameraParameters::EFFECT_POSTERIZE[] = "posterize";
+const char CameraParameters::EFFECT_WHITEBOARD[] = "whiteboard";
+const char CameraParameters::EFFECT_BLACKBOARD[] = "blackboard";
+const char CameraParameters::EFFECT_AQUA[] = "aqua";
+
+// Values for antibanding settings.
+const char CameraParameters::ANTIBANDING_AUTO[] = "auto";
+const char CameraParameters::ANTIBANDING_50HZ[] = "50hz";
+const char CameraParameters::ANTIBANDING_60HZ[] = "60hz";
+const char CameraParameters::ANTIBANDING_OFF[] = "off";
+
+// Values for flash mode settings.
+const char CameraParameters::FLASH_MODE_OFF[] = "off";
+const char CameraParameters::FLASH_MODE_AUTO[] = "auto";
+const char CameraParameters::FLASH_MODE_ON[] = "on";
+const char CameraParameters::FLASH_MODE_RED_EYE[] = "red-eye";
+const char CameraParameters::FLASH_MODE_TORCH[] = "torch";
+
+// Values for scene mode settings.
+const char CameraParameters::SCENE_MODE_AUTO[] = "auto";
+const char CameraParameters::SCENE_MODE_ACTION[] = "action";
+const char CameraParameters::SCENE_MODE_PORTRAIT[] = "portrait";
+const char CameraParameters::SCENE_MODE_LANDSCAPE[] = "landscape";
+const char CameraParameters::SCENE_MODE_NIGHT[] = "night";
+const char CameraParameters::SCENE_MODE_NIGHT_PORTRAIT[] = "night-portrait";
+const char CameraParameters::SCENE_MODE_THEATRE[] = "theatre";
+const char CameraParameters::SCENE_MODE_BEACH[] = "beach";
+const char CameraParameters::SCENE_MODE_SNOW[] = "snow";
+const char CameraParameters::SCENE_MODE_SUNSET[] = "sunset";
+const char CameraParameters::SCENE_MODE_STEADYPHOTO[] = "steadyphoto";
+const char CameraParameters::SCENE_MODE_FIREWORKS[] = "fireworks";
+const char CameraParameters::SCENE_MODE_SPORTS[] = "sports";
+const char CameraParameters::SCENE_MODE_PARTY[] = "party";
+const char CameraParameters::SCENE_MODE_CANDLELIGHT[] = "candlelight";
+
+// Formats for setPreviewFormat and setPictureFormat.
+const char CameraParameters::PIXEL_FORMAT_YUV422SP[] = "yuv422sp";
+const char CameraParameters::PIXEL_FORMAT_YUV420SP[] = "yuv420sp";
+const char CameraParameters::PIXEL_FORMAT_YUV422I[] = "yuv422i-yuyv";
+const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565";
+const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg";
+
+// Values for focus mode settings.
+const char CameraParameters::FOCUS_MODE_AUTO[] = "auto";
+const char CameraParameters::FOCUS_MODE_INFINITY[] = "infinity";
+const char CameraParameters::FOCUS_MODE_MACRO[] = "macro";
+const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed";
static const char* portrait = "portrait";
static const char* landscape = "landscape";
@@ -91,7 +188,7 @@
void CameraParameters::set(const char *key, const char *value)
{
- // XXX i think i can do this with strspn()
+ // XXX i think i can do this with strspn()
if (strchr(key, '=') || strchr(key, ';')) {
//XXX LOGE("Key \"%s\"contains invalid character (= or ;)", key);
return;
@@ -150,7 +247,7 @@
{
char str[32];
sprintf(str, "%dx%d", width, height);
- set("preview-size", str);
+ set(KEY_PREVIEW_SIZE, str);
}
void CameraParameters::getPreviewSize(int *width, int *height) const
@@ -159,7 +256,7 @@
*height = -1;
// Get the current string, if it doesn't exist, leave the -1x-1
- const char *p = get("preview-size");
+ const char *p = get(KEY_PREVIEW_SIZE);
if (p == 0)
return;
@@ -172,17 +269,17 @@
void CameraParameters::setPreviewFrameRate(int fps)
{
- set("preview-frame-rate", fps);
+ set(KEY_PREVIEW_FRAME_RATE, fps);
}
int CameraParameters::getPreviewFrameRate() const
{
- return getInt("preview-frame-rate");
+ return getInt(KEY_PREVIEW_FRAME_RATE);
}
void CameraParameters::setPreviewFormat(const char *format)
{
- set("preview-format", format);
+ set(KEY_PREVIEW_FORMAT, format);
}
int CameraParameters::getOrientation() const
@@ -196,22 +293,22 @@
void CameraParameters::setOrientation(int orientation)
{
if (orientation == CAMERA_ORIENTATION_PORTRAIT) {
- set("preview-format", portrait);
+ set("orientation", portrait);
} else {
- set("preview-format", landscape);
+ set("orientation", landscape);
}
}
const char *CameraParameters::getPreviewFormat() const
{
- return get("preview-format");
+ return get(KEY_PREVIEW_FORMAT);
}
void CameraParameters::setPictureSize(int width, int height)
{
char str[32];
sprintf(str, "%dx%d", width, height);
- set("picture-size", str);
+ set(KEY_PICTURE_SIZE, str);
}
void CameraParameters::getPictureSize(int *width, int *height) const
@@ -220,7 +317,7 @@
*height = -1;
// Get the current string, if it doesn't exist, leave the -1x-1
- const char *p = get("picture-size");
+ const char *p = get(KEY_PICTURE_SIZE);
if (p == 0)
return;
@@ -233,12 +330,12 @@
void CameraParameters::setPictureFormat(const char *format)
{
- set("picture-format", format);
+ set(KEY_PICTURE_FORMAT, format);
}
const char *CameraParameters::getPictureFormat() const
{
- return get("picture-format");
+ return get(KEY_PICTURE_FORMAT);
}
void CameraParameters::dump() const
diff --git a/libs/ui/EGLDisplaySurface.cpp b/libs/ui/EGLDisplaySurface.cpp
deleted file mode 100644
index d06c98b..0000000
--- a/libs/ui/EGLDisplaySurface.cpp
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- **
- ** Copyright 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 "EGLDisplaySurface"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#include <cutils/log.h>
-#include <cutils/atomic.h>
-#include <cutils/properties.h>
-
-#include <hardware/copybit.h>
-
-#include <ui/SurfaceComposerClient.h>
-#include <ui/DisplayInfo.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
-#include <ui/EGLDisplaySurface.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/msm_mdp.h>
-#endif
-
-#include <EGL/egl.h>
-
-#include <pixelflinger/format.h>
-
-
-// ----------------------------------------------------------------------------
-
-egl_native_window_t* android_createDisplaySurface()
-{
- egl_native_window_t* s = new android::EGLDisplaySurface();
- s->memory_type = NATIVE_MEMORY_TYPE_GPU;
- return s;
-}
-
-#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
-#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-EGLDisplaySurface::EGLDisplaySurface()
- : EGLNativeSurface<EGLDisplaySurface>()
-{
- egl_native_window_t::version = sizeof(egl_native_window_t);
- egl_native_window_t::ident = 0;
- egl_native_window_t::incRef = &EGLDisplaySurface::hook_incRef;
- egl_native_window_t::decRef = &EGLDisplaySurface::hook_decRef;
- egl_native_window_t::swapBuffers = &EGLDisplaySurface::hook_swapBuffers;
- egl_native_window_t::connect = 0;
- egl_native_window_t::disconnect = 0;
-
- mFb[0].data = 0;
- mFb[1].data = 0;
- mBlitEngine = 0;
- egl_native_window_t::fd = mapFrameBuffer();
- if (egl_native_window_t::fd >= 0) {
-
- hw_module_t const* module;
- if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
- copybit_open(module, &mBlitEngine);
- }
-
- const float in2mm = 25.4f;
- float refreshRate = 1000000000000000LLU / (
- float( mInfo.upper_margin + mInfo.lower_margin + mInfo.yres )
- * ( mInfo.left_margin + mInfo.right_margin + mInfo.xres )
- * mInfo.pixclock);
-
- const GGLSurface& buffer = mFb[1 - mIndex];
- egl_native_window_t::width = buffer.width;
- egl_native_window_t::height = buffer.height;
- egl_native_window_t::stride = buffer.stride;
- egl_native_window_t::format = buffer.format;
- egl_native_window_t::base = intptr_t(mFb[0].data);
- egl_native_window_t::offset =
- intptr_t(buffer.data) - egl_native_window_t::base;
- egl_native_window_t::flags = 0;
- egl_native_window_t::xdpi = (mInfo.xres * in2mm) / mInfo.width;
- egl_native_window_t::ydpi = (mInfo.yres * in2mm) / mInfo.height;
- egl_native_window_t::fps = refreshRate;
- egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_FB;
- // no error, set the magic word
- egl_native_window_t::magic = 0x600913;
- }
- mSwapCount = -1;
- mPageFlipCount = 0;
-}
-
-EGLDisplaySurface::~EGLDisplaySurface()
-{
- magic = 0;
- copybit_close(mBlitEngine);
- mBlitEngine = 0;
- close(egl_native_window_t::fd);
- munmap(mFb[0].data, mSize);
- if (!(mFlags & PAGE_FLIP))
- free((void*)mFb[1].data);
-}
-
-void EGLDisplaySurface::hook_incRef(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- that->incStrong(that);
-}
-void EGLDisplaySurface::hook_decRef(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- that->decStrong(that);
-}
-uint32_t EGLDisplaySurface::hook_swapBuffers(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- return that->swapBuffers();
-}
-
-void EGLDisplaySurface::setSwapRectangle(int l, int t, int w, int h)
-{
- mInfo.reserved[0] = 0x54445055; // "UPDT";
- mInfo.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
- mInfo.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
-}
-
-uint32_t EGLDisplaySurface::swapBuffers()
-{
-#define SHOW_FPS 0
-#if SHOW_FPS
- nsecs_t now = systemTime();
- if (mSwapCount == -1) {
- mTime = now;
- mSwapCount = 0;
- mSleep = 0;
- } else {
- nsecs_t d = now-mTime;
- if (d >= seconds(1)) {
- double fps = (mSwapCount * double(seconds(1))) / double(d);
- LOGD("%f fps, sleep=%d / frame",
- fps, (int)ns2us(mSleep / mSwapCount));
- mSwapCount = 0;
- mTime = now;
- mSleep = 0;
- } else {
- mSwapCount++;
- }
- }
-#endif
- /* If we can't do the page_flip, just copy the back buffer to the front */
- if (!(mFlags & PAGE_FLIP)) {
- memcpy(mFb[0].data, mFb[1].data, mInfo.xres*mInfo.yres*2);
- return 0;
- }
-
- // do the actual flip
- mIndex = 1 - mIndex;
- mInfo.activate = FB_ACTIVATE_VBL;
- mInfo.yoffset = mIndex ? mInfo.yres : 0;
- if (ioctl(egl_native_window_t::fd, FBIOPUT_VSCREENINFO, &mInfo) == -1) {
- LOGE("FBIOPUT_VSCREENINFO failed");
- return 0;
- }
-
- /*
- * this is a monstrous hack: Because the h/w accelerator is not able
- * to render directly into the framebuffer, we need to copy its
- * internal framebuffer out to the fb.
- * oem[0] is used to access the fd of internal fb.
- * All this is needed only in standalone mode, in SurfaceFlinger mode
- * we control where the GPU renders.
- * We do this only if we have copybit, since this hack is needed only
- * with msm7k.
- */
- if (egl_native_window_t::memory_type == NATIVE_MEMORY_TYPE_GPU && oem[0] && mBlitEngine) {
- copybit_device_t *copybit = mBlitEngine;
- copybit_rect_t sdrect = { 0, 0,
- egl_native_window_t::width, egl_native_window_t::height };
- copybit_image_t dst = {
- egl_native_window_t::width,
- egl_native_window_t::height,
- egl_native_window_t::format,
- egl_native_window_t::offset,
- (void*)egl_native_window_t::base,
- egl_native_window_t::fd
- };
- copybit_image_t src = {
- egl_native_window_t::width,
- egl_native_window_t::height,
- egl_native_window_t::format, // XXX: use proper format
- egl_native_window_t::offset,
- (void*)egl_native_window_t::base, // XXX: use proper base
- egl_native_window_t::oem[0]
- };
- region_iterator it(Region(Rect(
- egl_native_window_t::width, egl_native_window_t::height)));
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
- copybit->stretch(copybit, &dst, &src, &sdrect, &sdrect, &it);
- }
-
- // update the address of the buffer to draw to next
- const GGLSurface& buffer = mFb[1 - mIndex];
- egl_native_window_t::offset =
- intptr_t(buffer.data) - egl_native_window_t::base;
-
-#if SHOW_FPS
- mSleep += systemTime()-now;
-#endif
-
- mPageFlipCount++;
-
- // We don't support screen-size changes for now
- return 0;
-}
-
-int32_t EGLDisplaySurface::getPageFlipCount() const
-{
- return mPageFlipCount;
-}
-
-void EGLDisplaySurface::copyFrontToBack(const Region& copyback)
-{
-#if HAVE_ANDROID_OS
- if (mBlitEngine) {
- copybit_image_t dst = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[1-mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- copybit_image_t src = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- region_iterator it(copyback);
- mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
- } else
-#endif
- {
- /* no extra copy needed since we copied back to front instead of
- * flipping */
- if (!(mFlags & PAGE_FLIP)) {
- return;
- }
-
- Region::iterator iterator(copyback);
- if (iterator) {
- Rect r;
- uint8_t* const screen_src = mFb[ mIndex].data;
- uint8_t* const screen_dst = mFb[1-mIndex].data;
- const size_t bpp = bytesPerPixel(egl_native_window_t::format);
- const size_t bpr = egl_native_window_t::stride * bpp;
- while (iterator.iterate(&r)) {
- ssize_t h = r.bottom - r.top;
- if (h) {
- size_t size = (r.right - r.left) * bpp;
- size_t o = (r.left + egl_native_window_t::stride * r.top) * bpp;
- uint8_t* s = screen_src + o;
- uint8_t* d = screen_dst + o;
- if (size == bpr) {
- size *= h;
- h = 1;
- }
- do {
- memcpy(d, s, size);
- d += bpr;
- s += bpr;
- } while (--h > 0);
- }
- }
- }
- }
-}
-
-void EGLDisplaySurface::copyFrontToImage(const copybit_image_t& dst)
-{
-#if HAVE_ANDROID_OS
- if (mBlitEngine) {
- copybit_image_t src = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- region_iterator it(Region(Rect(
- egl_native_window_t::width, egl_native_window_t::height)));
- mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
- } else
-#endif
- {
- uint8_t* const screen_src = mFb[ mIndex].data;
- const size_t bpp = bytesPerPixel(egl_native_window_t::format);
- const size_t bpr = egl_native_window_t::stride * bpp;
- memcpy((char*)dst.base + dst.offset, screen_src,
- bpr*egl_native_window_t::height);
- }
-}
-
-void EGLDisplaySurface::copyBackToImage(const copybit_image_t& dst)
-{
-#if HAVE_ANDROID_OS
- if (mBlitEngine) {
- copybit_image_t src = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[1-mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- region_iterator it(Region(Rect(
- egl_native_window_t::width, egl_native_window_t::height)));
- mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
- } else
-#endif
- {
- uint8_t* const screen_src = mFb[1-mIndex].data;
- const size_t bpp = bytesPerPixel(egl_native_window_t::format);
- const size_t bpr = egl_native_window_t::stride * bpp;
- memcpy((char*)dst.base + dst.offset, screen_src,
- bpr*egl_native_window_t::height);
- }
-}
-
-
-status_t EGLDisplaySurface::mapFrameBuffer()
-{
- char const * const device_template[] = {
- "/dev/graphics/fb%u",
- "/dev/fb%u",
- 0 };
- int fd = -1;
- int i=0;
- char name[64];
- while ((fd==-1) && device_template[i]) {
- snprintf(name, 64, device_template[i], 0);
- fd = open(name, O_RDWR, 0);
- i++;
- }
- if (fd < 0)
- return -errno;
-
- struct fb_fix_screeninfo finfo;
- if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
- return -errno;
-
- struct fb_var_screeninfo info;
- if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
- return -errno;
-
- info.reserved[0] = 0;
- info.reserved[1] = 0;
- info.reserved[2] = 0;
- info.xoffset = 0;
- info.yoffset = 0;
- info.yres_virtual = info.yres * 2;
- info.bits_per_pixel = 16;
- /* Explicitly request 5/6/5 */
- info.red.offset = 11;
- info.red.length = 5;
- info.green.offset = 5;
- info.green.length = 6;
- info.blue.offset = 0;
- info.blue.length = 5;
- info.transp.offset = 0;
- info.transp.length = 0;
- info.activate = FB_ACTIVATE_NOW;
-
- uint32_t flags = PAGE_FLIP;
- if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
- info.yres_virtual = info.yres;
- flags &= ~PAGE_FLIP;
- LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
- }
-
- if (info.yres_virtual < info.yres * 2) {
- info.yres_virtual = info.yres;
- flags &= ~PAGE_FLIP;
- LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
- info.yres_virtual, info.yres*2);
- }
-
- if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
- return -errno;
-
- int refreshRate = 1000000000000000LLU /
- (
- uint64_t( info.upper_margin + info.lower_margin + info.yres )
- * ( info.left_margin + info.right_margin + info.xres )
- * info.pixclock
- );
-
- if (refreshRate == 0) {
- // bleagh, bad info from the driver
- refreshRate = 60*1000; // 60 Hz
- }
- if (int(info.width) <= 0 || int(info.height) <= 0) {
- // the driver doesn't return that information
- // default to 160 dpi
- info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
- info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
- }
-
- float xdpi = (info.xres * 25.4f) / info.width;
- float ydpi = (info.yres * 25.4f) / info.height;
- float fps = refreshRate / 1000.0f;
-
- LOGI( "using (fd=%d)\n"
- "id = %s\n"
- "xres = %d px\n"
- "yres = %d px\n"
- "xres_virtual = %d px\n"
- "yres_virtual = %d px\n"
- "bpp = %d\n"
- "r = %2u:%u\n"
- "g = %2u:%u\n"
- "b = %2u:%u\n",
- fd,
- finfo.id,
- info.xres,
- info.yres,
- info.xres_virtual,
- info.yres_virtual,
- info.bits_per_pixel,
- info.red.offset, info.red.length,
- info.green.offset, info.green.length,
- info.blue.offset, info.blue.length
- );
-
- LOGI( "width = %d mm (%f dpi)\n"
- "height = %d mm (%f dpi)\n"
- "refresh rate = %.2f Hz\n",
- info.width, xdpi,
- info.height, ydpi,
- fps
- );
-
-
- if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
- return -errno;
-
- if (finfo.smem_len <= 0)
- return -errno;
-
- /*
- * Open and map the display.
- */
-
- void* buffer = (uint16_t*) mmap(
- 0, finfo.smem_len,
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- fd, 0);
-
- if (buffer == MAP_FAILED)
- return -errno;
-
- // at least for now, always clear the fb
- memset(buffer, 0, finfo.smem_len);
-
- uint8_t* offscreen[2];
- offscreen[0] = (uint8_t*)buffer;
- if (flags & PAGE_FLIP) {
- offscreen[1] = (uint8_t*)buffer + finfo.line_length*info.yres;
- } else {
- offscreen[1] = (uint8_t*)malloc(finfo.smem_len);
- if (offscreen[1] == 0) {
- munmap(buffer, finfo.smem_len);
- return NO_MEMORY;
- }
- }
-
- mFlags = flags;
- mInfo = info;
- mFinfo = finfo;
- mSize = finfo.smem_len;
- mIndex = 0;
- for (int i=0 ; i<2 ; i++) {
- mFb[i].version = sizeof(GGLSurface);
- mFb[i].width = info.xres;
- mFb[i].height = info.yres;
- mFb[i].stride = finfo.line_length / (info.bits_per_pixel >> 3);
- mFb[i].data = (GGLubyte*)(offscreen[i]);
- mFb[i].format = GGL_PIXEL_FORMAT_RGB_565;
- }
- return fd;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
diff --git a/libs/ui/EGLNativeWindowSurface.cpp b/libs/ui/EGLNativeWindowSurface.cpp
deleted file mode 100644
index f1071cf..0000000
--- a/libs/ui/EGLNativeWindowSurface.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
-**
-** Copyright 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 "EGLNativeWindowSurface"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <cutils/log.h>
-#include <cutils/atomic.h>
-
-#include <ui/SurfaceComposerClient.h>
-#include <ui/DisplayInfo.h>
-#include <ui/Rect.h>
-
-#include <EGL/egl.h>
-
-#include <pixelflinger/format.h>
-
-#include <ui/EGLNativeWindowSurface.h>
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-EGLNativeWindowSurface::EGLNativeWindowSurface(const sp<Surface>& surface)
- : EGLNativeSurface<EGLNativeWindowSurface>(),
- mSurface(surface), mConnected(false)
-{
- egl_native_window_t::magic = 0x600913;
- egl_native_window_t::version = sizeof(egl_native_window_t);
- egl_native_window_t::ident = 0;
- egl_native_window_t::incRef = &EGLNativeWindowSurface::hook_incRef;
- egl_native_window_t::decRef = &EGLNativeWindowSurface::hook_decRef;
- egl_native_window_t::swapBuffers = &EGLNativeWindowSurface::hook_swapBuffers;
- egl_native_window_t::connect = &EGLNativeWindowSurface::hook_connect;
- egl_native_window_t::disconnect = &EGLNativeWindowSurface::hook_disconnect;
-
- DisplayInfo dinfo;
- SurfaceComposerClient::getDisplayInfo(0, &dinfo);
- egl_native_window_t::xdpi = dinfo.xdpi;
- egl_native_window_t::ydpi = dinfo.ydpi;
- egl_native_window_t::fps = dinfo.fps;
- egl_native_window_t::flags= EGL_NATIVES_FLAG_DESTROY_BACKBUFFER;
-}
-
-EGLNativeWindowSurface::~EGLNativeWindowSurface()
-{
- disconnect();
- mSurface.clear();
- magic = 0;
-}
-
-void EGLNativeWindowSurface::hook_incRef(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->incStrong(that);
-}
-
-void EGLNativeWindowSurface::hook_decRef(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->decStrong(that);
-}
-
-void EGLNativeWindowSurface::hook_connect(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->connect();
-}
-
-void EGLNativeWindowSurface::hook_disconnect(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->disconnect();
-}
-
-uint32_t EGLNativeWindowSurface::hook_swapBuffers(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- return that->swapBuffers();
-}
-
-void EGLNativeWindowSurface::setSwapRectangle(int l, int t, int w, int h)
-{
- mSurface->setSwapRectangle(Rect(l, t, l+w, t+h));
-}
-
-uint32_t EGLNativeWindowSurface::swapBuffers()
-{
- const int w = egl_native_window_t::width;
- const int h = egl_native_window_t::height;
- const sp<Surface>& surface(mSurface);
- Surface::SurfaceInfo info;
- surface->unlockAndPost();
- surface->lock(&info);
- // update the address of the buffer to draw to next
- egl_native_window_t::base = intptr_t(info.base);
- egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
-
- // update size if it changed
- if (w != int(info.w) || h != int(info.h)) {
- egl_native_window_t::width = info.w;
- egl_native_window_t::height = info.h;
- egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format);
- egl_native_window_t::format = info.format;
- return EGL_NATIVES_FLAG_SIZE_CHANGED;
- }
- return 0;
-}
-
-void EGLNativeWindowSurface::connect()
-{
- if (!mConnected) {
- Surface::SurfaceInfo info;
- mSurface->lock(&info);
- mSurface->setSwapRectangle(Rect(info.w, info.h));
- mConnected = true;
-
- egl_native_window_t::width = info.w;
- egl_native_window_t::height = info.h;
- egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format);
- egl_native_window_t::format = info.format;
- egl_native_window_t::base = intptr_t(info.base);
- egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
- // FIXME: egl_native_window_t::memory_type used to be set from
- // mSurface, but we wanted to break this dependency. We set it to
- // GPU because the software rendered doesn't care, but the h/w
- // accelerator needs it. Eventually, this value should go away
- // completely, since memory will be managed by OpenGL.
- egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_GPU;
- egl_native_window_t::fd = 0;
- }
-}
-
-void EGLNativeWindowSurface::disconnect()
-{
- if (mConnected) {
- mSurface->unlock();
- mConnected = false;
- }
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
diff --git a/libs/ui/EGLUtils.cpp b/libs/ui/EGLUtils.cpp
new file mode 100644
index 0000000..1663313
--- /dev/null
+++ b/libs/ui/EGLUtils.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#define LOG_TAG "EGLUtils"
+
+#include <cutils/log.h>
+#include <utils/Errors.h>
+
+#include <ui/EGLUtils.h>
+
+#include <EGL/egl.h>
+
+#include <private/ui/android_natives_priv.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+const char *EGLUtils::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";
+ }
+}
+
+status_t EGLUtils::selectConfigForPixelFormat(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ PixelFormat format,
+ EGLConfig* outConfig)
+{
+ EGLint numConfigs = -1, n=0;
+
+ if (!attrs)
+ return BAD_VALUE;
+
+ if (outConfig == NULL)
+ return BAD_VALUE;
+
+ int err;
+ PixelFormatInfo fbFormatInfo;
+ if ((err = getPixelFormatInfo(PixelFormat(format), &fbFormatInfo)) < 0) {
+ return err;
+ }
+
+ // Get all the "potential match" configs...
+ if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE)
+ return BAD_VALUE;
+
+ EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);
+ if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {
+ free(configs);
+ return BAD_VALUE;
+ }
+
+ const int fbSzA = fbFormatInfo.getSize(PixelFormatInfo::INDEX_ALPHA);
+ const int fbSzR = fbFormatInfo.getSize(PixelFormatInfo::INDEX_RED);
+ const int fbSzG = fbFormatInfo.getSize(PixelFormatInfo::INDEX_GREEN);
+ const int fbSzB = fbFormatInfo.getSize(PixelFormatInfo::INDEX_BLUE);
+
+ int i;
+ EGLConfig config = NULL;
+ for (i=0 ; i<n ; i++) {
+ EGLint r,g,b,a;
+ EGLConfig curr = configs[i];
+ eglGetConfigAttrib(dpy, curr, EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(dpy, curr, EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(dpy, curr, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(dpy, curr, EGL_ALPHA_SIZE, &a);
+ if (fbSzA == a && fbSzR == r && fbSzG == g && fbSzB == b) {
+ config = curr;
+ break;
+ }
+ }
+
+ free(configs);
+
+ if (i<n) {
+ *outConfig = config;
+ return NO_ERROR;
+ }
+
+ return NAME_NOT_FOUND;
+}
+
+status_t EGLUtils::selectConfigForNativeWindow(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ EGLNativeWindowType window,
+ EGLConfig* outConfig)
+{
+ int err;
+ int format;
+
+ if (!window)
+ return BAD_VALUE;
+
+ if ((err = window->query(window, NATIVE_WINDOW_FORMAT, &format)) < 0) {
+ return err;
+ }
+
+ return selectConfigForPixelFormat(dpy, attrs, format, outConfig);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 7c2fc8e..e39a357 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -16,13 +16,14 @@
//#define LOG_NDEBUG 0
#include <ui/EventHub.h>
+#include <ui/KeycodeLabels.h>
#include <hardware_legacy/power.h>
#include <cutils/properties.h>
-#include <utils/IServiceManager.h>
#include <utils/Log.h>
#include <utils/Timers.h>
-#include <utils.h>
+#include <utils/threads.h>
+#include <utils/Errors.h>
#include <stdlib.h>
#include <stdio.h>
@@ -58,6 +59,18 @@
#define SEQ_SHIFT 16
#define id_to_index(id) ((id&ID_MASK)+1)
+#ifndef ABS_MT_TOUCH_MAJOR
+#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
+#endif
+
+#ifndef ABS_MT_POSITION_X
+#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */
+#endif
+
+#ifndef ABS_MT_POSITION_Y
+#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
+#endif
+
namespace android {
static const char *WAKE_LOCK_ID = "KeyEvents";
@@ -69,8 +82,8 @@
return (v1 > v2) ? v1 : v2;
}
-EventHub::device_t::device_t(int32_t _id, const char* _path)
- : id(_id), path(_path), classes(0)
+EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name)
+ : id(_id), path(_path), name(name), classes(0)
, keyBitmask(NULL), layoutMap(new KeyLayoutMap()), next(NULL) {
}
@@ -83,7 +96,7 @@
: mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(0)
, mDevicesById(0), mNumDevicesById(0)
, mOpeningDevices(0), mClosingDevices(0)
- , mDevices(0), mFDs(0), mFDCount(0)
+ , mDevices(0), mFDs(0), mFDCount(0), mOpened(false)
{
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
#ifdef EV_SW
@@ -100,11 +113,6 @@
// we should free stuff here...
}
-void EventHub::onFirstRef()
-{
- mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
-}
-
status_t EventHub::errorCheck() const
{
return mError;
@@ -239,6 +247,41 @@
return 0;
}
+status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode,
+ int32_t* outKeycode, uint32_t* outFlags) const
+{
+ AutoMutex _l(mLock);
+ device_t* device = getDevice(deviceId);
+
+ if (device != NULL && device->layoutMap != NULL) {
+ status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
+ if (err == NO_ERROR) {
+ return NO_ERROR;
+ }
+ }
+
+ if (mHaveFirstKeyboard) {
+ device = getDevice(mFirstKeyboardId);
+
+ if (device != NULL && device->layoutMap != NULL) {
+ status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
+ if (err == NO_ERROR) {
+ return NO_ERROR;
+ }
+ }
+ }
+
+ *outKeycode = 0;
+ *outFlags = 0;
+ return NAME_NOT_FOUND;
+}
+
+void EventHub::addExcludedDevice(const char* deviceName)
+{
+ String8 name(deviceName);
+ mExcludedDevices.push_back(name);
+}
+
EventHub::device_t* EventHub::getDevice(int32_t deviceId) const
{
if (deviceId == 0) deviceId = mFirstKeyboardId;
@@ -276,7 +319,12 @@
// Note that we only allow one caller to getEvent(), so don't need
// to do locking here... only when adding/removing devices.
-
+
+ if (!mOpened) {
+ mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
+ mOpened = true;
+ }
+
while(1) {
// First, report any devices that had last been added/removed.
@@ -474,6 +522,20 @@
//fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno));
name[0] = '\0';
}
+
+ // check to see if the device is on our excluded list
+ List<String8>::iterator iter = mExcludedDevices.begin();
+ List<String8>::iterator end = mExcludedDevices.end();
+ for ( ; iter != end; iter++) {
+ const char* test = *iter;
+ if (strcmp(name, test) == 0) {
+ LOGI("ignoring event id %s driver %s\n", deviceName, test);
+ close(fd);
+ fd = -1;
+ return -1;
+ }
+ }
+
if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
//fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno));
location[0] = '\0';
@@ -531,7 +593,7 @@
version >> 16, (version >> 8) & 0xff, version & 0xff);
#endif
- device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName);
+ device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name);
if (device == NULL) {
LOGE("out of memory");
return -1;
@@ -541,6 +603,8 @@
mFDs[mFDCount].events = POLLIN;
// figure out the kinds of events the device reports
+
+ // See if this is a keyboard, and classify it.
uint8_t key_bitmask[(KEY_MAX+1)/8];
memset(key_bitmask, 0, sizeof(key_bitmask));
LOGV("Getting keys...");
@@ -552,15 +616,11 @@
for (int i=0; i<((BTN_MISC+7)/8); i++) {
if (key_bitmask[i] != 0) {
device->classes |= CLASS_KEYBOARD;
- // 'Q' key support = cheap test of whether this is an alpha-capable kbd
- if (test_bit(KEY_Q, key_bitmask)) {
- device->classes |= CLASS_ALPHAKEY;
- }
break;
}
}
if ((device->classes & CLASS_KEYBOARD) != 0) {
- device->keyBitmask = new uint8_t[(KEY_MAX+1)/8];
+ device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
if (device->keyBitmask != NULL) {
memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
} else {
@@ -570,6 +630,8 @@
}
}
}
+
+ // See if this is a trackball.
if (test_bit(BTN_MOUSE, key_bitmask)) {
uint8_t rel_bitmask[(REL_MAX+1)/8];
memset(rel_bitmask, 0, sizeof(rel_bitmask));
@@ -581,16 +643,22 @@
}
}
}
- if (test_bit(BTN_TOUCH, key_bitmask)) {
- uint8_t abs_bitmask[(ABS_MAX+1)/8];
- memset(abs_bitmask, 0, sizeof(abs_bitmask));
- LOGV("Getting absolute controllers...");
- if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0)
- {
- if (test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
- device->classes |= CLASS_TOUCHSCREEN;
- }
- }
+
+ uint8_t abs_bitmask[(ABS_MAX+1)/8];
+ memset(abs_bitmask, 0, sizeof(abs_bitmask));
+ LOGV("Getting absolute controllers...");
+ ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask);
+
+ // Is this a new modern multi-touch driver?
+ if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)
+ && test_bit(ABS_MT_POSITION_X, abs_bitmask)
+ && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
+ device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT;
+
+ // Is this an old style single-touch driver?
+ } else if (test_bit(BTN_TOUCH, key_bitmask)
+ && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
+ device->classes |= CLASS_TOUCHSCREEN;
}
#ifdef EV_SW
@@ -609,21 +677,15 @@
}
#endif
- LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
- deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
-
if ((device->classes&CLASS_KEYBOARD) != 0) {
- char devname[101];
- char tmpfn[101];
+ char tmpfn[sizeof(name)];
char keylayoutFilename[300];
// a more descriptive name
- ioctl(mFDs[mFDCount].fd, EVIOCGNAME(sizeof(devname)-1), devname);
- devname[sizeof(devname)-1] = 0;
- device->name = devname;
+ device->name = name;
// replace all the spaces with underscores
- strcpy(tmpfn, devname);
+ strcpy(tmpfn, name);
for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
*p = '_';
@@ -656,12 +718,29 @@
}
char propName[100];
sprintf(propName, "hw.keyboards.%u.devname", publicID);
- property_set(propName, devname);
+ property_set(propName, name);
- LOGI("New keyboard: publicID=%d device->id=%d devname='%s' propName='%s' keylayout='%s'\n",
- publicID, device->id, devname, propName, keylayoutFilename);
+ // 'Q' key support = cheap test of whether this is an alpha-capable kbd
+ if (hasKeycode(device, kKeyCodeQ)) {
+ device->classes |= CLASS_ALPHAKEY;
+ }
+
+ // See if this has a DPAD.
+ if (hasKeycode(device, kKeyCodeDpadUp) &&
+ hasKeycode(device, kKeyCodeDpadDown) &&
+ hasKeycode(device, kKeyCodeDpadLeft) &&
+ hasKeycode(device, kKeyCodeDpadRight) &&
+ hasKeycode(device, kKeyCodeDpadCenter)) {
+ device->classes |= CLASS_DPAD;
+ }
+
+ LOGI("New keyboard: publicID=%d device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
+ publicID, device->id, name, propName, keylayoutFilename);
}
+ LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
+ deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
+
LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n",
deviceName, device, mFDCount, devid, device->classes);
@@ -674,6 +753,25 @@
return 0;
}
+bool EventHub::hasKeycode(device_t* device, int keycode) const
+{
+ if (device->keyBitmask == NULL || device->layoutMap == NULL) {
+ return false;
+ }
+
+ Vector<int32_t> scanCodes;
+ device->layoutMap->findScancodes(keycode, &scanCodes);
+ const size_t N = scanCodes.size();
+ for (size_t i=0; i<N && i<=KEY_MAX; i++) {
+ int32_t sc = scanCodes.itemAt(i);
+ if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
int EventHub::close_device(const char *deviceName)
{
AutoMutex _l(mLock);
@@ -683,11 +781,21 @@
if(strcmp(mDevices[i]->path.string(), deviceName) == 0) {
//LOGD("remove device %d: %s\n", i, deviceName);
device_t* device = mDevices[i];
- int count = mFDCount - i - 1;
+
+ LOGI("Removed device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
+ device->path.string(), device->name.string(), device->id,
+ mNumDevicesById, mFDCount, mFDs[i].fd, device->classes);
+
+ // Clear this device's entry.
int index = (device->id&ID_MASK);
mDevicesById[index].device = NULL;
+
+ // Close the file descriptor and compact the fd array.
+ close(mFDs[i].fd);
+ int count = mFDCount - i - 1;
memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count);
memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count);
+ mFDCount--;
#ifdef EV_SW
for (int j=0; j<EV_SW; j++) {
@@ -700,8 +808,6 @@
device->next = mClosingDevices;
mClosingDevices = device;
- mFDCount--;
-
uint32_t publicID;
if (device->id == mFirstKeyboardId) {
LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
@@ -718,7 +824,7 @@
return 0;
}
}
- LOGE("remote device: %s not found\n", deviceName);
+ LOGE("remove device: %s not found\n", deviceName);
return -1;
}
@@ -733,6 +839,7 @@
int event_pos = 0;
struct inotify_event *event;
+ LOGV("EventHub::read_notify nfd: %d\n", nfd);
res = read(nfd, event_buf, sizeof(event_buf));
if(res < (int)sizeof(*event)) {
if(errno == EINTR)
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
new file mode 100644
index 0000000..0efba9c
--- /dev/null
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -0,0 +1,279 @@
+/*
+**
+** Copyright 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 "FramebufferNativeWindow"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <utils/threads.h>
+#include <utils/RefBase.h>
+
+#include <ui/SurfaceComposerClient.h>
+#include <ui/Rect.h>
+#include <ui/FramebufferNativeWindow.h>
+
+#include <EGL/egl.h>
+
+#include <pixelflinger/format.h>
+#include <pixelflinger/pixelflinger.h>
+
+#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
+
+#include <private/ui/android_natives_priv.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+class NativeBuffer
+ : public EGLNativeBase<
+ android_native_buffer_t,
+ NativeBuffer,
+ LightRefBase<NativeBuffer> >
+{
+public:
+ NativeBuffer(int w, int h, int f, int u) : BASE() {
+ android_native_buffer_t::width = w;
+ android_native_buffer_t::height = h;
+ android_native_buffer_t::format = f;
+ android_native_buffer_t::usage = u;
+ }
+private:
+ friend class LightRefBase<NativeBuffer>;
+ ~NativeBuffer() { }; // this class cannot be overloaded
+};
+
+
+/*
+ * This implements the (main) framebuffer management. This class is used
+ * mostly by SurfaceFlinger, but also by command line GL application.
+ *
+ * In fact this is an implementation of android_native_window_t on top of
+ * the framebuffer.
+ *
+ * Currently it is pretty simple, it manages only two buffers (the front and
+ * back buffer).
+ *
+ */
+
+FramebufferNativeWindow::FramebufferNativeWindow()
+ : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
+{
+ hw_module_t const* module;
+ if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
+ int stride;
+ int err;
+ err = framebuffer_open(module, &fbDev);
+ LOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
+
+ err = gralloc_open(module, &grDev);
+ LOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
+
+ // bail out if we can't initialize the modules
+ if (!fbDev || !grDev)
+ return;
+
+ mUpdateOnDemand = (fbDev->setUpdateRect != 0);
+
+ // initialize the buffer FIFO
+ mNumBuffers = 2;
+ mNumFreeBuffers = 2;
+ mBufferHead = mNumBuffers-1;
+ buffers[0] = new NativeBuffer(
+ fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
+ buffers[1] = new NativeBuffer(
+ fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
+
+ err = grDev->alloc(grDev,
+ fbDev->width, fbDev->height, fbDev->format,
+ GRALLOC_USAGE_HW_FB, &buffers[0]->handle, &buffers[0]->stride);
+
+ LOGE_IF(err, "fb buffer 0 allocation failed w=%d, h=%d, err=%s",
+ fbDev->width, fbDev->height, strerror(-err));
+
+ err = grDev->alloc(grDev,
+ fbDev->width, fbDev->height, fbDev->format,
+ GRALLOC_USAGE_HW_FB, &buffers[1]->handle, &buffers[1]->stride);
+
+ LOGE_IF(err, "fb buffer 1 allocation failed w=%d, h=%d, err=%s",
+ fbDev->width, fbDev->height, strerror(-err));
+
+ LOGE("xDpi %d", fbDev->xdpi);
+ LOGE("yDpi %d", fbDev->ydpi);
+ const_cast<uint32_t&>(android_native_window_t::flags) = fbDev->flags;
+ const_cast<float&>(android_native_window_t::xdpi) = fbDev->xdpi;
+ const_cast<float&>(android_native_window_t::ydpi) = fbDev->ydpi;
+ const_cast<int&>(android_native_window_t::minSwapInterval) =
+ fbDev->minSwapInterval;
+ const_cast<int&>(android_native_window_t::maxSwapInterval) =
+ fbDev->maxSwapInterval;
+ } else {
+ LOGE("Couldn't get gralloc module");
+ }
+
+ android_native_window_t::setSwapInterval = setSwapInterval;
+ android_native_window_t::dequeueBuffer = dequeueBuffer;
+ android_native_window_t::lockBuffer = lockBuffer;
+ android_native_window_t::queueBuffer = queueBuffer;
+ android_native_window_t::query = query;
+ android_native_window_t::perform = perform;
+}
+
+FramebufferNativeWindow::~FramebufferNativeWindow()
+{
+ if (grDev) {
+ if (buffers[0] != NULL)
+ grDev->free(grDev, buffers[0]->handle);
+ if (buffers[1] != NULL)
+ grDev->free(grDev, buffers[1]->handle);
+ gralloc_close(grDev);
+ }
+
+ if (fbDev) {
+ framebuffer_close(fbDev);
+ }
+}
+
+status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r)
+{
+ if (!mUpdateOnDemand) {
+ return INVALID_OPERATION;
+ }
+ return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height());
+}
+
+status_t FramebufferNativeWindow::compositionComplete()
+{
+ if (fbDev->compositionComplete) {
+ return fbDev->compositionComplete(fbDev);
+ }
+ return INVALID_OPERATION;
+}
+
+int FramebufferNativeWindow::setSwapInterval(
+ android_native_window_t* window, int interval)
+{
+ framebuffer_device_t* fb = getSelf(window)->fbDev;
+ return fb->setSwapInterval(fb, interval);
+}
+
+int FramebufferNativeWindow::dequeueBuffer(android_native_window_t* window,
+ android_native_buffer_t** buffer)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+ framebuffer_device_t* fb = self->fbDev;
+
+ // wait for a free buffer
+ while (!self->mNumFreeBuffers) {
+ self->mCondition.wait(self->mutex);
+ }
+ // get this buffer
+ self->mNumFreeBuffers--;
+ int index = self->mBufferHead++;
+ if (self->mBufferHead >= self->mNumBuffers)
+ self->mBufferHead = 0;
+
+ *buffer = self->buffers[index].get();
+
+ return 0;
+}
+
+int FramebufferNativeWindow::lockBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+
+ // wait that the buffer we're locking is not front anymore
+ while (self->front == buffer) {
+ self->mCondition.wait(self->mutex);
+ }
+
+ return NO_ERROR;
+}
+
+int FramebufferNativeWindow::queueBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+ framebuffer_device_t* fb = self->fbDev;
+ buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle;
+ int res = fb->post(fb, handle);
+ self->front = static_cast<NativeBuffer*>(buffer);
+ self->mNumFreeBuffers++;
+ self->mCondition.broadcast();
+ return res;
+}
+
+int FramebufferNativeWindow::query(android_native_window_t* window,
+ int what, int* value)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+ framebuffer_device_t* fb = self->fbDev;
+ switch (what) {
+ case NATIVE_WINDOW_WIDTH:
+ *value = fb->width;
+ return NO_ERROR;
+ case NATIVE_WINDOW_HEIGHT:
+ *value = fb->height;
+ return NO_ERROR;
+ case NATIVE_WINDOW_FORMAT:
+ *value = fb->format;
+ return NO_ERROR;
+ }
+ *value = 0;
+ return BAD_VALUE;
+}
+
+int FramebufferNativeWindow::perform(android_native_window_t* window,
+ int operation, ...)
+{
+ switch (operation) {
+ case NATIVE_WINDOW_SET_USAGE:
+ break;
+ default:
+ return NAME_NOT_FOUND;
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+EGLNativeWindowType android_createDisplaySurface(void)
+{
+ FramebufferNativeWindow* w;
+ w = new FramebufferNativeWindow();
+ if (w->getDevice() == NULL) {
+ // get a ref so it can be destroyed when we exit this block
+ sp<FramebufferNativeWindow> ref(w);
+ return NULL;
+ }
+ return (EGLNativeWindowType)w;
+}
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
new file mode 100644
index 0000000..6a5c8a9
--- /dev/null
+++ b/libs/ui/GraphicBuffer.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+#include <ui/PixelFormat.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+namespace android {
+
+// ===========================================================================
+// Buffer and implementation of android_native_buffer_t
+// ===========================================================================
+
+GraphicBuffer::GraphicBuffer()
+ : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
+ mInitCheck(NO_ERROR), mVStride(0), mIndex(-1)
+{
+ width =
+ height =
+ stride =
+ format =
+ usage = 0;
+ handle = NULL;
+}
+
+GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat reqFormat, uint32_t reqUsage)
+ : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
+ mInitCheck(NO_ERROR), mVStride(0), mIndex(-1)
+{
+ width =
+ height =
+ stride =
+ format =
+ usage = 0;
+ handle = NULL;
+ mInitCheck = initSize(w, h, reqFormat, reqUsage);
+}
+
+GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat inFormat, uint32_t inUsage,
+ uint32_t inStride, native_handle_t* inHandle, bool keepOwnership)
+ : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
+ mBufferMapper(GraphicBufferMapper::get()),
+ mInitCheck(NO_ERROR), mVStride(0), mIndex(-1)
+{
+ width = w;
+ height = h;
+ stride = inStride;
+ format = inFormat;
+ usage = inUsage;
+ handle = inHandle;
+}
+
+GraphicBuffer::GraphicBuffer(const Parcel& data)
+ : BASE(), mOwner(ownHandle), mBufferMapper(GraphicBufferMapper::get()),
+ mInitCheck(NO_ERROR), mVStride(0), mIndex(-1)
+{
+ // we own the handle in this case
+ width = data.readInt32();
+ if (width < 0) {
+ width = height = stride = format = usage = 0;
+ handle = 0;
+ } else {
+ height = data.readInt32();
+ stride = data.readInt32();
+ format = data.readInt32();
+ usage = data.readInt32();
+ handle = data.readNativeHandle();
+ }
+}
+
+GraphicBuffer::~GraphicBuffer()
+{
+ if (handle) {
+ if (mOwner == ownHandle) {
+ native_handle_close(handle);
+ native_handle_delete(const_cast<native_handle*>(handle));
+ } else if (mOwner == ownData) {
+ GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
+ allocator.free(handle);
+ }
+ }
+}
+
+status_t GraphicBuffer::initCheck() const {
+ return mInitCheck;
+}
+
+android_native_buffer_t* GraphicBuffer::getNativeBuffer() const
+{
+ return static_cast<android_native_buffer_t*>(
+ const_cast<GraphicBuffer*>(this));
+}
+
+status_t GraphicBuffer::reallocate(uint32_t w, uint32_t h, PixelFormat f,
+ uint32_t reqUsage)
+{
+ if (mOwner != ownData)
+ return INVALID_OPERATION;
+
+ if (handle) {
+ GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
+ allocator.free(handle);
+ handle = 0;
+ }
+ return initSize(w, h, f, reqUsage);
+}
+
+status_t GraphicBuffer::initSize(uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t reqUsage)
+{
+ if (format == PIXEL_FORMAT_RGBX_8888)
+ format = PIXEL_FORMAT_RGBA_8888;
+
+ GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
+ status_t err = allocator.alloc(w, h, format, reqUsage, &handle, &stride);
+ if (err == NO_ERROR) {
+ this->width = w;
+ this->height = h;
+ this->format = format;
+ this->usage = reqUsage;
+ mVStride = 0;
+ }
+ return err;
+}
+
+status_t GraphicBuffer::lock(uint32_t usage, void** vaddr)
+{
+ const Rect lockBounds(width, height);
+ status_t res = lock(usage, lockBounds, vaddr);
+ return res;
+}
+
+status_t GraphicBuffer::lock(uint32_t usage, const Rect& rect, void** vaddr)
+{
+ if (rect.left < 0 || rect.right > this->width ||
+ rect.top < 0 || rect.bottom > this->height) {
+ LOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
+ rect.left, rect.top, rect.right, rect.bottom,
+ this->width, this->height);
+ return BAD_VALUE;
+ }
+ status_t res = getBufferMapper().lock(handle, usage, rect, vaddr);
+ return res;
+}
+
+status_t GraphicBuffer::unlock()
+{
+ status_t res = getBufferMapper().unlock(handle);
+ return res;
+}
+
+status_t GraphicBuffer::lock(GGLSurface* sur, uint32_t usage)
+{
+ void* vaddr;
+ status_t res = GraphicBuffer::lock(usage, &vaddr);
+ if (res == NO_ERROR && sur) {
+ sur->version = sizeof(GGLSurface);
+ sur->width = width;
+ sur->height = height;
+ sur->stride = stride;
+ sur->format = format;
+ sur->vstride = mVStride;
+ sur->data = static_cast<GGLubyte*>(vaddr);
+ }
+ return res;
+}
+
+
+status_t GraphicBuffer::writeToParcel(Parcel* reply,
+ android_native_buffer_t const* buffer)
+{
+ if (buffer == NULL)
+ return BAD_VALUE;
+
+ if (buffer->width < 0 || buffer->height < 0)
+ return BAD_VALUE;
+
+ status_t err = NO_ERROR;
+ if (buffer->handle == NULL) {
+ // this buffer doesn't have a handle
+ reply->writeInt32(NO_MEMORY);
+ } else {
+ reply->writeInt32(buffer->width);
+ reply->writeInt32(buffer->height);
+ reply->writeInt32(buffer->stride);
+ reply->writeInt32(buffer->format);
+ reply->writeInt32(buffer->usage);
+ err = reply->writeNativeHandle(buffer->handle);
+ }
+ return err;
+}
+
+
+void GraphicBuffer::setIndex(int index) {
+ mIndex = index;
+}
+
+int GraphicBuffer::getIndex() const {
+ return mIndex;
+}
+
+void GraphicBuffer::setVerticalStride(uint32_t vstride) {
+ mVStride = vstride;
+}
+
+uint32_t GraphicBuffer::getVerticalStride() const {
+ return mVStride;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
new file mode 100644
index 0000000..57d5fc3
--- /dev/null
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -0,0 +1,141 @@
+/*
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <cutils/log.h>
+
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+
+#include <ui/GraphicBufferAllocator.h>
+
+#include <private/ui/sw_gralloc_handle.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferAllocator )
+
+Mutex GraphicBufferAllocator::sLock;
+KeyedVector<buffer_handle_t,
+ GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList;
+
+GraphicBufferAllocator::GraphicBufferAllocator()
+ : mAllocDev(0)
+{
+ hw_module_t const* module;
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
+ if (err == 0) {
+ gralloc_open(module, &mAllocDev);
+ }
+}
+
+GraphicBufferAllocator::~GraphicBufferAllocator()
+{
+ gralloc_close(mAllocDev);
+}
+
+void GraphicBufferAllocator::dump(String8& result) const
+{
+ Mutex::Autolock _l(sLock);
+ KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ size_t total = 0;
+ const size_t SIZE = 512;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, "Allocated buffers:\n");
+ result.append(buffer);
+ const size_t c = list.size();
+ for (size_t i=0 ; i<c ; i++) {
+ const alloc_rec_t& rec(list.valueAt(i));
+ snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u x %4u | %2d | 0x%08x\n",
+ list.keyAt(i), rec.size/1024.0f,
+ rec.w, rec.h, rec.format, rec.usage);
+ result.append(buffer);
+ total += rec.size;
+ }
+ snprintf(buffer, SIZE, "Total allocated: %.2f KB\n", total/1024.0f);
+ result.append(buffer);
+}
+
+static inline uint32_t clamp(uint32_t c) {
+ return c>0 ? c : 1;
+}
+
+status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
+ int usage, buffer_handle_t* handle, int32_t* stride)
+{
+ Mutex::Autolock _l(mLock);
+
+ // make sure to not allocate a 0 x 0 buffer
+ w = clamp(w);
+ h = clamp(h);
+
+ // we have a h/w allocator and h/w buffer is requested
+ status_t err;
+
+ if (usage & GRALLOC_USAGE_HW_MASK) {
+ err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
+ } else {
+ err = sw_gralloc_handle_t::alloc(w, h, format, usage, handle, stride);
+ }
+
+ LOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
+ w, h, format, usage, err, strerror(-err));
+
+ if (err == NO_ERROR) {
+ Mutex::Autolock _l(sLock);
+ KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ alloc_rec_t rec;
+ rec.w = w;
+ rec.h = h;
+ rec.format = format;
+ rec.usage = usage;
+ rec.vaddr = 0;
+ rec.size = h * stride[0] * bytesPerPixel(format);
+ list.add(*handle, rec);
+ } else {
+ String8 s;
+ dump(s);
+ LOGD("%s", s.string());
+ }
+
+ return err;
+}
+
+status_t GraphicBufferAllocator::free(buffer_handle_t handle)
+{
+ Mutex::Autolock _l(mLock);
+
+ status_t err;
+ if (sw_gralloc_handle_t::validate(handle) < 0) {
+ err = mAllocDev->free(mAllocDev, handle);
+ } else {
+ err = sw_gralloc_handle_t::free((sw_gralloc_handle_t*)handle);
+ }
+
+ LOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err));
+ if (err == NO_ERROR) {
+ Mutex::Autolock _l(sLock);
+ KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ list.removeItem(handle);
+ }
+
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
new file mode 100644
index 0000000..ce2acd0
--- /dev/null
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -0,0 +1,228 @@
+/*
+ * 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 "GraphicBufferMapper"
+
+#include <stdint.h>
+#ifdef HAVE_ANDROID_OS // just want PAGE_SIZE define
+# include <asm/page.h>
+#else
+# include <sys/user.h>
+#endif
+#include <errno.h>
+#include <sys/mman.h>
+
+#include <cutils/ashmem.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/GraphicBufferMapper.h>
+#include <ui/Rect.h>
+
+#include <hardware/gralloc.h>
+
+#include <private/ui/sw_gralloc_handle.h>
+
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
+
+GraphicBufferMapper::GraphicBufferMapper()
+ : mAllocMod(0)
+{
+ hw_module_t const* module;
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
+ if (err == 0) {
+ mAllocMod = (gralloc_module_t const *)module;
+ }
+}
+
+status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle)
+{
+ status_t err;
+ if (sw_gralloc_handle_t::validate(handle) < 0) {
+ err = mAllocMod->registerBuffer(mAllocMod, handle);
+ } else {
+ err = sw_gralloc_handle_t::registerBuffer((sw_gralloc_handle_t*)handle);
+ }
+ LOGW_IF(err, "registerBuffer(%p) failed %d (%s)",
+ handle, err, strerror(-err));
+ return err;
+}
+
+status_t GraphicBufferMapper::unregisterBuffer(buffer_handle_t handle)
+{
+ status_t err;
+ if (sw_gralloc_handle_t::validate(handle) < 0) {
+ err = mAllocMod->unregisterBuffer(mAllocMod, handle);
+ } else {
+ err = sw_gralloc_handle_t::unregisterBuffer((sw_gralloc_handle_t*)handle);
+ }
+ LOGW_IF(err, "unregisterBuffer(%p) failed %d (%s)",
+ handle, err, strerror(-err));
+ return err;
+}
+
+status_t GraphicBufferMapper::lock(buffer_handle_t handle,
+ int usage, const Rect& bounds, void** vaddr)
+{
+ status_t err;
+ if (sw_gralloc_handle_t::validate(handle) < 0) {
+ err = mAllocMod->lock(mAllocMod, handle, usage,
+ bounds.left, bounds.top, bounds.width(), bounds.height(),
+ vaddr);
+ } else {
+ err = sw_gralloc_handle_t::lock((sw_gralloc_handle_t*)handle, usage,
+ bounds.left, bounds.top, bounds.width(), bounds.height(),
+ vaddr);
+ }
+ LOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
+ return err;
+}
+
+status_t GraphicBufferMapper::unlock(buffer_handle_t handle)
+{
+ status_t err;
+ if (sw_gralloc_handle_t::validate(handle) < 0) {
+ err = mAllocMod->unlock(mAllocMod, handle);
+ } else {
+ err = sw_gralloc_handle_t::unlock((sw_gralloc_handle_t*)handle);
+ }
+ LOGW_IF(err, "unlock(...) failed %d (%s)", err, strerror(-err));
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+
+status_t sw_gralloc_handle_t::alloc(uint32_t w, uint32_t h, int format,
+ int usage, buffer_handle_t* pHandle, int32_t* pStride)
+{
+ int align = 4;
+ int bpp = 0;
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ bpp = 4;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ bpp = 3;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_RGBA_5551:
+ case HAL_PIXEL_FORMAT_RGBA_4444:
+ bpp = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+ size_t bpr = (w*bpp + (align-1)) & ~(align-1);
+ size_t size = bpr * h;
+ size_t stride = bpr / bpp;
+ size = (size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
+
+ int fd = ashmem_create_region("sw-gralloc-buffer", size);
+ if (fd < 0) {
+ LOGE("ashmem_create_region(size=%d) failed (%s)",
+ size, strerror(-errno));
+ return -errno;
+ }
+
+ int prot = PROT_READ;
+ if (usage & GRALLOC_USAGE_SW_WRITE_MASK)
+ prot |= PROT_WRITE;
+
+ if (ashmem_set_prot_region(fd, prot) < 0) {
+ LOGE("ashmem_set_prot_region(fd=%d, prot=%x) failed (%s)",
+ fd, prot, strerror(-errno));
+ close(fd);
+ return -errno;
+ }
+
+ void* base = mmap(0, size, prot, MAP_SHARED, fd, 0);
+ if (base == MAP_FAILED) {
+ LOGE("alloc mmap(fd=%d, size=%d, prot=%x) failed (%s)",
+ fd, size, prot, strerror(-errno));
+ close(fd);
+ return -errno;
+ }
+
+ sw_gralloc_handle_t* hnd = new sw_gralloc_handle_t();
+ hnd->fd = fd;
+ hnd->size = size;
+ hnd->base = intptr_t(base);
+ hnd->prot = prot;
+ *pStride = stride;
+ *pHandle = hnd;
+
+ return NO_ERROR;
+}
+
+status_t sw_gralloc_handle_t::free(sw_gralloc_handle_t* hnd)
+{
+ if (hnd->base) {
+ munmap((void*)hnd->base, hnd->size);
+ }
+ if (hnd->fd >= 0) {
+ close(hnd->fd);
+ }
+ delete hnd;
+ return NO_ERROR;
+}
+
+status_t sw_gralloc_handle_t::registerBuffer(sw_gralloc_handle_t* hnd)
+{
+ if (hnd->pid != getpid()) {
+ void* base = mmap(0, hnd->size, hnd->prot, MAP_SHARED, hnd->fd, 0);
+ if (base == MAP_FAILED) {
+ LOGE("registerBuffer mmap(fd=%d, size=%d, prot=%x) failed (%s)",
+ hnd->fd, hnd->size, hnd->prot, strerror(-errno));
+ return -errno;
+ }
+ hnd->base = intptr_t(base);
+ }
+ return NO_ERROR;
+}
+
+status_t sw_gralloc_handle_t::unregisterBuffer(sw_gralloc_handle_t* hnd)
+{
+ if (hnd->pid != getpid()) {
+ if (hnd->base) {
+ munmap((void*)hnd->base, hnd->size);
+ }
+ hnd->base = 0;
+ }
+ return NO_ERROR;
+}
+
+status_t sw_gralloc_handle_t::lock(sw_gralloc_handle_t* hnd, int usage,
+ int l, int t, int w, int h, void** vaddr)
+{
+ *vaddr = (void*)hnd->base;
+ return NO_ERROR;
+}
+
+status_t sw_gralloc_handle_t::unlock(sw_gralloc_handle_t* hnd)
+{
+ return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
index ab0fef1..e1b3ec7 100644
--- a/libs/ui/ICamera.cpp
+++ b/libs/ui/ICamera.cpp
@@ -20,7 +20,7 @@
#include <utils/Log.h>
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <ui/ICamera.h>
namespace android {
@@ -32,9 +32,11 @@
START_PREVIEW,
STOP_PREVIEW,
AUTO_FOCUS,
+ CANCEL_AUTO_FOCUS,
TAKE_PICTURE,
SET_PARAMETERS,
GET_PARAMETERS,
+ SEND_COMMAND,
CONNECT,
LOCK,
UNLOCK,
@@ -162,6 +164,17 @@
return ret;
}
+ // cancel focus
+ status_t cancelAutoFocus()
+ {
+ LOGV("cancelAutoFocus");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ remote()->transact(CANCEL_AUTO_FOCUS, data, &reply);
+ status_t ret = reply.readInt32();
+ return ret;
+ }
+
// take a picture - returns an IMemory (ref-counted mmap)
status_t takePicture()
{
@@ -193,6 +206,17 @@
remote()->transact(GET_PARAMETERS, data, &reply);
return reply.readString8();
}
+ virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
+ {
+ LOGD("sendCommand");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ data.writeInt32(cmd);
+ data.writeInt32(arg1);
+ data.writeInt32(arg2);
+ remote()->transact(SEND_COMMAND, data, &reply);
+ return reply.readInt32();
+ }
virtual status_t connect(const sp<ICameraClient>& cameraClient)
{
Parcel data, reply;
@@ -221,12 +245,6 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnCamera::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -300,6 +318,12 @@
reply->writeInt32(autoFocus());
return NO_ERROR;
} break;
+ case CANCEL_AUTO_FOCUS: {
+ LOGV("CANCEL_AUTO_FOCUS");
+ CHECK_INTERFACE(ICamera, data, reply);
+ reply->writeInt32(cancelAutoFocus());
+ return NO_ERROR;
+ } break;
case TAKE_PICTURE: {
LOGV("TAKE_PICTURE");
CHECK_INTERFACE(ICamera, data, reply);
@@ -319,6 +343,15 @@
reply->writeString8(getParameters());
return NO_ERROR;
} break;
+ case SEND_COMMAND: {
+ LOGD("SEND_COMMAND");
+ CHECK_INTERFACE(ICamera, data, reply);
+ int command = data.readInt32();
+ int arg1 = data.readInt32();
+ int arg2 = data.readInt32();
+ reply->writeInt32(sendCommand(command, arg1, arg2));
+ return NO_ERROR;
+ } break;
case CONNECT: {
CHECK_INTERFACE(ICamera, data, reply);
sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder());
diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp
index 59a6cf2..42b4da4 100644
--- a/libs/ui/ICameraClient.cpp
+++ b/libs/ui/ICameraClient.cpp
@@ -78,12 +78,6 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnCameraClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/ICameraService.cpp b/libs/ui/ICameraService.cpp
index e5687fe..84986c6 100644
--- a/libs/ui/ICameraService.cpp
+++ b/libs/ui/ICameraService.cpp
@@ -18,9 +18,9 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <ui/ICameraService.h>
@@ -49,12 +49,6 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnCameraService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/IOverlay.cpp b/libs/ui/IOverlay.cpp
index fed47c2..65e6b4f 100644
--- a/libs/ui/IOverlay.cpp
+++ b/libs/ui/IOverlay.cpp
@@ -18,8 +18,8 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/IInterface.h>
#include <ui/IOverlay.h>
@@ -49,12 +49,6 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnOverlay::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp
index d5e9f81..4fb38ed 100644
--- a/libs/ui/ISurface.cpp
+++ b/libs/ui/ISurface.cpp
@@ -14,19 +14,25 @@
* limitations under the License.
*/
+#define LOG_TAG "ISurface"
+
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
#include <ui/ISurface.h>
#include <ui/Overlay.h>
+#include <ui/Surface.h>
+#include <ui/GraphicBuffer.h>
namespace android {
+// ----------------------------------------------------------------------
+
ISurface::BufferHeap::BufferHeap()
: w(0), h(0), hor_stride(0), ver_stride(0), format(0),
transform(0), flags(0)
@@ -55,6 +61,8 @@
{
}
+// ----------------------------------------------------------------------
+
class BpSurface : public BpInterface<ISurface>
{
public:
@@ -63,6 +71,17 @@
{
}
+ virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+ data.writeInt32(bufferIdx);
+ data.writeInt32(usage);
+ remote()->transact(REQUEST_BUFFER, data, &reply);
+ sp<GraphicBuffer> buffer = new GraphicBuffer(reply);
+ return buffer;
+ }
+
virtual status_t registerBuffers(const BufferHeap& buffers)
{
Parcel data, reply;
@@ -112,16 +131,17 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnSurface::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
+ case REQUEST_BUFFER: {
+ CHECK_INTERFACE(ISurface, data, reply);
+ int bufferIdx = data.readInt32();
+ int usage = data.readInt32();
+ sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage));
+ return GraphicBuffer::writeToParcel(reply, buffer.get());
+ }
case REGISTER_BUFFERS: {
CHECK_INTERFACE(ISurface, data, reply);
BufferHeap buffer;
diff --git a/libs/ui/ISurfaceComposer.cpp b/libs/ui/ISurfaceComposer.cpp
index 76597e1..fd2a590 100644
--- a/libs/ui/ISurfaceComposer.cpp
+++ b/libs/ui/ISurfaceComposer.cpp
@@ -20,10 +20,10 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <ui/ISurfaceComposer.h>
#include <ui/DisplayInfo.h>
@@ -54,12 +54,12 @@
return interface_cast<ISurfaceFlingerClient>(reply.readStrongBinder());
}
- virtual sp<IMemory> getCblk() const
+ virtual sp<IMemoryHeap> getCblk() const
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
remote()->transact(BnSurfaceComposer::GET_CBLK, data, &reply);
- return interface_cast<IMemory>(reply.readStrongBinder());
+ return interface_cast<IMemoryHeap>(reply.readStrongBinder());
}
virtual void openGlobalTransaction()
@@ -114,36 +114,6 @@
remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
}
- virtual status_t requestGPU(
- const sp<IGPUCallback>& callback, gpu_info_t* gpu)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(callback->asBinder());
- remote()->transact(BnSurfaceComposer::REQUEST_GPU, data, &reply);
- gpu->regs = interface_cast<IMemory>(reply.readStrongBinder());
- gpu->count = reply.readInt32();
-
- // FIXME: for now, we don't dynamically allocate the regions array
- size_t maxCount = sizeof(gpu->regions)/sizeof(*gpu->regions);
- if (gpu->count > maxCount)
- return BAD_VALUE;
-
- for (size_t i=0 ; i<gpu->count ; i++) {
- gpu->regions[i].region = interface_cast<IMemory>(reply.readStrongBinder());
- gpu->regions[i].reserved = reply.readInt32();
- }
- return reply.readInt32();
- }
-
- virtual status_t revokeGPU()
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::REVOKE_GPU, data, &reply);
- return reply.readInt32();
- }
-
virtual void signal() const
{
Parcel data, reply;
@@ -156,124 +126,61 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnSurfaceComposer::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
- status_t err = BnInterface<ISurfaceComposer>::onTransact(code, data, reply, flags);
- if (err == NO_ERROR)
- return err;
-
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
-
switch(code) {
case CREATE_CONNECTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> b = createConnection()->asBinder();
reply->writeStrongBinder(b);
} break;
case OPEN_GLOBAL_TRANSACTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
openGlobalTransaction();
} break;
case CLOSE_GLOBAL_TRANSACTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
closeGlobalTransaction();
} break;
case SET_ORIENTATION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
DisplayID dpy = data.readInt32();
int orientation = data.readInt32();
uint32_t flags = data.readInt32();
reply->writeInt32( setOrientation(dpy, orientation, flags) );
} break;
case FREEZE_DISPLAY: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
DisplayID dpy = data.readInt32();
uint32_t flags = data.readInt32();
reply->writeInt32( freezeDisplay(dpy, flags) );
} break;
case UNFREEZE_DISPLAY: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
DisplayID dpy = data.readInt32();
uint32_t flags = data.readInt32();
reply->writeInt32( unfreezeDisplay(dpy, flags) );
} break;
case BOOT_FINISHED: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
bootFinished();
} break;
- case REVOKE_GPU: {
- reply->writeInt32( revokeGPU() );
- } break;
case SIGNAL: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
signal();
} break;
case GET_CBLK: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> b = getCblk()->asBinder();
reply->writeStrongBinder(b);
} break;
- case REQUEST_GPU: {
- // TODO: this should be protected by a permission
- gpu_info_t info;
- sp<IGPUCallback> callback
- = interface_cast<IGPUCallback>(data.readStrongBinder());
- status_t res = requestGPU(callback, &info);
-
- // FIXME: for now, we don't dynamically allocate the regions array
- size_t maxCount = sizeof(info.regions)/sizeof(*info.regions);
- if (info.count > maxCount)
- return BAD_VALUE;
-
- reply->writeStrongBinder(info.regs->asBinder());
- reply->writeInt32(info.count);
- for (size_t i=0 ; i<info.count ; i++) {
- reply->writeStrongBinder(info.regions[i].region->asBinder());
- reply->writeInt32(info.regions[i].reserved);
- }
- reply->writeInt32(res);
- } break;
default:
- return UNKNOWN_TRANSACTION;
+ return BBinder::onTransact(code, data, reply, flags);
}
return NO_ERROR;
}
// ----------------------------------------------------------------------------
-enum {
- // Note: BOOT_FINISHED must remain this value, it is called by ActivityManagerService.
- GPU_LOST = IBinder::FIRST_CALL_TRANSACTION
-};
-
-class BpGPUCallback : public BpInterface<IGPUCallback>
-{
-public:
- BpGPUCallback(const sp<IBinder>& impl)
- : BpInterface<IGPUCallback>(impl)
- {
- }
-
- virtual void gpuLost()
- {
- Parcel data, reply;
- data.writeInterfaceToken(IGPUCallback::getInterfaceDescriptor());
- remote()->transact(GPU_LOST, data, &reply, IBinder::FLAG_ONEWAY);
- }
-};
-
-IMPLEMENT_META_INTERFACE(GPUCallback, "android.ui.IGPUCallback");
-
-status_t BnGPUCallback::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case GPU_LOST: {
- CHECK_INTERFACE(IGPUCallback, data, reply);
- gpuLost();
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
};
diff --git a/libs/ui/ISurfaceFlingerClient.cpp b/libs/ui/ISurfaceFlingerClient.cpp
index dab5f71..4a6a1d7 100644
--- a/libs/ui/ISurfaceFlingerClient.cpp
+++ b/libs/ui/ISurfaceFlingerClient.cpp
@@ -21,10 +21,10 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <ui/ISurface.h>
#include <ui/ISurfaceFlingerClient.h>
@@ -64,12 +64,12 @@
{
}
- virtual void getControlBlocks(sp<IMemory>* ctl) const
+ virtual sp<IMemoryHeap> getControlBlock() const
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
remote()->transact(GET_CBLK, data, &reply);
- *ctl = interface_cast<IMemory>(reply.readStrongBinder());
+ return interface_cast<IMemoryHeap>(reply.readStrongBinder());
}
virtual sp<ISurface> createSurface( surface_data_t* params,
@@ -118,12 +118,6 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnSurfaceFlingerClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -132,8 +126,7 @@
switch(code) {
case GET_CBLK: {
CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
- sp<IMemory> ctl;
- getControlBlocks(&ctl);
+ sp<IMemoryHeap> ctl(getControlBlock());
reply->writeStrongBinder(ctl->asBinder());
return NO_ERROR;
} break;
@@ -196,10 +189,11 @@
status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& parcel)
{
- token = parcel.readInt32();
- identity = parcel.readInt32();
- heap[0] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
- heap[1] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
+ token = parcel.readInt32();
+ identity = parcel.readInt32();
+ width = parcel.readInt32();
+ height = parcel.readInt32();
+ format = parcel.readInt32();
return NO_ERROR;
}
@@ -207,8 +201,9 @@
{
parcel->writeInt32(token);
parcel->writeInt32(identity);
- parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL);
- parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL);
+ parcel->writeInt32(width);
+ parcel->writeInt32(height);
+ parcel->writeInt32(format);
return NO_ERROR;
}
diff --git a/libs/ui/LayerState.cpp b/libs/ui/LayerState.cpp
index 0b6374b..a53ffb7 100644
--- a/libs/ui/LayerState.cpp
+++ b/libs/ui/LayerState.cpp
@@ -15,7 +15,7 @@
*/
#include <utils/Errors.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <private/ui/LayerState.h>
namespace android {
diff --git a/libs/ui/Overlay.cpp b/libs/ui/Overlay.cpp
index 59c6514..3aa8950 100644
--- a/libs/ui/Overlay.cpp
+++ b/libs/ui/Overlay.cpp
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#include <utils/IMemory.h>
-#include <utils/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
#include <utils/Errors.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryHeapBase.h>
#include <ui/IOverlay.h>
#include <ui/Overlay.h>
@@ -59,6 +59,30 @@
return mOverlayData->queueBuffer(mOverlayData, buffer);
}
+status_t Overlay::resizeInput(uint32_t width, uint32_t height)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->resizeInput(mOverlayData, width, height);
+}
+
+status_t Overlay::setParameter(int param, int value)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->setParameter(mOverlayData, param, value);
+}
+
+status_t Overlay::setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->setCrop(mOverlayData, x, y, w, h);
+}
+
+status_t Overlay::getCrop(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->getCrop(mOverlayData, x, y, w, h);
+}
+
int32_t Overlay::getBufferCount() const
{
if (mStatus != NO_ERROR) return mStatus;
@@ -73,6 +97,15 @@
void Overlay::destroy() {
if (mStatus != NO_ERROR) return;
+
+ // Must delete the objects in reverse creation order, thus the
+ // data side must be closed first and then the destroy send to
+ // the control side.
+ if (mOverlayData) {
+ overlay_data_close(mOverlayData);
+ mOverlayData = NULL;
+ }
+
mOverlayRef->mOverlayChannel->destroy();
}
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 26e694a..d21ed57 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -16,295 +16,661 @@
#define LOG_TAG "Region"
-#include <stdio.h>
-#include <utils/Atomic.h>
-#include <utils/Debug.h>
+#include <limits.h>
+
+#include <utils/Log.h>
#include <utils/String8.h>
+
+#include <ui/Rect.h>
#include <ui/Region.h>
+#include <ui/Point.h>
+
+#include <private/ui/RegionHelper.h>
+
+// ----------------------------------------------------------------------------
+#define VALIDATE_REGIONS (false)
+#define VALIDATE_WITH_CORECG (false)
+// ----------------------------------------------------------------------------
+
+#if VALIDATE_WITH_CORECG
+#include <core/SkRegion.h>
+#endif
namespace android {
+// ----------------------------------------------------------------------------
+
+enum {
+ op_nand = region_operator<Rect>::op_nand,
+ op_and = region_operator<Rect>::op_and,
+ op_or = region_operator<Rect>::op_or,
+ op_xor = region_operator<Rect>::op_xor
+};
// ----------------------------------------------------------------------------
Region::Region()
+ : mBounds(0,0)
{
}
Region::Region(const Region& rhs)
- : mRegion(rhs.mRegion)
+ : mBounds(rhs.mBounds), mStorage(rhs.mStorage)
{
}
-Region::Region(const SkRegion& rhs)
- : mRegion(rhs)
+Region::Region(const Rect& rhs)
+ : mBounds(rhs)
{
}
+Region::Region(const Parcel& parcel)
+{
+ status_t err = read(parcel);
+ LOGE_IF(err<0, "error %s reading Region from parcel", strerror(err));
+}
+
+Region::Region(const void* buffer)
+{
+ status_t err = read(buffer);
+ LOGE_IF(err<0, "error %s reading Region from parcel", strerror(err));
+}
+
Region::~Region()
{
}
-Region::Region(const Rect& rhs)
-{
- set(rhs);
-}
-
-Region::Region(const Parcel& parcel)
-{
- read(parcel);
-}
-
-Region::Region(const void* buffer)
-{
- read(buffer);
-}
-
Region& Region::operator = (const Region& rhs)
{
- mRegion = rhs.mRegion;
+#if VALIDATE_REGIONS
+ validate(rhs, "operator=");
+#endif
+ mBounds = rhs.mBounds;
+ mStorage = rhs.mStorage;
return *this;
}
-const SkRegion& Region::toSkRegion() const
+Region& Region::makeBoundsSelf()
{
- return mRegion;
-}
-
-Rect Region::bounds() const
-{
- const SkIRect& b(mRegion.getBounds());
- return Rect(b.fLeft, b.fTop, b.fRight, b.fBottom);
+ mStorage.clear();
+ return *this;
}
void Region::clear()
{
- mRegion.setEmpty();
+ mBounds.clear();
+ mStorage.clear();
}
void Region::set(const Rect& r)
{
- SkIRect ir;
- ir.set(r.left, r.top, r.right, r.bottom);
- mRegion.setRect(ir);
+ mBounds = r;
+ mStorage.clear();
+}
+
+void Region::set(uint32_t w, uint32_t h)
+{
+ mBounds = Rect(int(w), int(h));
+ mStorage.clear();
}
// ----------------------------------------------------------------------------
-Region& Region::orSelf(const Rect& r)
+void Region::addRectUnchecked(int l, int t, int r, int b)
{
- SkIRect ir;
- ir.set(r.left, r.top, r.right, r.bottom);
- mRegion.op(ir, SkRegion::kUnion_Op);
- return *this;
+ mStorage.add(Rect(l,t,r,b));
+#if VALIDATE_REGIONS
+ validate(*this, "addRectUnchecked");
+#endif
}
-Region& Region::andSelf(const Rect& r)
-{
- SkIRect ir;
- ir.set(r.left, r.top, r.right, r.bottom);
- mRegion.op(ir, SkRegion::kIntersect_Op);
+// ----------------------------------------------------------------------------
+
+Region& Region::orSelf(const Rect& r) {
+ return operationSelf(r, op_or);
+}
+Region& Region::andSelf(const Rect& r) {
+ return operationSelf(r, op_and);
+}
+Region& Region::subtractSelf(const Rect& r) {
+ return operationSelf(r, op_nand);
+}
+Region& Region::operationSelf(const Rect& r, int op) {
+ Region lhs(*this);
+ boolean_operation(op, *this, lhs, r);
return *this;
}
// ----------------------------------------------------------------------------
Region& Region::orSelf(const Region& rhs) {
- mRegion.op(rhs.mRegion, SkRegion::kUnion_Op);
- return *this;
+ return operationSelf(rhs, op_or);
}
-
Region& Region::andSelf(const Region& rhs) {
- mRegion.op(rhs.mRegion, SkRegion::kIntersect_Op);
- return *this;
+ return operationSelf(rhs, op_and);
}
-
Region& Region::subtractSelf(const Region& rhs) {
- mRegion.op(rhs.mRegion, SkRegion::kDifference_Op);
+ return operationSelf(rhs, op_nand);
+}
+Region& Region::operationSelf(const Region& rhs, int op) {
+ Region lhs(*this);
+ boolean_operation(op, *this, lhs, rhs);
return *this;
}
Region& Region::translateSelf(int x, int y) {
- if (x|y) mRegion.translate(x, y);
+ if (x|y) translate(*this, x, y);
return *this;
}
-Region Region::merge(const Region& rhs) const {
+// ----------------------------------------------------------------------------
+
+const Region Region::merge(const Rect& rhs) const {
+ return operation(rhs, op_or);
+}
+const Region Region::intersect(const Rect& rhs) const {
+ return operation(rhs, op_and);
+}
+const Region Region::subtract(const Rect& rhs) const {
+ return operation(rhs, op_nand);
+}
+const Region Region::operation(const Rect& rhs, int op) const {
Region result;
- result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kUnion_Op);
+ boolean_operation(op, result, *this, rhs);
return result;
}
-Region Region::intersect(const Region& rhs) const {
+// ----------------------------------------------------------------------------
+
+const Region Region::merge(const Region& rhs) const {
+ return operation(rhs, op_or);
+}
+const Region Region::intersect(const Region& rhs) const {
+ return operation(rhs, op_and);
+}
+const Region Region::subtract(const Region& rhs) const {
+ return operation(rhs, op_nand);
+}
+const Region Region::operation(const Region& rhs, int op) const {
Region result;
- result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kIntersect_Op);
+ boolean_operation(op, result, *this, rhs);
return result;
}
-Region Region::subtract(const Region& rhs) const {
+const Region Region::translate(int x, int y) const {
Region result;
- result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kDifference_Op);
- return result;
-}
-
-Region Region::translate(int x, int y) const {
- Region result;
- mRegion.translate(x, y, &result.mRegion);
+ translate(result, *this, x, y);
return result;
}
// ----------------------------------------------------------------------------
Region& Region::orSelf(const Region& rhs, int dx, int dy) {
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- mRegion.op(r, SkRegion::kUnion_Op);
- return *this;
+ return operationSelf(rhs, dx, dy, op_or);
}
-
Region& Region::andSelf(const Region& rhs, int dx, int dy) {
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- mRegion.op(r, SkRegion::kIntersect_Op);
- return *this;
+ return operationSelf(rhs, dx, dy, op_and);
}
-
Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- mRegion.op(r, SkRegion::kDifference_Op);
+ return operationSelf(rhs, dx, dy, op_nand);
+}
+Region& Region::operationSelf(const Region& rhs, int dx, int dy, int op) {
+ Region lhs(*this);
+ boolean_operation(op, *this, lhs, rhs, dx, dy);
return *this;
}
-Region Region::merge(const Region& rhs, int dx, int dy) const {
- Region result;
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- result.mRegion.op(mRegion, r, SkRegion::kUnion_Op);
- return result;
-}
+// ----------------------------------------------------------------------------
-Region Region::intersect(const Region& rhs, int dx, int dy) const {
- Region result;
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- result.mRegion.op(mRegion, r, SkRegion::kIntersect_Op);
- return result;
+const Region Region::merge(const Region& rhs, int dx, int dy) const {
+ return operation(rhs, dx, dy, op_or);
}
-
-Region Region::subtract(const Region& rhs, int dx, int dy) const {
+const Region Region::intersect(const Region& rhs, int dx, int dy) const {
+ return operation(rhs, dx, dy, op_and);
+}
+const Region Region::subtract(const Region& rhs, int dx, int dy) const {
+ return operation(rhs, dx, dy, op_nand);
+}
+const Region Region::operation(const Region& rhs, int dx, int dy, int op) const {
Region result;
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- result.mRegion.op(mRegion, r, SkRegion::kDifference_Op);
+ boolean_operation(op, result, *this, rhs, dx, dy);
return result;
}
// ----------------------------------------------------------------------------
-Region::iterator::iterator(const Region& r)
- : mIt(r.mRegion)
+// This is our region rasterizer, which merges rects and spans together
+// to obtain an optimal region.
+class Region::rasterizer : public region_operator<Rect>::region_rasterizer
{
+ Rect& bounds;
+ Vector<Rect>& storage;
+ Rect* head;
+ Rect* tail;
+ Vector<Rect> span;
+ Rect* cur;
+public:
+ rasterizer(Region& reg)
+ : bounds(reg.mBounds), storage(reg.mStorage), head(), tail(), cur() {
+ bounds.top = bounds.bottom = 0;
+ bounds.left = INT_MAX;
+ bounds.right = INT_MIN;
+ storage.clear();
+ }
+
+ ~rasterizer() {
+ if (span.size()) {
+ flushSpan();
+ }
+ if (storage.size()) {
+ bounds.top = storage.itemAt(0).top;
+ bounds.bottom = storage.top().bottom;
+ if (storage.size() == 1) {
+ storage.clear();
+ }
+ } else {
+ bounds.left = 0;
+ bounds.right = 0;
+ }
+ }
+
+ virtual void operator()(const Rect& rect) {
+ //LOGD(">>> %3d, %3d, %3d, %3d",
+ // rect.left, rect.top, rect.right, rect.bottom);
+ if (span.size()) {
+ if (cur->top != rect.top) {
+ flushSpan();
+ } else if (cur->right == rect.left) {
+ cur->right = rect.right;
+ return;
+ }
+ }
+ span.add(rect);
+ cur = span.editArray() + (span.size() - 1);
+ }
+private:
+ template<typename T>
+ static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; }
+ template<typename T>
+ static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; }
+ void flushSpan() {
+ bool merge = false;
+ if (tail-head == ssize_t(span.size())) {
+ Rect const* p = cur;
+ Rect const* q = head;
+ if (p->top == q->bottom) {
+ merge = true;
+ while (q != tail) {
+ if ((p->left != q->left) || (p->right != q->right)) {
+ merge = false;
+ break;
+ }
+ p++, q++;
+ }
+ }
+ }
+ if (merge) {
+ const int bottom = span[0].bottom;
+ Rect* r = head;
+ while (r != tail) {
+ r->bottom = bottom;
+ r++;
+ }
+ } else {
+ bounds.left = min(span.itemAt(0).left, bounds.left);
+ bounds.right = max(span.top().right, bounds.right);
+ storage.appendVector(span);
+ tail = storage.editArray() + storage.size();
+ head = tail - span.size();
+ }
+ span.clear();
+ }
+};
+
+bool Region::validate(const Region& reg, const char* name)
+{
+ bool result = true;
+ const_iterator cur = reg.begin();
+ const_iterator const tail = reg.end();
+ const_iterator prev = cur++;
+ Rect b(*prev);
+ while (cur != tail) {
+ b.left = b.left < cur->left ? b.left : cur->left;
+ b.top = b.top < cur->top ? b.top : cur->top;
+ b.right = b.right > cur->right ? b.right : cur->right;
+ b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
+ if (cur->top == prev->top) {
+ if (cur->bottom != prev->bottom) {
+ LOGE("%s: invalid span %p", name, cur);
+ result = false;
+ } else if (cur->left < prev->right) {
+ LOGE("%s: spans overlap horizontally prev=%p, cur=%p",
+ name, prev, cur);
+ result = false;
+ }
+ } else if (cur->top < prev->bottom) {
+ LOGE("%s: spans overlap vertically prev=%p, cur=%p",
+ name, prev, cur);
+ result = false;
+ }
+ prev = cur;
+ cur++;
+ }
+ if (b != reg.getBounds()) {
+ result = false;
+ LOGE("%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
+ b.left, b.top, b.right, b.bottom,
+ reg.getBounds().left, reg.getBounds().top,
+ reg.getBounds().right, reg.getBounds().bottom);
+ }
+ if (result == false) {
+ reg.dump(name);
+ }
+ return result;
}
-int Region::iterator::iterate(Rect* rect)
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs,
+ const Region& rhs, int dx, int dy)
{
- if (mIt.done())
- return 0;
- const SkIRect& r(mIt.rect());
- rect->left = r.fLeft;
- rect->top = r.fTop;
- rect->right = r.fRight;
- rect->bottom= r.fBottom;
- mIt.next();
- return 1;
+ size_t lhs_count;
+ Rect const * const lhs_rects = lhs.getArray(&lhs_count);
+
+ size_t rhs_count;
+ Rect const * const rhs_rects = rhs.getArray(&rhs_count);
+
+ region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
+ region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy);
+ region_operator<Rect> operation(op, lhs_region, rhs_region);
+ { // scope for rasterizer (dtor has side effects)
+ rasterizer r(dst);
+ operation(r);
+ }
+
+#if VALIDATE_REGIONS
+ validate(lhs, "boolean_operation: lhs");
+ validate(rhs, "boolean_operation: rhs");
+ validate(dst, "boolean_operation: dst");
+#endif
+
+#if VALIDATE_WITH_CORECG
+ SkRegion sk_lhs;
+ SkRegion sk_rhs;
+ SkRegion sk_dst;
+
+ for (size_t i=0 ; i<lhs_count ; i++)
+ sk_lhs.op(
+ lhs_rects[i].left + dx,
+ lhs_rects[i].top + dy,
+ lhs_rects[i].right + dx,
+ lhs_rects[i].bottom + dy,
+ SkRegion::kUnion_Op);
+
+ for (size_t i=0 ; i<rhs_count ; i++)
+ sk_rhs.op(
+ rhs_rects[i].left + dx,
+ rhs_rects[i].top + dy,
+ rhs_rects[i].right + dx,
+ rhs_rects[i].bottom + dy,
+ SkRegion::kUnion_Op);
+
+ const char* name = "---";
+ SkRegion::Op sk_op;
+ switch (op) {
+ case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
+ case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
+ case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
+ }
+ sk_dst.op(sk_lhs, sk_rhs, sk_op);
+
+ if (sk_dst.isEmpty() && dst.isEmpty())
+ return;
+
+ bool same = true;
+ Region::const_iterator head = dst.begin();
+ Region::const_iterator const tail = dst.end();
+ SkRegion::Iterator it(sk_dst);
+ while (!it.done()) {
+ if (head != tail) {
+ if (
+ head->left != it.rect().fLeft ||
+ head->top != it.rect().fTop ||
+ head->right != it.rect().fRight ||
+ head->bottom != it.rect().fBottom
+ ) {
+ same = false;
+ break;
+ }
+ } else {
+ same = false;
+ break;
+ }
+ head++;
+ it.next();
+ }
+
+ if (head != tail) {
+ same = false;
+ }
+
+ if(!same) {
+ LOGD("---\nregion boolean %s failed", name);
+ lhs.dump("lhs");
+ rhs.dump("rhs");
+ dst.dump("dst");
+ LOGD("should be");
+ SkRegion::Iterator it(sk_dst);
+ while (!it.done()) {
+ LOGD(" [%3d, %3d, %3d, %3d]",
+ it.rect().fLeft,
+ it.rect().fTop,
+ it.rect().fRight,
+ it.rect().fBottom);
+ it.next();
+ }
+ }
+#endif
+}
+
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs,
+ const Rect& rhs, int dx, int dy)
+{
+#if VALIDATE_WITH_CORECG || VALIDATE_REGIONS
+ boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
+#else
+ size_t lhs_count;
+ Rect const * const lhs_rects = lhs.getArray(&lhs_count);
+
+ region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
+ region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy);
+ region_operator<Rect> operation(op, lhs_region, rhs_region);
+ { // scope for rasterizer (dtor has side effects)
+ rasterizer r(dst);
+ operation(r);
+ }
+
+#endif
+}
+
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs, const Region& rhs)
+{
+ boolean_operation(op, dst, lhs, rhs, 0, 0);
+}
+
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs, const Rect& rhs)
+{
+ boolean_operation(op, dst, lhs, rhs, 0, 0);
+}
+
+void Region::translate(Region& reg, int dx, int dy)
+{
+ if (!reg.isEmpty()) {
+#if VALIDATE_REGIONS
+ validate(reg, "translate (before)");
+#endif
+ reg.mBounds.translate(dx, dy);
+ size_t count = reg.mStorage.size();
+ Rect* rects = reg.mStorage.editArray();
+ while (count) {
+ rects->translate(dx, dy);
+ rects++;
+ count--;
+ }
+#if VALIDATE_REGIONS
+ validate(reg, "translate (after)");
+#endif
+ }
+}
+
+void Region::translate(Region& dst, const Region& reg, int dx, int dy)
+{
+ dst = reg;
+ translate(dst, dx, dy);
}
// ----------------------------------------------------------------------------
-// we write a 4byte size ahead of the actual region, so we know how much we'll need for reading
-
status_t Region::write(Parcel& parcel) const
{
- int32_t size = mRegion.flatten(NULL);
- parcel.writeInt32(size);
- mRegion.flatten(parcel.writeInplace(size));
+#if VALIDATE_REGIONS
+ validate(*this, "write(Parcel)");
+#endif
+ status_t err;
+ const size_t count = mStorage.size();
+ const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
+ void* buffer = parcel.writeInplace(sizeNeeded);
+ if (!buffer) return NO_MEMORY;
+ ssize_t written = Region::write(buffer, sizeNeeded);
+ if (written < 0) return status_t(written);
return NO_ERROR;
}
status_t Region::read(const Parcel& parcel)
{
- size_t size = parcel.readInt32();
- mRegion.unflatten(parcel.readInplace(size));
+ void const* buffer = parcel.readInplace(sizeof(int32_t));
+ if (!buffer) return NO_MEMORY;
+ const size_t count = *static_cast<int32_t const *>(buffer);
+ void const* dummy = parcel.readInplace((1+count)*sizeof(Rect));
+ if (!dummy) return NO_MEMORY;
+ const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
+ const ssize_t read = Region::read(buffer);
+ if (read < 0) return status_t(read);
+#if VALIDATE_REGIONS
+ validate(*this, "read(Parcel)");
+#endif
return NO_ERROR;
}
ssize_t Region::write(void* buffer, size_t size) const
{
- size_t sizeNeeded = mRegion.flatten(NULL);
+#if VALIDATE_REGIONS
+ validate(*this, "write(buffer)");
+#endif
+ const size_t count = mStorage.size();
+ const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
if (sizeNeeded > size) return NO_MEMORY;
- return mRegion.flatten(buffer);
+ int32_t* const p = static_cast<int32_t*>(buffer);
+ *p = count;
+ memcpy(p+1, &mBounds, sizeof(Rect));
+ if (count) {
+ memcpy(p+5, mStorage.array(), count*sizeof(Rect));
+ }
+ return ssize_t(sizeNeeded);
}
ssize_t Region::read(const void* buffer)
{
- return mRegion.unflatten(buffer);
+ int32_t const* const p = static_cast<int32_t const*>(buffer);
+ const size_t count = *p;
+ memcpy(&mBounds, p+1, sizeof(Rect));
+ mStorage.clear();
+ if (count) {
+ mStorage.insertAt(0, count);
+ memcpy(mStorage.editArray(), p+5, count*sizeof(Rect));
+ }
+#if VALIDATE_REGIONS
+ validate(*this, "read(buffer)");
+#endif
+ return ssize_t(sizeof(int32_t) + (1+count)*sizeof(Rect));
}
ssize_t Region::writeEmpty(void* buffer, size_t size)
{
- if (size < 4) return NO_MEMORY;
- // this needs to stay in sync with SkRegion
- *static_cast<int32_t*>(buffer) = -1;
- return 4;
+ const size_t sizeNeeded = sizeof(int32_t) + sizeof(Rect);
+ if (sizeNeeded > size) return NO_MEMORY;
+ int32_t* const p = static_cast<int32_t*>(buffer);
+ memset(p, 0, sizeNeeded);
+ return ssize_t(sizeNeeded);
}
bool Region::isEmpty(void* buffer)
{
- // this needs to stay in sync with SkRegion
- return *static_cast<int32_t*>(buffer) == -1;
+ int32_t const* const p = static_cast<int32_t const*>(buffer);
+ Rect const* const b = reinterpret_cast<Rect const *>(p+1);
+ return b->isEmpty();
}
-size_t Region::rects(Vector<Rect>& rectList) const
+// ----------------------------------------------------------------------------
+
+Region::const_iterator Region::begin() const {
+ return isRect() ? &mBounds : mStorage.array();
+}
+
+Region::const_iterator Region::end() const {
+ return isRect() ? ((&mBounds) + 1) : (mStorage.array() + mStorage.size());
+}
+
+Rect const* Region::getArray(size_t* count) const {
+ const_iterator const b(begin());
+ const_iterator const e(end());
+ if (count) *count = e-b;
+ return b;
+}
+
+size_t Region::getRects(Vector<Rect>& rectList) const
{
- rectList.clear();
- if (!isEmpty()) {
- SkRegion::Iterator iterator(mRegion);
- while( !iterator.done() ) {
- const SkIRect& ir(iterator.rect());
- rectList.push(Rect(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom));
- iterator.next();
- }
+ rectList = mStorage;
+ if (rectList.isEmpty()) {
+ rectList.clear();
+ rectList.add(mBounds);
}
return rectList.size();
}
+// ----------------------------------------------------------------------------
+
void Region::dump(String8& out, const char* what, uint32_t flags) const
{
(void)flags;
- Vector<Rect> r;
- rects(r);
-
+ const_iterator head = begin();
+ const_iterator const tail = end();
+
size_t SIZE = 256;
char buffer[SIZE];
-
- snprintf(buffer, SIZE, " Region %s (this=%p, count=%d)\n", what, this, r.size());
+
+ snprintf(buffer, SIZE, " Region %s (this=%p, count=%d)\n",
+ what, this, tail-head);
out.append(buffer);
- for (size_t i=0 ; i<r.size() ; i++) {
+ while (head != tail) {
snprintf(buffer, SIZE, " [%3d, %3d, %3d, %3d]\n",
- r[i].left, r[i].top,r[i].right,r[i].bottom);
+ head->left, head->top, head->right, head->bottom);
out.append(buffer);
+ head++;
}
}
void Region::dump(const char* what, uint32_t flags) const
{
(void)flags;
- Vector<Rect> r;
- rects(r);
- LOGD(" Region %s (this=%p, count=%d)\n", what, this, r.size());
- for (size_t i=0 ; i<r.size() ; i++) {
+ const_iterator head = begin();
+ const_iterator const tail = end();
+ LOGD(" Region %s (this=%p, count=%d)\n", what, this, tail-head);
+ while (head != tail) {
LOGD(" [%3d, %3d, %3d, %3d]\n",
- r[i].left, r[i].top,r[i].right,r[i].bottom);
+ head->left, head->top, head->right, head->bottom);
+ head++;
}
}
diff --git a/libs/ui/SharedBufferStack.cpp b/libs/ui/SharedBufferStack.cpp
new file mode 100644
index 0000000..46b6766
--- /dev/null
+++ b/libs/ui/SharedBufferStack.cpp
@@ -0,0 +1,424 @@
+/*
+ * 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 "SharedBufferStack"
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#include <private/ui/SharedBufferStack.h>
+
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#define DEBUG_ATOMICS 0
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+SharedClient::SharedClient()
+ : lock(Mutex::SHARED)
+{
+}
+
+SharedClient::~SharedClient() {
+}
+
+
+// these functions are used by the clients
+status_t SharedClient::validate(size_t i) const {
+ if (uint32_t(i) >= uint32_t(NUM_LAYERS_MAX))
+ return BAD_INDEX;
+ return surfaces[i].status;
+}
+
+uint32_t SharedClient::getIdentity(size_t token) const {
+ return uint32_t(surfaces[token].identity);
+}
+
+// ----------------------------------------------------------------------------
+
+
+SharedBufferStack::SharedBufferStack()
+{
+}
+
+void SharedBufferStack::init(int32_t i)
+{
+ inUse = -1;
+ status = NO_ERROR;
+ identity = i;
+}
+
+status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
+{
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return BAD_INDEX;
+
+ // in the current implementation we only send a single rectangle
+ const Rect bounds(dirty.getBounds());
+ FlatRegion& reg(dirtyRegion[buffer]);
+ reg.count = 1;
+ reg.rects[0] = uint16_t(bounds.left);
+ reg.rects[1] = uint16_t(bounds.top);
+ reg.rects[2] = uint16_t(bounds.right);
+ reg.rects[3] = uint16_t(bounds.bottom);
+ return NO_ERROR;
+}
+
+Region SharedBufferStack::getDirtyRegion(int buffer) const
+{
+ Region res;
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return res;
+
+ const FlatRegion& reg(dirtyRegion[buffer]);
+ res.set(Rect(reg.rects[0], reg.rects[1], reg.rects[2], reg.rects[3]));
+ return res;
+}
+
+// ----------------------------------------------------------------------------
+
+SharedBufferBase::SharedBufferBase(SharedClient* sharedClient,
+ int surface, int num, int32_t identity)
+ : mSharedClient(sharedClient),
+ mSharedStack(sharedClient->surfaces + surface),
+ mNumBuffers(num), mIdentity(identity)
+{
+}
+
+SharedBufferBase::~SharedBufferBase()
+{
+}
+
+uint32_t SharedBufferBase::getIdentity()
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.identity;
+}
+
+status_t SharedBufferBase::getStatus() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.status;
+}
+
+size_t SharedBufferBase::getFrontBuffer() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return size_t( stack.head );
+}
+
+String8 SharedBufferBase::dump(char const* prefix) const
+{
+ const size_t SIZE = 1024;
+ char buffer[SIZE];
+ String8 result;
+ SharedBufferStack& stack( *mSharedStack );
+ snprintf(buffer, SIZE,
+ "%s[ head=%2d, available=%2d, queued=%2d ] "
+ "reallocMask=%08x, inUse=%2d, identity=%d, status=%d\n",
+ prefix, stack.head, stack.available, stack.queued,
+ stack.reallocMask, stack.inUse, stack.identity, stack.status);
+ result.append(buffer);
+ return result;
+}
+
+// ============================================================================
+// conditions and updates
+// ============================================================================
+
+SharedBufferClient::DequeueCondition::DequeueCondition(
+ SharedBufferClient* sbc) : ConditionBase(sbc) {
+}
+bool SharedBufferClient::DequeueCondition::operator()() {
+ return stack.available > 0;
+}
+
+SharedBufferClient::LockCondition::LockCondition(
+ SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) {
+}
+bool SharedBufferClient::LockCondition::operator()() {
+ return (buf != stack.head ||
+ (stack.queued > 0 && stack.inUse != buf));
+}
+
+SharedBufferServer::ReallocateCondition::ReallocateCondition(
+ SharedBufferBase* sbb, int buf) : ConditionBase(sbb), buf(buf) {
+}
+bool SharedBufferServer::ReallocateCondition::operator()() {
+ // TODO: we should also check that buf has been dequeued
+ return (buf != stack.head);
+}
+
+// ----------------------------------------------------------------------------
+
+SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb)
+ : UpdateBase(sbb) {
+}
+ssize_t SharedBufferClient::QueueUpdate::operator()() {
+ android_atomic_inc(&stack.queued);
+ return NO_ERROR;
+}
+
+SharedBufferClient::UndoDequeueUpdate::UndoDequeueUpdate(SharedBufferBase* sbb)
+ : UpdateBase(sbb) {
+}
+ssize_t SharedBufferClient::UndoDequeueUpdate::operator()() {
+ android_atomic_inc(&stack.available);
+ return NO_ERROR;
+}
+
+SharedBufferServer::UnlockUpdate::UnlockUpdate(
+ SharedBufferBase* sbb, int lockedBuffer)
+ : UpdateBase(sbb), lockedBuffer(lockedBuffer) {
+}
+ssize_t SharedBufferServer::UnlockUpdate::operator()() {
+ if (stack.inUse != lockedBuffer) {
+ LOGE("unlocking %d, but currently locked buffer is %d",
+ lockedBuffer, stack.inUse);
+ return BAD_VALUE;
+ }
+ android_atomic_write(-1, &stack.inUse);
+ return NO_ERROR;
+}
+
+SharedBufferServer::RetireUpdate::RetireUpdate(
+ SharedBufferBase* sbb, int numBuffers)
+ : UpdateBase(sbb), numBuffers(numBuffers) {
+}
+ssize_t SharedBufferServer::RetireUpdate::operator()() {
+ // head is only written in this function, which is single-thread.
+ int32_t head = stack.head;
+
+ // Preventively lock the current buffer before updating queued.
+ android_atomic_write(head, &stack.inUse);
+
+ // Decrement the number of queued buffers
+ int32_t queued;
+ do {
+ queued = stack.queued;
+ if (queued == 0) {
+ return NOT_ENOUGH_DATA;
+ }
+ } while (android_atomic_cmpxchg(queued, queued-1, &stack.queued));
+
+ // update the head pointer
+ head = ((head+1 >= numBuffers) ? 0 : head+1);
+
+ // lock the buffer before advancing head, which automatically unlocks
+ // the buffer we preventively locked upon entering this function
+ android_atomic_write(head, &stack.inUse);
+
+ // advance head
+ android_atomic_write(head, &stack.head);
+
+ // now that head has moved, we can increment the number of available buffers
+ android_atomic_inc(&stack.available);
+ return head;
+}
+
+SharedBufferServer::StatusUpdate::StatusUpdate(
+ SharedBufferBase* sbb, status_t status)
+ : UpdateBase(sbb), status(status) {
+}
+
+ssize_t SharedBufferServer::StatusUpdate::operator()() {
+ android_atomic_write(status, &stack.status);
+ return NO_ERROR;
+}
+
+// ============================================================================
+
+SharedBufferClient::SharedBufferClient(SharedClient* sharedClient,
+ int surface, int num, int32_t identity)
+ : SharedBufferBase(sharedClient, surface, num, identity), tail(0)
+{
+ tail = computeTail();
+}
+
+int32_t SharedBufferClient::computeTail() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ // we need to make sure we read available and head coherently,
+ // w.r.t RetireUpdate.
+ int32_t newTail;
+ int32_t avail;
+ int32_t head;
+ do {
+ avail = stack.available;
+ head = stack.head;
+ } while (stack.available != avail);
+ newTail = head - avail + 1;
+ if (newTail < 0) {
+ newTail += mNumBuffers;
+ }
+ return newTail;
+}
+
+ssize_t SharedBufferClient::dequeue()
+{
+ SharedBufferStack& stack( *mSharedStack );
+
+ if (stack.head == tail && stack.available == 2) {
+ LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",
+ tail, stack.head, stack.available, stack.queued);
+ }
+
+ const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
+
+ //LOGD("[%d] about to dequeue a buffer",
+ // mSharedStack->identity);
+ DequeueCondition condition(this);
+ status_t err = waitForCondition(condition);
+ if (err != NO_ERROR)
+ return ssize_t(err);
+
+ // NOTE: 'stack.available' is part of the conditions, however
+ // decrementing it, never changes any conditions, so we don't need
+ // to do this as part of an update.
+ if (android_atomic_dec(&stack.available) == 0) {
+ LOGW("dequeue probably called from multiple threads!");
+ }
+
+ int dequeued = tail;
+ tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1);
+ LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail=%d, %s",
+ dequeued, tail, dump("").string());
+
+ mDequeueTime[dequeued] = dequeueTime;
+
+ return dequeued;
+}
+
+status_t SharedBufferClient::undoDequeue(int buf)
+{
+ UndoDequeueUpdate update(this);
+ status_t err = updateCondition( update );
+ if (err == NO_ERROR) {
+ tail = computeTail();
+ }
+ return err;
+}
+
+status_t SharedBufferClient::lock(int buf)
+{
+ LockCondition condition(this, buf);
+ status_t err = waitForCondition(condition);
+ return err;
+}
+
+status_t SharedBufferClient::queue(int buf)
+{
+ QueueUpdate update(this);
+ status_t err = updateCondition( update );
+ LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string());
+ SharedBufferStack& stack( *mSharedStack );
+ const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
+ stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
+ return err;
+}
+
+bool SharedBufferClient::needNewBuffer(int buffer) const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ const uint32_t mask = 1<<buffer;
+ return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0;
+}
+
+status_t SharedBufferClient::setDirtyRegion(int buffer, const Region& reg)
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.setDirtyRegion(buffer, reg);
+}
+
+// ----------------------------------------------------------------------------
+
+SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
+ int surface, int num, int32_t identity)
+ : SharedBufferBase(sharedClient, surface, num, identity)
+{
+ mSharedStack->init(identity);
+ mSharedStack->head = num-1;
+ mSharedStack->available = num;
+ mSharedStack->queued = 0;
+ mSharedStack->reallocMask = 0;
+ memset(mSharedStack->dirtyRegion, 0, sizeof(mSharedStack->dirtyRegion));
+}
+
+ssize_t SharedBufferServer::retireAndLock()
+{
+ RetireUpdate update(this, mNumBuffers);
+ ssize_t buf = updateCondition( update );
+ LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s", int(buf), dump("").string());
+ return buf;
+}
+
+status_t SharedBufferServer::unlock(int buffer)
+{
+ UnlockUpdate update(this, buffer);
+ status_t err = updateCondition( update );
+ return err;
+}
+
+void SharedBufferServer::setStatus(status_t status)
+{
+ if (status < NO_ERROR) {
+ StatusUpdate update(this, status);
+ updateCondition( update );
+ }
+}
+
+status_t SharedBufferServer::reallocate()
+{
+ SharedBufferStack& stack( *mSharedStack );
+ uint32_t mask = (1<<mNumBuffers)-1;
+ android_atomic_or(mask, &stack.reallocMask);
+ return NO_ERROR;
+}
+
+int32_t SharedBufferServer::getQueuedCount() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.queued;
+}
+
+status_t SharedBufferServer::assertReallocate(int buffer)
+{
+ ReallocateCondition condition(this, buffer);
+ status_t err = waitForCondition(condition);
+ return err;
+}
+
+Region SharedBufferServer::getDirtyRegion(int buffer) const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.getDirtyRegion(buffer);
+}
+
+SharedBufferStack::Statistics SharedBufferServer::getStats() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.stats;
+}
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index 4ea9ae2..f51ca7a 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -23,233 +23,734 @@
#include <sys/types.h>
#include <sys/stat.h>
-#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/threads.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IMemory.h>
+#include <utils/CallStack.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IMemory.h>
#include <utils/Log.h>
+#include <ui/DisplayInfo.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferMapper.h>
#include <ui/ISurface.h>
#include <ui/Surface.h>
#include <ui/SurfaceComposerClient.h>
#include <ui/Rect.h>
-#include <private/ui/SharedState.h>
+#include <pixelflinger/pixelflinger.h>
+
+#include <private/ui/SharedBufferStack.h>
#include <private/ui/LayerState.h>
namespace android {
-// ---------------------------------------------------------------------------
+// ----------------------------------------------------------------------
-Surface::Surface(const sp<SurfaceComposerClient>& client,
+static status_t copyBlt(
+ const sp<GraphicBuffer>& dst,
+ const sp<GraphicBuffer>& src,
+ const Region& reg)
+{
+ status_t err;
+ uint8_t const * src_bits = NULL;
+ err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
+ LOGE_IF(err, "error locking src buffer %s", strerror(-err));
+
+ uint8_t* dst_bits = NULL;
+ err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
+ LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
+
+ Region::const_iterator head(reg.begin());
+ Region::const_iterator tail(reg.end());
+ if (head != tail && src_bits && dst_bits) {
+ // NOTE: dst and src must be the same format
+ const size_t bpp = bytesPerPixel(src->format);
+ const size_t dbpr = dst->stride * bpp;
+ const size_t sbpr = src->stride * bpp;
+
+ while (head != tail) {
+ const Rect& r(*head++);
+ ssize_t h = r.height();
+ if (h <= 0) continue;
+ size_t size = r.width() * bpp;
+ uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+ uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+ if (dbpr==sbpr && size==sbpr) {
+ size *= h;
+ h = 1;
+ }
+ do {
+ memcpy(d, s, size);
+ d += dbpr;
+ s += sbpr;
+ } while (--h > 0);
+ }
+ }
+
+ if (src_bits)
+ src->unlock();
+
+ if (dst_bits)
+ dst->unlock();
+
+ return err;
+}
+
+// ============================================================================
+// SurfaceControl
+// ============================================================================
+
+SurfaceControl::SurfaceControl(
+ const sp<SurfaceComposerClient>& client,
const sp<ISurface>& surface,
const ISurfaceFlingerClient::surface_data_t& data,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
- bool owner)
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
: mClient(client), mSurface(surface),
mToken(data.token), mIdentity(data.identity),
- mFormat(format), mFlags(flags), mOwner(owner)
+ mWidth(data.width), mHeight(data.height), mFormat(data.format),
+ mFlags(flags)
{
- mSwapRectangle.makeInvalid();
- mSurfaceHeapBase[0] = 0;
- mSurfaceHeapBase[1] = 0;
- mHeap[0] = data.heap[0];
- mHeap[1] = data.heap[1];
+}
+
+SurfaceControl::~SurfaceControl()
+{
+ destroy();
}
-Surface::Surface(Surface const* rhs)
- : mOwner(false)
+void SurfaceControl::destroy()
{
- mToken = rhs->mToken;
- mIdentity= rhs->mIdentity;
- mClient = rhs->mClient;
- mSurface = rhs->mSurface;
- mHeap[0] = rhs->mHeap[0];
- mHeap[1] = rhs->mHeap[1];
- mFormat = rhs->mFormat;
- mFlags = rhs->mFlags;
- mSurfaceHeapBase[0] = rhs->mSurfaceHeapBase[0];
- mSurfaceHeapBase[1] = rhs->mSurfaceHeapBase[1];
- mSwapRectangle.makeInvalid();
-}
-
-Surface::~Surface()
-{
- if (mOwner && mToken>=0 && mClient!=0) {
+ if (isValid()) {
mClient->destroySurface(mToken);
}
+
+ // clear all references and trigger an IPC now, to make sure things
+ // happen without delay, since these resources are quite heavy.
mClient.clear();
mSurface.clear();
- mHeap[0].clear();
- mHeap[1].clear();
IPCThreadState::self()->flushCommands();
}
-sp<Surface> Surface::dup() const
+void SurfaceControl::clear()
{
- Surface const * r = this;
- if (this && mOwner) {
- // the only reason we need to do this is because of Java's garbage
- // collector: because we're creating a copy of the Surface
- // instead of a reference, we can garantee that when our last
- // reference goes away, the real surface will be deleted.
- // Without this hack (the code is correct too), we'd have to
- // wait for a GC for the surface to go away.
- r = new Surface(this);
- }
- return const_cast<Surface*>(r);
+ // here, the window manager tells us explicitly that we should destroy
+ // the surface's resource. Soon after this call, it will also release
+ // its last reference (which will call the dtor); however, it is possible
+ // that a client living in the same process still holds references which
+ // would delay the call to the dtor -- that is why we need this explicit
+ // "clear()" call.
+ destroy();
}
-status_t Surface::nextBuffer(SurfaceInfo* info) {
- return mClient->nextBuffer(this, info);
-}
-
-status_t Surface::lock(SurfaceInfo* info, bool blocking) {
- return Surface::lock(info, NULL, blocking);
-}
-
-status_t Surface::lock(SurfaceInfo* info, Region* dirty, bool blocking) {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->lockSurface(this, info, dirty, blocking);
-}
-
-status_t Surface::unlockAndPost() {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->unlockAndPostSurface(this);
-}
-
-status_t Surface::unlock() {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->unlockSurface(this);
-}
-
-status_t Surface::setLayer(int32_t layer) {
- return mClient->setLayer(this, layer);
-}
-status_t Surface::setPosition(int32_t x, int32_t y) {
- return mClient->setPosition(this, x, y);
-}
-status_t Surface::setSize(uint32_t w, uint32_t h) {
- return mClient->setSize(this, w, h);
-}
-status_t Surface::hide() {
- return mClient->hide(this);
-}
-status_t Surface::show(int32_t layer) {
- return mClient->show(this, layer);
-}
-status_t Surface::freeze() {
- return mClient->freeze(this);
-}
-status_t Surface::unfreeze() {
- return mClient->unfreeze(this);
-}
-status_t Surface::setFlags(uint32_t flags, uint32_t mask) {
- return mClient->setFlags(this, flags, mask);
-}
-status_t Surface::setTransparentRegionHint(const Region& transparent) {
- return mClient->setTransparentRegionHint(this, transparent);
-}
-status_t Surface::setAlpha(float alpha) {
- return mClient->setAlpha(this, alpha);
-}
-status_t Surface::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
- return mClient->setMatrix(this, dsdx, dtdx, dsdy, dtdy);
-}
-status_t Surface::setFreezeTint(uint32_t tint) {
- return mClient->setFreezeTint(this, tint);
-}
-
-Region Surface::dirtyRegion() const {
- return mDirtyRegion;
-}
-void Surface::setDirtyRegion(const Region& region) const {
- mDirtyRegion = region;
-}
-const Rect& Surface::swapRectangle() const {
- return mSwapRectangle;
-}
-void Surface::setSwapRectangle(const Rect& r) {
- mSwapRectangle = r;
-}
-
-sp<Surface> Surface::readFromParcel(Parcel* parcel)
-{
- sp<SurfaceComposerClient> client;
- ISurfaceFlingerClient::surface_data_t data;
- sp<IBinder> clientBinder= parcel->readStrongBinder();
- sp<ISurface> surface = interface_cast<ISurface>(parcel->readStrongBinder());
- data.heap[0] = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
- data.heap[1] = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
- data.token = parcel->readInt32();
- data.identity = parcel->readInt32();
- PixelFormat format = parcel->readInt32();
- uint32_t flags = parcel->readInt32();
-
- if (clientBinder != NULL)
- client = SurfaceComposerClient::clientForConnection(clientBinder);
-
- return new Surface(client, surface, data, 0, 0, format, flags, false);
-}
-
-status_t Surface::writeToParcel(const sp<Surface>& surface, Parcel* parcel)
-{
- uint32_t flags=0;
- uint32_t format=0;
- SurfaceID token = -1;
- uint32_t identity = 0;
- sp<SurfaceComposerClient> client;
- sp<ISurface> sur;
- sp<IMemoryHeap> heap[2];
- if (surface->isValid()) {
- token = surface->mToken;
- identity = surface->mIdentity;
- client = surface->mClient;
- sur = surface->mSurface;
- heap[0] = surface->mHeap[0];
- heap[1] = surface->mHeap[1];
- format = surface->mFormat;
- flags = surface->mFlags;
- }
- parcel->writeStrongBinder(client!=0 ? client->connection() : NULL);
- parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
- parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL);
- parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL);
- parcel->writeInt32(token);
- parcel->writeInt32(identity);
- parcel->writeInt32(format);
- parcel->writeInt32(flags);
- return NO_ERROR;
-}
-
-bool Surface::isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs)
+bool SurfaceControl::isSameSurface(
+ const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs)
{
if (lhs == 0 || rhs == 0)
return false;
return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
}
-void* Surface::heapBase(int i) const
+status_t SurfaceControl::setLayer(int32_t layer) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setLayer(mToken, layer);
+}
+status_t SurfaceControl::setPosition(int32_t x, int32_t y) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setPosition(mToken, x, y);
+}
+status_t SurfaceControl::setSize(uint32_t w, uint32_t h) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setSize(mToken, w, h);
+}
+status_t SurfaceControl::hide() {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->hide(mToken);
+}
+status_t SurfaceControl::show(int32_t layer) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->show(mToken, layer);
+}
+status_t SurfaceControl::freeze() {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->freeze(mToken);
+}
+status_t SurfaceControl::unfreeze() {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->unfreeze(mToken);
+}
+status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setFlags(mToken, flags, mask);
+}
+status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setTransparentRegionHint(mToken, transparent);
+}
+status_t SurfaceControl::setAlpha(float alpha) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setAlpha(mToken, alpha);
+}
+status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setMatrix(mToken, dsdx, dtdx, dsdy, dtdy);
+}
+status_t SurfaceControl::setFreezeTint(uint32_t tint) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setFreezeTint(mToken, tint);
+}
+
+status_t SurfaceControl::validate(SharedClient const* cblk) const
{
- void* heapBase = mSurfaceHeapBase[i];
- // map lazily so it doesn't get mapped in clients that don't need it
- if (heapBase == 0) {
- const sp<IMemoryHeap>& heap(mHeap[i]);
- if (heap != 0) {
- heapBase = static_cast<uint8_t*>(heap->base());
- if (heapBase == MAP_FAILED) {
- heapBase = NULL;
- LOGE("Couldn't map Surface's heap (binder=%p, heap=%p)",
- heap->asBinder().get(), heap.get());
- }
- mSurfaceHeapBase[i] = heapBase;
+ if (mToken<0 || mClient==0) {
+ LOGE("invalid token (%d, identity=%u) or client (%p)",
+ mToken, mIdentity, mClient.get());
+ return NO_INIT;
+ }
+ if (cblk == 0) {
+ LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity);
+ return NO_INIT;
+ }
+ status_t err = cblk->validate(mToken);
+ if (err != NO_ERROR) {
+ LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
+ mToken, mIdentity, err, strerror(-err));
+ return err;
+ }
+ uint32_t identity = cblk->getIdentity(mToken);
+ if (mIdentity != identity) {
+ LOGE("using an invalid surface id=%d, identity=%u should be %d",
+ mToken, mIdentity, identity);
+ return NO_INIT;
+ }
+ return NO_ERROR;
+}
+
+status_t SurfaceControl::writeSurfaceToParcel(
+ const sp<SurfaceControl>& control, Parcel* parcel)
+{
+ uint32_t flags = 0;
+ uint32_t format = 0;
+ SurfaceID token = -1;
+ uint32_t identity = 0;
+ uint32_t width = 0;
+ uint32_t height = 0;
+ sp<SurfaceComposerClient> client;
+ sp<ISurface> sur;
+ if (SurfaceControl::isValid(control)) {
+ token = control->mToken;
+ identity = control->mIdentity;
+ client = control->mClient;
+ sur = control->mSurface;
+ width = control->mWidth;
+ height = control->mHeight;
+ format = control->mFormat;
+ flags = control->mFlags;
+ }
+ parcel->writeStrongBinder(client!=0 ? client->connection() : NULL);
+ parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
+ parcel->writeInt32(token);
+ parcel->writeInt32(identity);
+ parcel->writeInt32(width);
+ parcel->writeInt32(height);
+ parcel->writeInt32(format);
+ parcel->writeInt32(flags);
+ return NO_ERROR;
+}
+
+sp<Surface> SurfaceControl::getSurface() const
+{
+ Mutex::Autolock _l(mLock);
+ if (mSurfaceData == 0) {
+ mSurfaceData = new Surface(const_cast<SurfaceControl*>(this));
+ }
+ return mSurfaceData;
+}
+
+// ============================================================================
+// Surface
+// ============================================================================
+
+Surface::Surface(const sp<SurfaceControl>& surface)
+ : mClient(surface->mClient), mSurface(surface->mSurface),
+ mToken(surface->mToken), mIdentity(surface->mIdentity),
+ mFormat(surface->mFormat), mFlags(surface->mFlags),
+ mBufferMapper(GraphicBufferMapper::get()), mSharedBufferClient(NULL),
+ mWidth(surface->mWidth), mHeight(surface->mHeight)
+{
+ mSharedBufferClient = new SharedBufferClient(
+ mClient->mControl, mToken, 2, mIdentity);
+
+ init();
+}
+
+Surface::Surface(const Parcel& parcel)
+ : mBufferMapper(GraphicBufferMapper::get()), mSharedBufferClient(NULL)
+{
+ sp<IBinder> clientBinder = parcel.readStrongBinder();
+ mSurface = interface_cast<ISurface>(parcel.readStrongBinder());
+ mToken = parcel.readInt32();
+ mIdentity = parcel.readInt32();
+ mWidth = parcel.readInt32();
+ mHeight = parcel.readInt32();
+ mFormat = parcel.readInt32();
+ mFlags = parcel.readInt32();
+
+ // FIXME: what does that mean if clientBinder is NULL here?
+ if (clientBinder != NULL) {
+ mClient = SurfaceComposerClient::clientForConnection(clientBinder);
+
+ mSharedBufferClient = new SharedBufferClient(
+ mClient->mControl, mToken, 2, mIdentity);
+ }
+
+ init();
+}
+
+void Surface::init()
+{
+ android_native_window_t::setSwapInterval = setSwapInterval;
+ android_native_window_t::dequeueBuffer = dequeueBuffer;
+ android_native_window_t::lockBuffer = lockBuffer;
+ android_native_window_t::queueBuffer = queueBuffer;
+ android_native_window_t::query = query;
+ android_native_window_t::perform = perform;
+ mSwapRectangle.makeInvalid();
+ DisplayInfo dinfo;
+ SurfaceComposerClient::getDisplayInfo(0, &dinfo);
+ const_cast<float&>(android_native_window_t::xdpi) = dinfo.xdpi;
+ const_cast<float&>(android_native_window_t::ydpi) = dinfo.ydpi;
+ // FIXME: set real values here
+ const_cast<int&>(android_native_window_t::minSwapInterval) = 1;
+ const_cast<int&>(android_native_window_t::maxSwapInterval) = 1;
+ const_cast<uint32_t&>(android_native_window_t::flags) = 0;
+ // be default we request a hardware surface
+ mUsage = GRALLOC_USAGE_HW_RENDER;
+ mNeedFullUpdate = false;
+}
+
+Surface::~Surface()
+{
+ // this is a client-side operation, the surface is destroyed, unmap
+ // its buffers in this process.
+ for (int i=0 ; i<2 ; i++) {
+ if (mBuffers[i] != 0 && mBuffers[i]->handle != 0) {
+ getBufferMapper().unregisterBuffer(mBuffers[i]->handle);
}
}
- return heapBase;
+
+ // clear all references and trigger an IPC now, to make sure things
+ // happen without delay, since these resources are quite heavy.
+ mClient.clear();
+ mSurface.clear();
+ delete mSharedBufferClient;
+ IPCThreadState::self()->flushCommands();
+}
+
+sp<SurfaceComposerClient> Surface::getClient() const {
+ return mClient;
+}
+
+sp<ISurface> Surface::getISurface() const {
+ return mSurface;
+}
+
+bool Surface::isValid() {
+ return mToken>=0 && mClient!=0;
+}
+
+status_t Surface::validate(SharedClient const* cblk) const
+{
+ sp<SurfaceComposerClient> client(getClient());
+ if (mToken<0 || mClient==0) {
+ LOGE("invalid token (%d, identity=%u) or client (%p)",
+ mToken, mIdentity, client.get());
+ return NO_INIT;
+ }
+ if (cblk == 0) {
+ LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity);
+ return NO_INIT;
+ }
+ status_t err = cblk->validate(mToken);
+ if (err != NO_ERROR) {
+ LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
+ mToken, mIdentity, err, strerror(-err));
+ return err;
+ }
+ uint32_t identity = cblk->getIdentity(mToken);
+ if (mIdentity != identity) {
+ LOGE("using an invalid surface id=%d, identity=%u should be %d",
+ mToken, mIdentity, identity);
+ return NO_INIT;
+ }
+ return NO_ERROR;
+}
+
+
+bool Surface::isSameSurface(
+ const sp<Surface>& lhs, const sp<Surface>& rhs)
+{
+ if (lhs == 0 || rhs == 0)
+ return false;
+
+ return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
+}
+
+// ----------------------------------------------------------------------------
+
+int Surface::setSwapInterval(android_native_window_t* window, int interval) {
+ return 0;
+}
+
+int Surface::dequeueBuffer(android_native_window_t* window,
+ android_native_buffer_t** buffer) {
+ Surface* self = getSelf(window);
+ return self->dequeueBuffer(buffer);
+}
+
+int Surface::lockBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer) {
+ Surface* self = getSelf(window);
+ return self->lockBuffer(buffer);
+}
+
+int Surface::queueBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer) {
+ Surface* self = getSelf(window);
+ return self->queueBuffer(buffer);
+}
+
+int Surface::query(android_native_window_t* window,
+ int what, int* value) {
+ Surface* self = getSelf(window);
+ return self->query(what, value);
+}
+
+int Surface::perform(android_native_window_t* window,
+ int operation, ...) {
+ va_list args;
+ va_start(args, operation);
+ Surface* self = getSelf(window);
+ int res = self->perform(operation, args);
+ va_end(args);
+ return res;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t Surface::dequeueBuffer(sp<GraphicBuffer>* buffer) {
+ android_native_buffer_t* out;
+ status_t err = dequeueBuffer(&out);
+ if (err == NO_ERROR) {
+ *buffer = GraphicBuffer::getSelf(out);
+ }
+ return err;
+}
+
+// ----------------------------------------------------------------------------
+
+
+int Surface::dequeueBuffer(android_native_buffer_t** buffer)
+{
+ sp<SurfaceComposerClient> client(getClient());
+ status_t err = validate(client->mControl);
+ if (err != NO_ERROR)
+ return err;
+
+ ssize_t bufIdx = mSharedBufferClient->dequeue();
+ if (bufIdx < 0) {
+ LOGE("error dequeuing a buffer (%s)", strerror(bufIdx));
+ return bufIdx;
+ }
+
+ // below we make sure we AT LEAST have the usage flags we want
+ const uint32_t usage(getUsage());
+ const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
+ if (backBuffer == 0 ||
+ ((uint32_t(backBuffer->usage) & usage) != usage) ||
+ mSharedBufferClient->needNewBuffer(bufIdx))
+ {
+ err = getBufferLocked(bufIdx, usage);
+ LOGE_IF(err, "getBufferLocked(%ld, %08x) failed (%s)",
+ bufIdx, usage, strerror(-err));
+ if (err == NO_ERROR) {
+ // reset the width/height with the what we get from the buffer
+ mWidth = uint32_t(backBuffer->width);
+ mHeight = uint32_t(backBuffer->height);
+ }
+ }
+
+ // if we still don't have a buffer here, we probably ran out of memory
+ if (!err && backBuffer==0) {
+ err = NO_MEMORY;
+ }
+
+ if (err == NO_ERROR) {
+ mDirtyRegion.set(backBuffer->width, backBuffer->height);
+ *buffer = backBuffer.get();
+ } else {
+ mSharedBufferClient->undoDequeue(bufIdx);
+ }
+
+ return err;
+}
+
+int Surface::lockBuffer(android_native_buffer_t* buffer)
+{
+ sp<SurfaceComposerClient> client(getClient());
+ status_t err = validate(client->mControl);
+ if (err != NO_ERROR)
+ return err;
+
+ int32_t bufIdx = GraphicBuffer::getSelf(buffer)->getIndex();
+ err = mSharedBufferClient->lock(bufIdx);
+ LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err));
+ return err;
+}
+
+int Surface::queueBuffer(android_native_buffer_t* buffer)
+{
+ sp<SurfaceComposerClient> client(getClient());
+ status_t err = validate(client->mControl);
+ if (err != NO_ERROR)
+ return err;
+
+ if (mSwapRectangle.isValid()) {
+ mDirtyRegion.set(mSwapRectangle);
+ }
+
+ int32_t bufIdx = GraphicBuffer::getSelf(buffer)->getIndex();
+ mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
+ err = mSharedBufferClient->queue(bufIdx);
+ LOGE_IF(err, "error queuing buffer %d (%s)", bufIdx, strerror(-err));
+
+ if (err == NO_ERROR) {
+ // FIXME: can we avoid this IPC if we know there is one pending?
+ client->signalServer();
+ }
+ return err;
+}
+
+int Surface::query(int what, int* value)
+{
+ switch (what) {
+ case NATIVE_WINDOW_WIDTH:
+ *value = int(mWidth);
+ return NO_ERROR;
+ case NATIVE_WINDOW_HEIGHT:
+ *value = int(mHeight);
+ return NO_ERROR;
+ case NATIVE_WINDOW_FORMAT:
+ *value = int(mFormat);
+ return NO_ERROR;
+ }
+ return BAD_VALUE;
+}
+
+int Surface::perform(int operation, va_list args)
+{
+ int res = NO_ERROR;
+ switch (operation) {
+ case NATIVE_WINDOW_SET_USAGE:
+ setUsage( va_arg(args, int) );
+ break;
+ default:
+ res = NAME_NOT_FOUND;
+ break;
+ }
+ return res;
+}
+
+void Surface::setUsage(uint32_t reqUsage)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+ mUsage = reqUsage;
+}
+
+uint32_t Surface::getUsage() const
+{
+ Mutex::Autolock _l(mSurfaceLock);
+ return mUsage;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t Surface::lock(SurfaceInfo* info, bool blocking) {
+ return Surface::lock(info, NULL, blocking);
+}
+
+status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
+{
+ if (mApiLock.tryLock() != NO_ERROR) {
+ LOGE("calling Surface::lock() from different threads!");
+ CallStack stack;
+ stack.update();
+ stack.dump("Surface::lock called from different threads");
+ return WOULD_BLOCK;
+ }
+
+ // we're intending to do software rendering from this point
+ setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+
+ sp<GraphicBuffer> backBuffer;
+ status_t err = dequeueBuffer(&backBuffer);
+ LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
+ if (err == NO_ERROR) {
+ err = lockBuffer(backBuffer.get());
+ LOGE_IF(err, "lockBuffer (idx=%d) failed (%s)",
+ backBuffer->getIndex(), strerror(-err));
+ if (err == NO_ERROR) {
+ // we handle copy-back here...
+
+ const Rect bounds(backBuffer->width, backBuffer->height);
+ Region scratch(bounds);
+ Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
+
+ if (mNeedFullUpdate) {
+ // reset newDirtyRegion to bounds when a buffer is reallocated
+ // it would be better if this information was associated with
+ // the buffer and made available to outside of Surface.
+ // This will do for now though.
+ mNeedFullUpdate = false;
+ newDirtyRegion.set(bounds);
+ } else {
+ newDirtyRegion.andSelf(bounds);
+ }
+
+ const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
+ if (frontBuffer !=0 &&
+ backBuffer->width == frontBuffer->width &&
+ backBuffer->height == frontBuffer->height &&
+ !(mFlags & ISurfaceComposer::eDestroyBackbuffer))
+ {
+ const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
+ if (!copyback.isEmpty() && frontBuffer!=0) {
+ // copy front to back
+ copyBlt(backBuffer, frontBuffer, copyback);
+ }
+ }
+
+ mDirtyRegion = newDirtyRegion;
+ mOldDirtyRegion = newDirtyRegion;
+
+ void* vaddr;
+ status_t res = backBuffer->lock(
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ newDirtyRegion.bounds(), &vaddr);
+
+ LOGW_IF(res, "failed locking buffer (handle = %p)",
+ backBuffer->handle);
+
+ mLockedBuffer = backBuffer;
+ other->w = backBuffer->width;
+ other->h = backBuffer->height;
+ other->s = backBuffer->stride;
+ other->usage = backBuffer->usage;
+ other->format = backBuffer->format;
+ other->bits = vaddr;
+ }
+ }
+ mApiLock.unlock();
+ return err;
+}
+
+status_t Surface::unlockAndPost()
+{
+ if (mLockedBuffer == 0) {
+ LOGE("unlockAndPost failed, no locked buffer");
+ return BAD_VALUE;
+ }
+
+ status_t err = mLockedBuffer->unlock();
+ LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
+
+ err = queueBuffer(mLockedBuffer.get());
+ LOGE_IF(err, "queueBuffer (idx=%d) failed (%s)",
+ mLockedBuffer->getIndex(), strerror(-err));
+
+ mPostedBuffer = mLockedBuffer;
+ mLockedBuffer = 0;
+ return err;
+}
+
+void Surface::setSwapRectangle(const Rect& r) {
+ Mutex::Autolock _l(mSurfaceLock);
+ mSwapRectangle = r;
+}
+
+status_t Surface::getBufferLocked(int index, int usage)
+{
+ sp<ISurface> s(mSurface);
+ if (s == 0) return NO_INIT;
+
+ status_t err = NO_MEMORY;
+
+ // free the current buffer
+ sp<GraphicBuffer>& currentBuffer(mBuffers[index]);
+ if (currentBuffer != 0) {
+ getBufferMapper().unregisterBuffer(currentBuffer->handle);
+ currentBuffer.clear();
+ }
+
+ sp<GraphicBuffer> buffer = s->requestBuffer(index, usage);
+ LOGE_IF(buffer==0,
+ "ISurface::getBuffer(%d, %08x) returned NULL",
+ index, usage);
+ if (buffer != 0) { // this should never happen by construction
+ LOGE_IF(buffer->handle == NULL,
+ "Surface (identity=%d) requestBuffer(%d, %08x) returned"
+ "a buffer with a null handle", mIdentity, index, usage);
+ err = mSharedBufferClient->getStatus();
+ LOGE_IF(err, "Surface (identity=%d) state = %d", mIdentity, err);
+ if (!err && buffer->handle != NULL) {
+ err = getBufferMapper().registerBuffer(buffer->handle);
+ LOGW_IF(err, "registerBuffer(...) failed %d (%s)",
+ err, strerror(-err));
+ if (err == NO_ERROR) {
+ currentBuffer = buffer;
+ currentBuffer->setIndex(index);
+ mNeedFullUpdate = true;
+ }
+ } else {
+ err = err<0 ? err : NO_MEMORY;
+ }
+ }
+ return err;
}
}; // namespace android
diff --git a/libs/ui/SurfaceComposerClient.cpp b/libs/ui/SurfaceComposerClient.cpp
index fe803ff..eda84ef 100644
--- a/libs/ui/SurfaceComposerClient.cpp
+++ b/libs/ui/SurfaceComposerClient.cpp
@@ -29,26 +29,19 @@
#include <utils/Errors.h>
#include <utils/threads.h>
#include <utils/KeyedVector.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-#include <utils/IMemory.h>
+#include <binder/IServiceManager.h>
+#include <binder/IMemory.h>
#include <utils/Log.h>
+#include <ui/DisplayInfo.h>
#include <ui/ISurfaceComposer.h>
#include <ui/ISurfaceFlingerClient.h>
#include <ui/ISurface.h>
#include <ui/SurfaceComposerClient.h>
-#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
-#include <ui/Point.h>
-#include <private/ui/SharedState.h>
#include <private/ui/LayerState.h>
-#include <private/ui/SurfaceFlingerSynchro.h>
-
-#include <pixelflinger/pixelflinger.h>
-
-#include <utils/BpBinder.h>
+#include <private/ui/SharedBufferStack.h>
#define VERBOSE(...) ((void)0)
//#define VERBOSE LOGD
@@ -65,42 +58,50 @@
static sp<ISurfaceComposer> gSurfaceManager;
static DefaultKeyedVector< sp<IBinder>, sp<SurfaceComposerClient> > gActiveConnections;
static SortedVector<sp<SurfaceComposerClient> > gOpenTransactions;
-static sp<IMemory> gServerCblkMemory;
+static sp<IMemoryHeap> gServerCblkMemory;
static volatile surface_flinger_cblk_t* gServerCblk;
-const sp<ISurfaceComposer>& _get_surface_manager()
+static sp<ISurfaceComposer> getComposerService()
{
- if (gSurfaceManager != 0) {
- return gSurfaceManager;
- }
-
- sp<IBinder> binder;
- sp<IServiceManager> sm = defaultServiceManager();
- do {
- binder = sm->getService(String16("SurfaceFlinger"));
- if (binder == 0) {
- LOGW("SurfaceFlinger not published, waiting...");
- usleep(500000); // 0.5 s
- }
- } while(binder == 0);
- sp<ISurfaceComposer> sc(interface_cast<ISurfaceComposer>(binder));
-
+ sp<ISurfaceComposer> sc;
Mutex::Autolock _l(gLock);
- if (gSurfaceManager == 0) {
- gSurfaceManager = sc;
+ if (gSurfaceManager != 0) {
+ sc = gSurfaceManager;
+ } else {
+ // release the lock while we're waiting...
+ gLock.unlock();
+
+ sp<IBinder> binder;
+ sp<IServiceManager> sm = defaultServiceManager();
+ do {
+ binder = sm->getService(String16("SurfaceFlinger"));
+ if (binder == 0) {
+ LOGW("SurfaceFlinger not published, waiting...");
+ usleep(500000); // 0.5 s
+ }
+ } while(binder == 0);
+
+ // grab the lock again for updating gSurfaceManager
+ gLock.lock();
+ if (gSurfaceManager == 0) {
+ sc = interface_cast<ISurfaceComposer>(binder);
+ gSurfaceManager = sc;
+ } else {
+ sc = gSurfaceManager;
+ }
}
- return gSurfaceManager;
+ return sc;
}
static volatile surface_flinger_cblk_t const * get_cblk()
{
if (gServerCblk == 0) {
- const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ sp<ISurfaceComposer> sm(getComposerService());
Mutex::Autolock _l(gLock);
if (gServerCblk == 0) {
gServerCblkMemory = sm->getCblk();
LOGE_IF(gServerCblkMemory==0, "Can't get server control block");
- gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->pointer();
+ gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->getBase();
LOGE_IF(gServerCblk==0, "Can't get server control block address");
}
}
@@ -109,210 +110,6 @@
// ---------------------------------------------------------------------------
-static void copyBlt(const GGLSurface& dst,
- const GGLSurface& src, const Region& reg)
-{
- Region::iterator iterator(reg);
- if (iterator) {
- // NOTE: dst and src must be the same format
- Rect r;
- const size_t bpp = bytesPerPixel(src.format);
- const size_t dbpr = dst.stride * bpp;
- const size_t sbpr = src.stride * bpp;
- while (iterator.iterate(&r)) {
- ssize_t h = r.bottom - r.top;
- if (h) {
- size_t size = (r.right - r.left) * bpp;
- uint8_t* s = src.data + (r.left + src.stride * r.top) * bpp;
- uint8_t* d = dst.data + (r.left + dst.stride * r.top) * bpp;
- if (dbpr==sbpr && size==sbpr) {
- size *= h;
- h = 1;
- }
- do {
- memcpy(d, s, size);
- d += dbpr;
- s += sbpr;
- } while (--h > 0);
- }
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-surface_flinger_cblk_t::surface_flinger_cblk_t()
-{
-}
-
-// ---------------------------------------------------------------------------
-
-per_client_cblk_t::per_client_cblk_t()
-{
-}
-
-// these functions are used by the clients
-inline status_t per_client_cblk_t::validate(size_t i) const {
- if (uint32_t(i) >= NUM_LAYERS_MAX)
- return BAD_INDEX;
- if (layers[i].swapState & eInvalidSurface)
- return NO_MEMORY;
- return NO_ERROR;
-}
-
-int32_t per_client_cblk_t::lock_layer(size_t i, uint32_t flags)
-{
- int32_t index;
- uint32_t state;
- int timeout = 0;
- status_t result;
- layer_cblk_t * const layer = layers + i;
- const bool blocking = flags & BLOCKING;
- const bool inspect = flags & INSPECT;
-
- do {
- state = layer->swapState;
-
- if (UNLIKELY((state&(eFlipRequested|eNextFlipPending)) == eNextFlipPending)) {
- LOGE("eNextFlipPending set but eFlipRequested not set, "
- "layer=%d (lcblk=%p), state=%08x",
- int(i), layer, int(state));
- return INVALID_OPERATION;
- }
-
- if (UNLIKELY(state&eLocked)) {
- LOGE("eLocked set when entering lock_layer(), "
- "layer=%d (lcblk=%p), state=%08x",
- int(i), layer, int(state));
- return WOULD_BLOCK;
- }
-
-
- if (state & (eFlipRequested | eNextFlipPending | eResizeRequested
- | eInvalidSurface))
- {
- int32_t resizeIndex;
- Mutex::Autolock _l(lock);
- // might block for a very short amount of time
- // will never cause the server to block (trylock())
-
- goto start_loop_here;
-
- // We block the client if:
- // eNextFlipPending: we've used both buffers already, so we need to
- // wait for one to become availlable.
- // eResizeRequested: the buffer we're going to acquire is being
- // resized. Block until it is done.
- // eFlipRequested && eBusy: the buffer we're going to acquire is
- // currently in use by the server.
- // eInvalidSurface: this is a special case, we don't block in this
- // case, we just return an error.
-
- while((state & (eNextFlipPending|eInvalidSurface)) ||
- (state & ((resizeIndex) ? eResizeBuffer1 : eResizeBuffer0)) ||
- ((state & (eFlipRequested|eBusy)) == (eFlipRequested|eBusy)) )
- {
- if (state & eInvalidSurface)
- return NO_MEMORY;
-
- if (!blocking)
- return WOULD_BLOCK;
-
- timeout = 0;
- result = cv.waitRelative(lock, seconds(1));
- if (__builtin_expect(result!=NO_ERROR, false)) {
- const int newState = layer->swapState;
- LOGW( "lock_layer timed out (is the CPU pegged?) "
- "layer=%d, lcblk=%p, state=%08x (was %08x)",
- int(i), layer, newState, int(state));
- timeout = newState != int(state);
- }
-
- start_loop_here:
- state = layer->swapState;
- resizeIndex = (state&eIndex) ^ ((state&eFlipRequested)>>1);
- }
-
- LOGW_IF(timeout,
- "lock_layer() timed out but didn't appear to need "
- "to be locked and we recovered "
- "(layer=%d, lcblk=%p, state=%08x)",
- int(i), layer, int(state));
- }
-
- // eFlipRequested is not set and cannot be set by another thread: it's
- // safe to use the first buffer without synchronization.
-
- // Choose the index depending on eFlipRequested.
- // When it's set, choose the 'other' buffer.
- index = (state&eIndex) ^ ((state&eFlipRequested)>>1);
-
- // make sure this buffer is valid
- if (layer->surface[index].bits_offset < 0) {
- return status_t(layer->surface[index].bits_offset);
- }
-
- if (inspect) {
- // we just want to inspect this layer. don't lock it.
- goto done;
- }
-
- // last thing before we're done, we need to atomically lock the state
- } while (android_atomic_cmpxchg(state, state|eLocked, &(layer->swapState)));
-
- VERBOSE("locked layer=%d (lcblk=%p), buffer=%d, state=0x%08x",
- int(i), layer, int(index), int(state));
-
- // store the index of the locked buffer (for client use only)
- layer->flags &= ~eBufferIndex;
- layer->flags |= ((index << eBufferIndexShift) & eBufferIndex);
-
-done:
- return index;
-}
-
-uint32_t per_client_cblk_t::unlock_layer_and_post(size_t i)
-{
- // atomically set eFlipRequested and clear eLocked and optionnaly
- // set eNextFlipPending if eFlipRequested was already set
-
- layer_cblk_t * const layer = layers + i;
- int32_t oldvalue, newvalue;
- do {
- oldvalue = layer->swapState;
- // get current value
-
- newvalue = oldvalue & ~eLocked;
- // clear eLocked
-
- newvalue |= eFlipRequested;
- // set eFlipRequested
-
- if (oldvalue & eFlipRequested)
- newvalue |= eNextFlipPending;
- // if eFlipRequested was alread set, set eNextFlipPending
-
- } while (android_atomic_cmpxchg(oldvalue, newvalue, &(layer->swapState)));
-
- VERBOSE("request pageflip for layer=%d, buffer=%d, state=0x%08x",
- int(i), int((layer->flags & eBufferIndex) >> eBufferIndexShift),
- int(newvalue));
-
- // from this point, the server can kick in at anytime and use the first
- // buffer, so we cannot use it anymore, and we must use the 'other'
- // buffer instead (or wait if it is not availlable yet, see lock_layer).
-
- return newvalue;
-}
-
-void per_client_cblk_t::unlock_layer(size_t i)
-{
- layer_cblk_t * const layer = layers + i;
- android_atomic_and(~eLocked, &layer->swapState);
-}
-
-// ---------------------------------------------------------------------------
-
static inline int compare_type( const layer_state_t& lhs,
const layer_state_t& rhs) {
if (lhs.surface < rhs.surface) return -1;
@@ -322,7 +119,7 @@
SurfaceComposerClient::SurfaceComposerClient()
{
- const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ sp<ISurfaceComposer> sm(getComposerService());
if (sm == 0) {
_init(0, 0);
return;
@@ -343,12 +140,20 @@
_init(sm, interface_cast<ISurfaceFlingerClient>(conn));
}
+
+status_t SurfaceComposerClient::linkToComposerDeath(
+ const sp<IBinder::DeathRecipient>& recipient,
+ void* cookie, uint32_t flags)
+{
+ sp<ISurfaceComposer> sm(getComposerService());
+ return sm->asBinder()->linkToDeath(recipient, cookie, flags);
+}
+
void SurfaceComposerClient::_init(
const sp<ISurfaceComposer>& sm, const sp<ISurfaceFlingerClient>& conn)
{
VERBOSE("Creating client %p, conn %p", this, conn.get());
- mSignalServer = 0;
mPrebuiltLayerState = 0;
mTransactionOpen = 0;
mStatus = NO_ERROR;
@@ -360,9 +165,9 @@
return;
}
- mClient->getControlBlocks(&mControlMemory);
- mSignalServer = new SurfaceFlingerSynchro(sm);
- mControl = static_cast<per_client_cblk_t *>(mControlMemory->pointer());
+ mControlMemory = mClient->getControlBlock();
+ mSignalServer = sm;
+ mControl = static_cast<SharedClient *>(mControlMemory->getBase());
}
SurfaceComposerClient::~SurfaceComposerClient()
@@ -376,32 +181,6 @@
return mStatus;
}
-status_t SurfaceComposerClient::validateSurface(
- per_client_cblk_t const* cblk, Surface const * surface)
-{
- SurfaceID index = surface->ID();
- if (cblk == 0) {
- LOGE("cblk is null (surface id=%d, identity=%u)",
- index, surface->getIdentity());
- return NO_INIT;
- }
-
- status_t err = cblk->validate(index);
- if (err != NO_ERROR) {
- LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
- index, surface->getIdentity(), err, strerror(-err));
- return err;
- }
-
- if (surface->getIdentity() != uint32_t(cblk->layers[index].identity)) {
- LOGE("using an invalid surface id=%d, identity=%u should be %d",
- index, surface->getIdentity(), cblk->layers[index].identity);
- return NO_INIT;
- }
-
- return NO_ERROR;
-}
-
sp<IBinder> SurfaceComposerClient::connection() const
{
return (mClient != 0) ? mClient->asBinder() : 0;
@@ -419,7 +198,7 @@
if (client == 0) {
// Need to make a new client.
- const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ sp<ISurfaceComposer> sm(getComposerService());
client = new SurfaceComposerClient(sm, conn);
if (client != 0 && client->initCheck() == NO_ERROR) {
Mutex::Autolock _l(gLock);
@@ -437,15 +216,13 @@
{
// this can be called more than once.
- sp<IMemory> controlMemory;
+ sp<IMemoryHeap> controlMemory;
sp<ISurfaceFlingerClient> client;
- sp<IMemoryHeap> surfaceHeap;
{
Mutex::Autolock _lg(gLock);
Mutex::Autolock _lm(mLock);
- delete mSignalServer;
mSignalServer = 0;
if (mClient != 0) {
@@ -462,9 +239,7 @@
delete mPrebuiltLayerState;
mPrebuiltLayerState = 0;
controlMemory = mControlMemory;
- surfaceHeap = mSurfaceHeap;
mControlMemory.clear();
- mSurfaceHeap.clear();
mControl = 0;
mStatus = NO_INIT;
}
@@ -528,7 +303,13 @@
return n;
}
-sp<Surface> SurfaceComposerClient::createSurface(
+
+void SurfaceComposerClient::signalServer()
+{
+ mSignalServer->signal();
+}
+
+sp<SurfaceControl> SurfaceComposerClient::createSurface(
int pid,
DisplayID display,
uint32_t w,
@@ -536,14 +317,14 @@
PixelFormat format,
uint32_t flags)
{
- sp<Surface> result;
+ sp<SurfaceControl> result;
if (mStatus == NO_ERROR) {
ISurfaceFlingerClient::surface_data_t data;
sp<ISurface> surface = mClient->createSurface(&data, pid,
display, w, h, format, flags);
if (surface != 0) {
if (uint32_t(data.token) < NUM_LAYERS_MAX) {
- result = new Surface(this, surface, data, w, h, format, flags);
+ result = new SurfaceControl(this, surface, data, w, h, format, flags);
}
}
}
@@ -568,186 +349,6 @@
return err;
}
-status_t SurfaceComposerClient::nextBuffer(Surface* surface,
- Surface::SurfaceInfo* info)
-{
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- int32_t backIdx = surface->mBackbufferIndex;
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- const surface_info_t* const front = lcblk->surface + (1-backIdx);
- info->w = front->w;
- info->h = front->h;
- info->format = front->format;
- info->base = surface->heapBase(1-backIdx);
- info->bits = reinterpret_cast<void*>(intptr_t(info->base) + front->bits_offset);
- info->bpr = front->bpr;
-
- return 0;
-}
-
-status_t SurfaceComposerClient::lockSurface(
- Surface* surface,
- Surface::SurfaceInfo* other,
- Region* dirty,
- bool blocking)
-{
- Mutex::Autolock _l(surface->getLock());
-
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- int32_t backIdx = cblk->lock_layer(size_t(index),
- per_client_cblk_t::BLOCKING);
- if (backIdx >= 0) {
- surface->mBackbufferIndex = backIdx;
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- const surface_info_t* const back = lcblk->surface + backIdx;
- const surface_info_t* const front = lcblk->surface + (1-backIdx);
- other->w = back->w;
- other->h = back->h;
- other->format = back->format;
- other->base = surface->heapBase(backIdx);
- other->bits = reinterpret_cast<void*>(intptr_t(other->base) + back->bits_offset);
- other->bpr = back->bpr;
-
- const Rect bounds(other->w, other->h);
- Region newDirtyRegion;
-
- if (back->flags & surface_info_t::eBufferDirty) {
- /* it is safe to write *back here, because we're guaranteed
- * SurfaceFlinger is not touching it (since it just granted
- * access to us) */
- const_cast<surface_info_t*>(back)->flags &=
- ~surface_info_t::eBufferDirty;
-
- // content is meaningless in this case and the whole surface
- // needs to be redrawn.
-
- newDirtyRegion.set(bounds);
- if (dirty) {
- *dirty = newDirtyRegion;
- }
-
- //if (bytesPerPixel(other->format) == 4) {
- // android_memset32(
- // (uint32_t*)other->bits, 0xFF00FF00, other->h * other->bpr);
- //} else {
- // android_memset16( // fill with green
- // (uint16_t*)other->bits, 0x7E0, other->h * other->bpr);
- //}
- }
- else
- {
- if (dirty) {
- dirty->andSelf(Region(bounds));
- newDirtyRegion = *dirty;
- } else {
- newDirtyRegion.set(bounds);
- }
-
- Region copyback;
- if (!(lcblk->flags & eNoCopyBack)) {
- const Region previousDirtyRegion(surface->dirtyRegion());
- copyback = previousDirtyRegion.subtract(newDirtyRegion);
- }
-
- if (!copyback.isEmpty()) {
- // copy front to back
- GGLSurface cb;
- cb.version = sizeof(GGLSurface);
- cb.width = back->w;
- cb.height = back->h;
- cb.stride = back->stride;
- cb.data = (GGLubyte*)surface->heapBase(backIdx);
- cb.data += back->bits_offset;
- cb.format = back->format;
-
- GGLSurface t;
- t.version = sizeof(GGLSurface);
- t.width = front->w;
- t.height = front->h;
- t.stride = front->stride;
- t.data = (GGLubyte*)surface->heapBase(1-backIdx);
- t.data += front->bits_offset;
- t.format = front->format;
-
- //const Region copyback(lcblk->region + 1-backIdx);
- copyBlt(cb, t, copyback);
- }
- }
-
- // update dirty region
- surface->setDirtyRegion(newDirtyRegion);
- }
- return (backIdx < 0) ? status_t(backIdx) : status_t(NO_ERROR);
-}
-
-void SurfaceComposerClient::_signal_server()
-{
- mSignalServer->signal();
-}
-
-void SurfaceComposerClient::_send_dirty_region(
- layer_cblk_t* lcblk, const Region& dirty)
-{
- const int32_t index = (lcblk->flags & eBufferIndex) >> eBufferIndexShift;
- flat_region_t* flat_region = lcblk->region + index;
- status_t err = dirty.write(flat_region, sizeof(flat_region_t));
- if (err < NO_ERROR) {
- // region doesn't fit, use the bounds
- const Region reg(dirty.bounds());
- reg.write(flat_region, sizeof(flat_region_t));
- }
-}
-
-status_t SurfaceComposerClient::unlockAndPostSurface(Surface* surface)
-{
- Mutex::Autolock _l(surface->getLock());
-
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- Region dirty(surface->dirtyRegion());
- const Rect& swapRect(surface->swapRectangle());
- if (swapRect.isValid()) {
- dirty.set(swapRect);
- }
-
- // transmit the dirty region
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- _send_dirty_region(lcblk, dirty);
- uint32_t newstate = cblk->unlock_layer_and_post(size_t(index));
- if (!(newstate & eNextFlipPending))
- _signal_server();
- return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::unlockSurface(Surface* surface)
-{
- Mutex::Autolock _l(surface->getLock());
-
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- cblk->unlock_layer(size_t(index));
- return NO_ERROR;
-}
-
void SurfaceComposerClient::openGlobalTransaction()
{
Mutex::Autolock _l(gLock);
@@ -789,34 +390,33 @@
const size_t N = clients.size();
VERBOSE("closeGlobalTransaction (%ld clients)", N);
- if (N == 1) {
- clients[0]->closeTransaction();
- } else {
- const sp<ISurfaceComposer>& sm(_get_surface_manager());
- sm->openGlobalTransaction();
- for (size_t i=0; i<N; i++) {
- clients[i]->closeTransaction();
- }
- sm->closeGlobalTransaction();
+
+ sp<ISurfaceComposer> sm(getComposerService());
+ sm->openGlobalTransaction();
+ for (size_t i=0; i<N; i++) {
+ clients[i]->closeTransaction();
}
+ sm->closeGlobalTransaction();
+
}
+
status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags)
{
- const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ sp<ISurfaceComposer> sm(getComposerService());
return sm->freezeDisplay(dpy, flags);
}
status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags)
{
- const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ sp<ISurfaceComposer> sm(getComposerService());
return sm->unfreezeDisplay(dpy, flags);
}
int SurfaceComposerClient::setOrientation(DisplayID dpy,
int orientation, uint32_t flags)
{
- const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ sp<ISurfaceComposer> sm(getComposerService());
return sm->setOrientation(dpy, orientation, flags);
}
@@ -866,14 +466,8 @@
return NO_ERROR;
}
-layer_state_t* SurfaceComposerClient::_get_state_l(const sp<Surface>& surface)
+layer_state_t* SurfaceComposerClient::_get_state_l(SurfaceID index)
{
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface.get());
- if (err != NO_ERROR)
- return 0;
-
// API usage error, do nothing.
if (mTransactionOpen<=0) {
LOGE("Not in transaction (client=%p, SurfaceID=%d, mTransactionOpen=%d",
@@ -892,11 +486,11 @@
return mStates.editArray() + i;
}
-layer_state_t* SurfaceComposerClient::_lockLayerState(const sp<Surface>& surface)
+layer_state_t* SurfaceComposerClient::_lockLayerState(SurfaceID id)
{
layer_state_t* s;
mLock.lock();
- s = _get_state_l(surface);
+ s = _get_state_l(id);
if (!s) mLock.unlock();
return s;
}
@@ -906,9 +500,9 @@
mLock.unlock();
}
-status_t SurfaceComposerClient::setPosition(Surface* surface, int32_t x, int32_t y)
+status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::ePositionChanged;
s->x = x;
@@ -917,9 +511,9 @@
return NO_ERROR;
}
-status_t SurfaceComposerClient::setSize(Surface* surface, uint32_t w, uint32_t h)
+status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eSizeChanged;
s->w = w;
@@ -928,9 +522,9 @@
return NO_ERROR;
}
-status_t SurfaceComposerClient::setLayer(Surface* surface, int32_t z)
+status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eLayerChanged;
s->z = z;
@@ -938,32 +532,32 @@
return NO_ERROR;
}
-status_t SurfaceComposerClient::hide(Surface* surface)
+status_t SurfaceComposerClient::hide(SurfaceID id)
{
- return setFlags(surface, ISurfaceComposer::eLayerHidden,
+ return setFlags(id, ISurfaceComposer::eLayerHidden,
ISurfaceComposer::eLayerHidden);
}
-status_t SurfaceComposerClient::show(Surface* surface, int32_t)
+status_t SurfaceComposerClient::show(SurfaceID id, int32_t)
{
- return setFlags(surface, 0, ISurfaceComposer::eLayerHidden);
+ return setFlags(id, 0, ISurfaceComposer::eLayerHidden);
}
-status_t SurfaceComposerClient::freeze(Surface* surface)
+status_t SurfaceComposerClient::freeze(SurfaceID id)
{
- return setFlags(surface, ISurfaceComposer::eLayerFrozen,
+ return setFlags(id, ISurfaceComposer::eLayerFrozen,
ISurfaceComposer::eLayerFrozen);
}
-status_t SurfaceComposerClient::unfreeze(Surface* surface)
+status_t SurfaceComposerClient::unfreeze(SurfaceID id)
{
- return setFlags(surface, 0, ISurfaceComposer::eLayerFrozen);
+ return setFlags(id, 0, ISurfaceComposer::eLayerFrozen);
}
-status_t SurfaceComposerClient::setFlags(Surface* surface,
+status_t SurfaceComposerClient::setFlags(SurfaceID id,
uint32_t flags, uint32_t mask)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eVisibilityChanged;
s->flags &= ~mask;
@@ -973,11 +567,10 @@
return NO_ERROR;
}
-
status_t SurfaceComposerClient::setTransparentRegionHint(
- Surface* surface, const Region& transparentRegion)
+ SurfaceID id, const Region& transparentRegion)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eTransparentRegionChanged;
s->transparentRegion = transparentRegion;
@@ -985,9 +578,9 @@
return NO_ERROR;
}
-status_t SurfaceComposerClient::setAlpha(Surface* surface, float alpha)
+status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eAlphaChanged;
s->alpha = alpha;
@@ -996,11 +589,11 @@
}
status_t SurfaceComposerClient::setMatrix(
- Surface* surface,
+ SurfaceID id,
float dsdx, float dtdx,
float dsdy, float dtdy )
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eMatrixChanged;
layer_state_t::matrix22_t matrix;
@@ -1013,9 +606,9 @@
return NO_ERROR;
}
-status_t SurfaceComposerClient::setFreezeTint(Surface* surface, uint32_t tint)
+status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eFreezeTintChanged;
s->tint = tint;
diff --git a/libs/ui/SurfaceFlingerSynchro.cpp b/libs/ui/SurfaceFlingerSynchro.cpp
deleted file mode 100644
index 5cd9755..0000000
--- a/libs/ui/SurfaceFlingerSynchro.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * 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 "SurfaceFlingerSynchro"
-
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <utils/IPCThreadState.h>
-#include <utils/Log.h>
-
-#include <private/ui/SurfaceFlingerSynchro.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-SurfaceFlingerSynchro::Barrier::Barrier()
- : state(CLOSED) {
-}
-
-SurfaceFlingerSynchro::Barrier::~Barrier() {
-}
-
-void SurfaceFlingerSynchro::Barrier::open() {
- asm volatile ("":::"memory");
- Mutex::Autolock _l(lock);
- state = OPENED;
- cv.broadcast();
-}
-
-void SurfaceFlingerSynchro::Barrier::close() {
- Mutex::Autolock _l(lock);
- state = CLOSED;
-}
-
-void SurfaceFlingerSynchro::Barrier::waitAndClose()
-{
- Mutex::Autolock _l(lock);
- while (state == CLOSED) {
- // we're about to wait, flush the binder command buffer
- IPCThreadState::self()->flushCommands();
- cv.wait(lock);
- }
- state = CLOSED;
-}
-
-status_t SurfaceFlingerSynchro::Barrier::waitAndClose(nsecs_t timeout)
-{
- Mutex::Autolock _l(lock);
- while (state == CLOSED) {
- // we're about to wait, flush the binder command buffer
- IPCThreadState::self()->flushCommands();
- int err = cv.waitRelative(lock, timeout);
- if (err != 0)
- return err;
- }
- state = CLOSED;
- return NO_ERROR;
-}
-
-// ---------------------------------------------------------------------------
-
-SurfaceFlingerSynchro::SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger)
- : mSurfaceComposer(flinger)
-{
-}
-
-SurfaceFlingerSynchro::SurfaceFlingerSynchro()
-{
-}
-
-SurfaceFlingerSynchro::~SurfaceFlingerSynchro()
-{
-}
-
-status_t SurfaceFlingerSynchro::signal()
-{
- mSurfaceComposer->signal();
- return NO_ERROR;
-}
-
-status_t SurfaceFlingerSynchro::wait()
-{
- mBarrier.waitAndClose();
- return NO_ERROR;
-}
-
-status_t SurfaceFlingerSynchro::wait(nsecs_t timeout)
-{
- if (timeout == 0)
- return SurfaceFlingerSynchro::wait();
- return mBarrier.waitAndClose(timeout);
-}
-
-void SurfaceFlingerSynchro::open()
-{
- mBarrier.open();
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
new file mode 100644
index 0000000..6cc4a5a
--- /dev/null
+++ b/libs/ui/tests/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ region.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libui
+
+LOCAL_MODULE:= test-region
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libs/ui/tests/region.cpp b/libs/ui/tests/region.cpp
new file mode 100644
index 0000000..ef15de9
--- /dev/null
+++ b/libs/ui/tests/region.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Region"
+
+#include <stdio.h>
+#include <utils/Debug.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+using namespace android;
+
+int main()
+{
+ Region empty;
+ Region reg0( Rect( 0, 0, 100, 100 ) );
+ Region reg1 = reg0;
+ Region reg2, reg3;
+
+ Region reg4 = empty | reg1;
+ Region reg5 = reg1 | empty;
+
+ reg4.dump("reg4");
+ reg5.dump("reg5");
+
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+
+ reg0 = reg0 | reg0.translate(150, 0);
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+
+ reg0 = reg0 | reg0.translate(300, 0);
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+
+ //reg2 = reg0 | reg0.translate(0, 100);
+ //reg0.dump("reg0");
+ //reg1.dump("reg1");
+ //reg2.dump("reg2");
+
+ //reg3 = reg0 | reg0.translate(0, 150);
+ //reg0.dump("reg0");
+ //reg1.dump("reg1");
+ //reg2.dump("reg2");
+ //reg3.dump("reg3");
+
+ LOGD("---");
+ reg2 = reg0 | reg0.translate(100, 0);
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+ reg2.dump("reg2");
+
+ return 0;
+}
+