diff options
Diffstat (limited to 'libs/surfaceflinger/DisplayHardware')
4 files changed, 931 insertions, 0 deletions
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp new file mode 100644 index 0000000..5dd9446 --- /dev/null +++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "SurfaceFlinger" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <GLES/egl.h> + +#include <utils/Log.h> + +#include <ui/EGLDisplaySurface.h> + +#include "DisplayHardware/DisplayHardware.h" +#include "ui/BlitHardware.h" + +using namespace android; + +static __attribute__((noinline)) +const char *egl_strerror(EGLint err) +{ + switch (err){ + case EGL_SUCCESS: return "EGL_SUCCESS"; + case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED"; + case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS"; + case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC"; + case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE"; + case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG"; + case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT"; + case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE"; + case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; + case EGL_BAD_MATCH: return "EGL_BAD_MATCH"; + case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP"; + case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW"; + case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER"; + case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE"; + case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST"; + default: return "UNKNOWN"; + } +} + +static __attribute__((noinline)) +void checkGLErrors() +{ + GLenum error = glGetError(); + if (error != GL_NO_ERROR) + LOGE("GL error 0x%04x", int(error)); +} + +static __attribute__((noinline)) +void checkEGLErrors(const char* token) +{ + EGLint error = eglGetError(); + // GLESonGL seems to be returning 0 when there is no errors? + if (error && error != EGL_SUCCESS) + LOGE("%s error 0x%04x (%s)", + token, int(error), egl_strerror(error)); +} + + +/* + * Initialize the display to the specified values. + * + */ + +DisplayHardware::DisplayHardware( + const sp<SurfaceFlinger>& flinger, + uint32_t dpy) + : DisplayHardwareBase(flinger, dpy) +{ + init(dpy); +} + +DisplayHardware::~DisplayHardware() +{ + fini(); +} + +float DisplayHardware::getDpiX() const { return mDpiX; } +float DisplayHardware::getDpiY() const { return mDpiY; } +float DisplayHardware::getRefreshRate() const { return mRefreshRate; } + +int DisplayHardware::getWidth() const { + return mWidth; +} +int DisplayHardware::getHeight() const { + return mHeight; +} +PixelFormat DisplayHardware::getFormat() const { + return mFormat; +} + +void DisplayHardware::init(uint32_t dpy) +{ + // initialize EGL + const EGLint attribs[] = { + EGL_RED_SIZE, 5, + EGL_GREEN_SIZE, 6, + EGL_BLUE_SIZE, 5, + EGL_DEPTH_SIZE, 0, + EGL_NONE + }; + EGLint w, h, dummy; + EGLint numConfigs, n; + EGLConfig config; + EGLSurface surface; + EGLContext context; + mFlags = 0; + + // TODO: all the extensions below should be queried through + // eglGetProcAddress(). + + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(display, NULL, NULL); + eglGetConfigs(display, NULL, 0, &numConfigs); + eglChooseConfig(display, attribs, &config, 1, &n); + + /* + * Gather EGL extensions + */ + + const char* const egl_extensions = eglQueryString( + display, EGL_EXTENSIONS); + + const char* egl_extensions_config = egl_extensions; + + if (strstr(egl_extensions, "EGL_ANDROID_query_string_config")) { + egl_extensions_config = eglQueryStringConfigANDROID( + display, config, EGL_EXTENSIONS); + } + + LOGI("EGL informations:"); + LOGI("# of configs : %d", numConfigs); + LOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); + LOGI("version : %s", eglQueryString(display, EGL_VERSION)); + LOGI("extensions: %s", egl_extensions); + LOGI("ext/config: %s", egl_extensions_config); + LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); + + if (strstr(egl_extensions_config, "EGL_ANDROID_swap_rectangle")) { + mFlags |= SWAP_RECTANGLE_EXTENSION; + // TODO: get the real "update_on_demand" behavior + mFlags |= UPDATE_ON_DEMAND; + } + if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) { + if (dummy == EGL_SLOW_CONFIG) + mFlags |= SLOW_CONFIG; + } + + /* + * Create our main surface + */ + + mDisplaySurface = new EGLDisplaySurface(); + + surface = eglCreateWindowSurface(display, config, mDisplaySurface.get(), NULL); + //checkEGLErrors("eglCreateDisplaySurfaceANDROID"); + + if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) { + if (dummy == EGL_BUFFER_PRESERVED) { + mFlags |= BUFFER_PRESERVED; + if (strstr(egl_extensions_config, "EGL_ANDROID_copy_front_to_back")) { + mFlags |= COPY_BACK_EXTENSION; + } + } + } + + GLint value = EGL_UNKNOWN; + eglQuerySurface(display, surface, EGL_HORIZONTAL_RESOLUTION, &value); + if (value == EGL_UNKNOWN) { + mDpiX = 160.0f; + } else { + mDpiX = 25.4f * float(value)/EGL_DISPLAY_SCALING; + } + value = EGL_UNKNOWN; + eglQuerySurface(display, surface, EGL_VERTICAL_RESOLUTION, &value); + if (value == EGL_UNKNOWN) { + mDpiY = 160.0f; + } else { + mDpiY = 25.4f * float(value)/EGL_DISPLAY_SCALING; + } + mRefreshRate = 60.f; // TODO: get the real refresh rate + + /* + * Create our OpenGL ES context + */ + + context = eglCreateContext(display, config, NULL, NULL); + //checkEGLErrors("eglCreateContext"); + + eglQuerySurface(display, surface, EGL_WIDTH, &mWidth); + eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight); + + + /* + * Gather OpenGL ES extensions + */ + + eglMakeCurrent(display, surface, surface, context); + const char* const gl_extensions = (const char*)glGetString(GL_EXTENSIONS); + LOGI("OpenGL informations:"); + LOGI("vendor : %s", glGetString(GL_VENDOR)); + LOGI("renderer : %s", glGetString(GL_RENDERER)); + LOGI("version : %s", glGetString(GL_VERSION)); + LOGI("extensions: %s", gl_extensions); + + if (strstr(gl_extensions, "GL_ARB_texture_non_power_of_two")) { + mFlags |= NPOT_EXTENSION; + } + if (strstr(gl_extensions, "GL_OES_draw_texture")) { + mFlags |= DRAW_TEXTURE_EXTENSION; + } + if (strstr(gl_extensions, "GL_ANDROID_direct_texture")) { + mFlags |= DIRECT_TEXTURE; + } + + // Unbind the context from this thread + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + mDisplay = display; + mConfig = config; + mSurface = surface; + mContext = context; + mFormat = GGL_PIXEL_FORMAT_RGB_565; + + mBlitEngine = copybit_init(); +} + +/* + * Clean up. Throw out our local state. + * + * (It's entirely possible we'll never get here, since this is meant + * for real hardware, which doesn't restart.) + */ + +void DisplayHardware::fini() +{ + eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglTerminate(mDisplay); + copybit_term(mBlitEngine); +} + +void DisplayHardware::releaseScreen() const +{ + DisplayHardwareBase::releaseScreen(); +} + +void DisplayHardware::acquireScreen() const +{ + DisplayHardwareBase::acquireScreen(); +} + +void DisplayHardware::getDisplaySurface(copybit_image_t* img) const +{ + img->w = mDisplaySurface->stride; + img->h = mDisplaySurface->height; + img->format = mDisplaySurface->format; + img->offset = mDisplaySurface->offset; + img->base = (void*)mDisplaySurface->base; + img->fd = mDisplaySurface->fd; +} + +void DisplayHardware::getDisplaySurface(GGLSurface* fb) const +{ + fb->version= sizeof(GGLSurface); + fb->width = mDisplaySurface->width; + fb->height = mDisplaySurface->height; + fb->stride = mDisplaySurface->stride; + fb->format = mDisplaySurface->format; + fb->data = (GGLubyte*)mDisplaySurface->base + mDisplaySurface->offset; +} + +uint32_t DisplayHardware::getPageFlipCount() const { + return mDisplaySurface->getPageFlipCount(); +} + +/* + * "Flip" the front and back buffers. + */ + +void DisplayHardware::flip(const Region& dirty) const +{ + checkGLErrors(); + + EGLDisplay dpy = mDisplay; + EGLSurface surface = mSurface; + + Region newDirty(dirty); + newDirty.andSelf(Rect(mWidth, mHeight)); + + if (mFlags & BUFFER_PRESERVED) { + const Region copyback(mDirty.subtract(newDirty)); + mDirty = newDirty; + mDisplaySurface->copyFrontToBack(copyback); + } + + if (mFlags & SWAP_RECTANGLE_EXTENSION) { + const Rect& b(newDirty.bounds()); + eglSwapRectangleANDROID( + dpy, surface, + b.left, b.top, b.width(), b.height()); + } + + eglSwapBuffers(dpy, surface); + checkEGLErrors("eglSwapBuffers"); + + // for debugging + //glClearColor(1,0,0,0); + //glClear(GL_COLOR_BUFFER_BIT); +} + +uint32_t DisplayHardware::getFlags() const +{ + return mFlags; +} + +void DisplayHardware::makeCurrent() const +{ + eglMakeCurrent(mDisplay, mSurface, mSurface, mContext); +} diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h new file mode 100644 index 0000000..299e236 --- /dev/null +++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DISPLAY_HARDWARE_H +#define ANDROID_DISPLAY_HARDWARE_H + +#include <stdlib.h> + +#include <ui/PixelFormat.h> +#include <ui/Region.h> + +#include <GLES/egl.h> + +#include "DisplayHardware/DisplayHardwareBase.h" + +struct copybit_image_t; +struct copybit_t; + +namespace android { + +class EGLDisplaySurface; + +class DisplayHardware : public DisplayHardwareBase +{ +public: + enum { + COPY_BACK_EXTENSION = 0x00000001, + DIRECT_TEXTURE = 0x00000002, + SWAP_RECTANGLE_EXTENSION= 0x00000004, + COPY_BITS_EXTENSION = 0x00000008, + NPOT_EXTENSION = 0x00000100, + DRAW_TEXTURE_EXTENSION = 0x00000200, + BUFFER_PRESERVED = 0x00010000, + UPDATE_ON_DEMAND = 0x00020000, // video driver feature + SLOW_CONFIG = 0x00040000, // software + }; + + DisplayHardware( + const sp<SurfaceFlinger>& flinger, + uint32_t displayIndex); + + ~DisplayHardware(); + + void releaseScreen() const; + void acquireScreen() const; + + // Flip the front and back buffers if the back buffer is "dirty". Might + // be instantaneous, might involve copying the frame buffer around. + void flip(const Region& dirty) const; + + float getDpiX() const; + float getDpiY() const; + float getRefreshRate() const; + int getWidth() const; + int getHeight() const; + PixelFormat getFormat() const; + uint32_t getFlags() const; + void makeCurrent() const; + + uint32_t getPageFlipCount() const; + void getDisplaySurface(copybit_image_t* img) const; + void getDisplaySurface(GGLSurface* fb) const; + EGLDisplay getEGLDisplay() const { return mDisplay; } + copybit_t* getBlitEngine() const { return mBlitEngine; } + + Rect bounds() const { + return Rect(mWidth, mHeight); + } + +private: + void init(uint32_t displayIndex) __attribute__((noinline)); + void fini() __attribute__((noinline)); + + EGLDisplay mDisplay; + EGLSurface mSurface; + EGLContext mContext; + EGLConfig mConfig; + float mDpiX; + float mDpiY; + float mRefreshRate; + int mWidth; + int mHeight; + PixelFormat mFormat; + uint32_t mFlags; + mutable Region mDirty; + sp<EGLDisplaySurface> mDisplaySurface; + copybit_t* mBlitEngine; +}; + +}; // namespace android + +#endif // ANDROID_DISPLAY_HARDWARE_H diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp new file mode 100644 index 0000000..90f6287 --- /dev/null +++ b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp @@ -0,0 +1,395 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "SurfaceFlinger" + +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <unistd.h> +#include <fcntl.h> +#include <signal.h> +#include <termios.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/resource.h> + +#include <linux/unistd.h> + +#include <utils/Log.h> + +#include "DisplayHardware/DisplayHardwareBase.h" +#include "SurfaceFlinger.h" + +// ---------------------------------------------------------------------------- +// the sim build doesn't have gettid + +#ifndef HAVE_GETTID +# define gettid getpid +#endif + +// ---------------------------------------------------------------------------- +namespace android { + +static char const * const kSleepFileName = "/sys/android_power/wait_for_fb_sleep"; +static char const * const kWakeFileName = "/sys/android_power/wait_for_fb_wake"; + +// This dir exists if the framebuffer console is present, either built into +// the kernel or loaded as a module. +static char const * const kFbconSysDir = "/sys/class/graphics/fbcon"; + +// ---------------------------------------------------------------------------- + +DisplayHardwareBase::DisplayEventThreadBase::DisplayEventThreadBase( + const sp<SurfaceFlinger>& flinger) + : Thread(false), mFlinger(flinger) { +} + +DisplayHardwareBase::DisplayEventThreadBase::~DisplayEventThreadBase() { +} + +// ---------------------------------------------------------------------------- + +DisplayHardwareBase::DisplayEventThread::DisplayEventThread( + const sp<SurfaceFlinger>& flinger) + : DisplayEventThreadBase(flinger) +{ +} + +DisplayHardwareBase::DisplayEventThread::~DisplayEventThread() +{ +} + +bool DisplayHardwareBase::DisplayEventThread::threadLoop() +{ + int err = 0; + char buf; + int fd; + + fd = open(kSleepFileName, O_RDONLY, 0); + do { + err = read(fd, &buf, 1); + } while (err < 0 && errno == EINTR); + close(fd); + LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno)); + if (err >= 0) { + sp<SurfaceFlinger> flinger = mFlinger.promote(); + LOGD("About to give-up screen, flinger = %p", flinger.get()); + if (flinger != 0) { + mBarrier.close(); + flinger->screenReleased(0); + mBarrier.wait(); + } + } + fd = open(kWakeFileName, O_RDONLY, 0); + do { + err = read(fd, &buf, 1); + } while (err < 0 && errno == EINTR); + close(fd); + LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno)); + if (err >= 0) { + sp<SurfaceFlinger> flinger = mFlinger.promote(); + LOGD("Screen about to return, flinger = %p", flinger.get()); + if (flinger != 0) + flinger->screenAcquired(0); + } + return true; +} + +status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const +{ + mBarrier.open(); + return NO_ERROR; +} + +status_t DisplayHardwareBase::DisplayEventThread::readyToRun() +{ + if (access(kSleepFileName, R_OK) || access(kWakeFileName, R_OK)) { + LOGE("Couldn't open %s or %s", kSleepFileName, kWakeFileName); + return NO_INIT; + } + return NO_ERROR; +} + +status_t DisplayHardwareBase::DisplayEventThread::initCheck() const +{ + return (access(kSleepFileName, R_OK) == 0 && + access(kWakeFileName, R_OK) == 0 && + access(kFbconSysDir, F_OK) != 0) ? NO_ERROR : NO_INIT; +} + +// ---------------------------------------------------------------------------- + +pid_t DisplayHardwareBase::ConsoleManagerThread::sSignalCatcherPid = 0; + +DisplayHardwareBase::ConsoleManagerThread::ConsoleManagerThread( + const sp<SurfaceFlinger>& flinger) + : DisplayEventThreadBase(flinger), consoleFd(-1) +{ + sSignalCatcherPid = 0; + + // create a new console + char const * const ttydev = "/dev/tty0"; + int fd = open(ttydev, O_RDWR | O_SYNC); + if (fd<0) { + LOGE("Can't open %s", ttydev); + this->consoleFd = -errno; + return; + } + + // to make sure that we are in text mode + int res = ioctl(fd, KDSETMODE, (void*) KD_TEXT); + if (res<0) { + LOGE("ioctl(%d, KDSETMODE, ...) failed, res %d (%s)", + fd, res, strerror(errno)); + } + + // get the current console + struct vt_stat vs; + res = ioctl(fd, VT_GETSTATE, &vs); + if (res<0) { + LOGE("ioctl(%d, VT_GETSTATE, ...) failed, res %d (%s)", + fd, res, strerror(errno)); + this->consoleFd = -errno; + return; + } + + // switch to console 7 (which is what X normaly uses) + int vtnum = 7; + do { + res = ioctl(fd, VT_ACTIVATE, (void*)vtnum); + } while(res < 0 && errno == EINTR); + if (res<0) { + LOGE("ioctl(%d, VT_ACTIVATE, ...) failed, %d (%s) for %d", + fd, errno, strerror(errno), vtnum); + this->consoleFd = -errno; + return; + } + + do { + res = ioctl(fd, VT_WAITACTIVE, (void*)vtnum); + } while(res < 0 && errno == EINTR); + if (res<0) { + LOGE("ioctl(%d, VT_WAITACTIVE, ...) failed, %d %d %s for %d", + fd, res, errno, strerror(errno), vtnum); + this->consoleFd = -errno; + return; + } + + // open the new console + close(fd); + fd = open(ttydev, O_RDWR | O_SYNC); + if (fd<0) { + LOGE("Can't open new console %s", ttydev); + this->consoleFd = -errno; + return; + } + + /* disable console line buffer, echo, ... */ + struct termios ttyarg; + ioctl(fd, TCGETS , &ttyarg); + ttyarg.c_iflag = 0; + ttyarg.c_lflag = 0; + ioctl(fd, TCSETS , &ttyarg); + + // set up signals so we're notified when the console changes + // we can't use SIGUSR1 because it's used by the java-vm + vm.mode = VT_PROCESS; + vm.waitv = 0; + vm.relsig = SIGUSR2; + vm.acqsig = SIGUNUSED; + vm.frsig = 0; + + struct sigaction act; + sigemptyset(&act.sa_mask); + act.sa_handler = sigHandler; + act.sa_flags = 0; + sigaction(vm.relsig, &act, NULL); + + sigemptyset(&act.sa_mask); + act.sa_handler = sigHandler; + act.sa_flags = 0; + sigaction(vm.acqsig, &act, NULL); + + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, vm.relsig); + sigaddset(&mask, vm.acqsig); + sigprocmask(SIG_BLOCK, &mask, NULL); + + // switch to graphic mode + res = ioctl(fd, KDSETMODE, (void*)KD_GRAPHICS); + LOGW_IF(res<0, + "ioctl(%d, KDSETMODE, KD_GRAPHICS) failed, res %d", fd, res); + + this->prev_vt_num = vs.v_active; + this->vt_num = vtnum; + this->consoleFd = fd; +} + +DisplayHardwareBase::ConsoleManagerThread::~ConsoleManagerThread() +{ + if (this->consoleFd >= 0) { + int fd = this->consoleFd; + int prev_vt_num = this->prev_vt_num; + int res; + ioctl(fd, KDSETMODE, (void*)KD_TEXT); + do { + res = ioctl(fd, VT_ACTIVATE, (void*)prev_vt_num); + } while(res < 0 && errno == EINTR); + do { + res = ioctl(fd, VT_WAITACTIVE, (void*)prev_vt_num); + } while(res < 0 && errno == EINTR); + close(fd); + char const * const ttydev = "/dev/tty0"; + fd = open(ttydev, O_RDWR | O_SYNC); + ioctl(fd, VT_DISALLOCATE, 0); + close(fd); + } +} + +status_t DisplayHardwareBase::ConsoleManagerThread::readyToRun() +{ + if (this->consoleFd >= 0) { + sSignalCatcherPid = gettid(); + + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, vm.relsig); + sigaddset(&mask, vm.acqsig); + sigprocmask(SIG_BLOCK, &mask, NULL); + + int res = ioctl(this->consoleFd, VT_SETMODE, &vm); + if (res<0) { + LOGE("ioctl(%d, VT_SETMODE, ...) failed, %d (%s)", + this->consoleFd, errno, strerror(errno)); + } + return NO_ERROR; + } + return this->consoleFd; +} + +void DisplayHardwareBase::ConsoleManagerThread::requestExit() +{ + Thread::requestExit(); + if (sSignalCatcherPid != 0) { + // wake the thread up + kill(sSignalCatcherPid, SIGINT); + // wait for it... + } +} + +void DisplayHardwareBase::ConsoleManagerThread::sigHandler(int sig) +{ + // resend the signal to our signal catcher thread + LOGW("received signal %d in thread %d, resending to %d", + sig, gettid(), sSignalCatcherPid); + + // we absolutely need the delays below because without them + // our main thread never gets a chance to handle the signal. + usleep(10000); + kill(sSignalCatcherPid, sig); + usleep(10000); +} + +status_t DisplayHardwareBase::ConsoleManagerThread::releaseScreen() const +{ + int fd = this->consoleFd; + int err = ioctl(fd, VT_RELDISP, (void*)1); + LOGE_IF(err<0, "ioctl(%d, VT_RELDISP, 1) failed %d (%s)", + fd, errno, strerror(errno)); + return (err<0) ? (-errno) : status_t(NO_ERROR); +} + +bool DisplayHardwareBase::ConsoleManagerThread::threadLoop() +{ + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, vm.relsig); + sigaddset(&mask, vm.acqsig); + + int sig = 0; + sigwait(&mask, &sig); + + if (sig == vm.relsig) { + sp<SurfaceFlinger> flinger = mFlinger.promote(); + //LOGD("About to give-up screen, flinger = %p", flinger.get()); + if (flinger != 0) + flinger->screenReleased(0); + } else if (sig == vm.acqsig) { + sp<SurfaceFlinger> flinger = mFlinger.promote(); + //LOGD("Screen about to return, flinger = %p", flinger.get()); + if (flinger != 0) + flinger->screenAcquired(0); + } + + return true; +} + +status_t DisplayHardwareBase::ConsoleManagerThread::initCheck() const +{ + return consoleFd >= 0 ? NO_ERROR : NO_INIT; +} + +// ---------------------------------------------------------------------------- + +DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger, + uint32_t displayIndex) + : mCanDraw(true) +{ + mDisplayEventThread = new DisplayEventThread(flinger); + if (mDisplayEventThread->initCheck() != NO_ERROR) { + // fall-back on the console + mDisplayEventThread = new ConsoleManagerThread(flinger); + } +} + +DisplayHardwareBase::~DisplayHardwareBase() +{ + // request exit + mDisplayEventThread->requestExitAndWait(); +} + + +bool DisplayHardwareBase::canDraw() const +{ + return mCanDraw; +} + +void DisplayHardwareBase::releaseScreen() const +{ + status_t err = mDisplayEventThread->releaseScreen(); + if (err >= 0) { + //LOGD("screen given-up"); + mCanDraw = false; + } +} + +void DisplayHardwareBase::acquireScreen() const +{ + status_t err = mDisplayEventThread->acquireScreen(); + if (err >= 0) { + //LOGD("screen returned"); + mCanDraw = true; + } +} + +}; // namespace android diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h new file mode 100644 index 0000000..8369bb8 --- /dev/null +++ b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_DISPLAY_HARDWARE_BASE_H +#define ANDROID_DISPLAY_HARDWARE_BASE_H + +#include <stdint.h> +#include <utils/RefBase.h> +#include <utils/threads.h> +#include <linux/kd.h> +#include <linux/vt.h> +#include "Barrier.h" + +namespace android { + +class SurfaceFlinger; + +class DisplayHardwareBase +{ +public: + DisplayHardwareBase( + const sp<SurfaceFlinger>& flinger, + uint32_t displayIndex); + + ~DisplayHardwareBase(); + + // console managment + void releaseScreen() const; + void acquireScreen() const; + bool canDraw() const; + +private: + class DisplayEventThreadBase : public Thread { + protected: + wp<SurfaceFlinger> mFlinger; + public: + DisplayEventThreadBase(const sp<SurfaceFlinger>& flinger); + virtual ~DisplayEventThreadBase(); + virtual void onFirstRef() { + run("DisplayEventThread", PRIORITY_URGENT_DISPLAY); + } + virtual status_t acquireScreen() const { return NO_ERROR; }; + virtual status_t releaseScreen() const { return NO_ERROR; }; + virtual status_t initCheck() const = 0; + }; + + class DisplayEventThread : public DisplayEventThreadBase + { + mutable Barrier mBarrier; + public: + DisplayEventThread(const sp<SurfaceFlinger>& flinger); + virtual ~DisplayEventThread(); + virtual bool threadLoop(); + virtual status_t readyToRun(); + virtual status_t releaseScreen() const; + virtual status_t initCheck() const; + }; + + class ConsoleManagerThread : public DisplayEventThreadBase + { + int consoleFd; + int vt_num; + int prev_vt_num; + vt_mode vm; + static void sigHandler(int sig); + static pid_t sSignalCatcherPid; + public: + ConsoleManagerThread(const sp<SurfaceFlinger>& flinger); + virtual ~ConsoleManagerThread(); + virtual bool threadLoop(); + virtual status_t readyToRun(); + virtual void requestExit(); + virtual status_t releaseScreen() const; + virtual status_t initCheck() const; + }; + + sp<DisplayEventThreadBase> mDisplayEventThread; + mutable int mCanDraw; +}; + +}; // namespace android + +#endif // ANDROID_DISPLAY_HARDWARE_BASE_H |