diff options
97 files changed, 8992 insertions, 4396 deletions
| diff --git a/camera/libcameraservice/Android.mk b/camera/libcameraservice/Android.mk index df5c166b27..a0d6ee15de 100644 --- a/camera/libcameraservice/Android.mk +++ b/camera/libcameraservice/Android.mk @@ -1,18 +1,21 @@  LOCAL_PATH:= $(call my-dir) -# -# Set USE_CAMERA_STUB for non-emulator and non-simulator builds, if you want -# the camera service to use the fake camera.  For emulator or simulator builds, -# we always use the fake camera. +# Set USE_CAMERA_STUB if you don't want to use the hardware camera. -ifeq ($(USE_CAMERA_STUB),) -USE_CAMERA_STUB:=false +# force these builds to use camera stub only  ifneq ($(filter sooner generic sim,$(TARGET_DEVICE)),) -USE_CAMERA_STUB:=true -endif #libcamerastub +  USE_CAMERA_STUB:=true  endif  ifeq ($(USE_CAMERA_STUB),true) +  INCLUDE_CAMERA_STUB:=true +  INCLUDE_CAMERA_HARDWARE:=false +else +  INCLUDE_CAMERA_STUB:=true  # set this to true temporarily for testing +  INCLUDE_CAMERA_HARDWARE:=true +endif + +ifeq ($(INCLUDE_CAMERA_STUB),true)  #  # libcamerastub  # @@ -32,7 +35,7 @@ endif  LOCAL_SHARED_LIBRARIES:= libui  include $(BUILD_STATIC_LIBRARY) -endif # USE_CAMERA_STUB +endif # INCLUDE_CAMERA_STUB  #  # libcameraservice @@ -54,18 +57,18 @@ LOCAL_SHARED_LIBRARIES:= \  LOCAL_MODULE:= libcameraservice -LOCAL_CFLAGS += -DLOG_TAG=\"CameraService\" -  ifeq ($(TARGET_SIMULATOR),true)  LOCAL_CFLAGS += -DSINGLE_PROCESS  endif -ifeq ($(USE_CAMERA_STUB), true) +ifeq ($(INCLUDE_CAMERA_STUB), true)  LOCAL_STATIC_LIBRARIES += libcamerastub -LOCAL_CFLAGS += -include CameraHardwareStub.h -else +LOCAL_CFLAGS += -DINCLUDE_CAMERA_STUB +endif + +ifeq ($(INCLUDE_CAMERA_HARDWARE),true) +LOCAL_CFLAGS += -DINCLUDE_CAMERA_HARDWARE  LOCAL_SHARED_LIBRARIES += libcamera   endif  include $(BUILD_SHARED_LIBRARY) - diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/camera/libcameraservice/CameraHardwareStub.cpp index 8b663898a0..fda48e8c8c 100644 --- a/camera/libcameraservice/CameraHardwareStub.cpp +++ b/camera/libcameraservice/CameraHardwareStub.cpp @@ -47,14 +47,14 @@ void CameraHardwareStub::initDefaultParameters()  {      CameraParameters p; -    p.set("preview-size-values","320x240"); +    p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, "320x240");      p.setPreviewSize(320, 240);      p.setPreviewFrameRate(15); -    p.setPreviewFormat("yuv422sp"); +    p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420SP); -    p.set("picture-size-values", "320x240"); +    p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, "320x240");      p.setPictureSize(320, 240); -    p.setPictureFormat("jpeg"); +    p.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);      if (setParameters(p) != NO_ERROR) {          LOGE("Failed to set default parameters?!"); @@ -66,14 +66,14 @@ void CameraHardwareStub::initHeapLocked()      // Create raw heap.      int picture_width, picture_height;      mParameters.getPictureSize(&picture_width, &picture_height); -    mRawHeap = new MemoryHeapBase(picture_width * 2 * picture_height); +    mRawHeap = new MemoryHeapBase(picture_width * picture_height * 3 / 2);      int preview_width, preview_height;      mParameters.getPreviewSize(&preview_width, &preview_height);      LOGD("initHeapLocked: preview size=%dx%d", preview_width, preview_height); -    // Note that we enforce yuv422 in setParameters(). -    int how_big = preview_width * preview_height * 2; +    // Note that we enforce yuv420sp in setParameters(). +    int how_big = preview_width * preview_height * 3 / 2;      // If we are being reinitialized to the same size as before, no      // work needs to be done. @@ -99,7 +99,6 @@ CameraHardwareStub::~CameraHardwareStub()  {      delete mFakeCamera;      mFakeCamera = 0; // paranoia -    singleton.clear();  }  sp<IMemoryHeap> CameraHardwareStub::getPreviewHeap() const @@ -175,7 +174,7 @@ int CameraHardwareStub::previewThread()          // Fill the current frame with the fake camera.          uint8_t *frame = ((uint8_t *)base) + offset; -        fakeCamera->getNextFrameAsYuv422(frame); +        fakeCamera->getNextFrameAsYuv420(frame);          //LOGV("previewThread: generated frame to buffer %d", mCurrentPreviewFrame); @@ -288,9 +287,9 @@ int CameraHardwareStub::pictureThread()          // In the meantime just make another fake camera picture.          int w, h;          mParameters.getPictureSize(&w, &h); -        sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * 2 * h); +        sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * h * 3 / 2);          FakeCamera cam(w, h); -        cam.getNextFrameAsYuv422((uint8_t *)mRawHeap->base()); +        cam.getNextFrameAsYuv420((uint8_t *)mRawHeap->base());          mDataCb(CAMERA_MSG_RAW_IMAGE, mem, mCallbackCookie);      } @@ -307,7 +306,7 @@ status_t CameraHardwareStub::takePicture()  {      stopPreview();      if (createThread(beginPictureThread, this) == false) -        return -1; +        return UNKNOWN_ERROR;      return NO_ERROR;  } @@ -339,12 +338,14 @@ status_t CameraHardwareStub::setParameters(const CameraParameters& params)      Mutex::Autolock lock(mLock);      // XXX verify params -    if (strcmp(params.getPreviewFormat(), "yuv422sp") != 0) { -        LOGE("Only yuv422sp preview is supported"); +    if (strcmp(params.getPreviewFormat(), +        CameraParameters::PIXEL_FORMAT_YUV420SP) != 0) { +        LOGE("Only yuv420sp preview is supported");          return -1;      } -    if (strcmp(params.getPictureFormat(), "jpeg") != 0) { +    if (strcmp(params.getPictureFormat(), +        CameraParameters::PIXEL_FORMAT_JPEG) != 0) {          LOGE("Only jpeg still pictures are supported");          return -1;      } @@ -379,22 +380,12 @@ void CameraHardwareStub::release()  {  } -wp<CameraHardwareInterface> CameraHardwareStub::singleton; -  sp<CameraHardwareInterface> CameraHardwareStub::createInstance()  { -    if (singleton != 0) { -        sp<CameraHardwareInterface> hardware = singleton.promote(); -        if (hardware != 0) { -            return hardware; -        } -    } -    sp<CameraHardwareInterface> hardware(new CameraHardwareStub()); -    singleton = hardware; -    return hardware; +    return new CameraHardwareStub();  } -extern "C" sp<CameraHardwareInterface> openCameraHardware() +extern "C" sp<CameraHardwareInterface> openCameraHardwareStub()  {      return CameraHardwareStub::createInstance();  } diff --git a/camera/libcameraservice/CameraHardwareStub.h b/camera/libcameraservice/CameraHardwareStub.h index 957813a4a4..d194f3c4ed 100644 --- a/camera/libcameraservice/CameraHardwareStub.h +++ b/camera/libcameraservice/CameraHardwareStub.h @@ -67,8 +67,6 @@ private:                          CameraHardwareStub();      virtual             ~CameraHardwareStub(); -    static wp<CameraHardwareInterface> singleton; -      static const int kBufferCount = 4;      class PreviewThread : public Thread { @@ -130,6 +128,8 @@ private:      int                 mCurrentPreviewFrame;  }; +extern "C" sp<CameraHardwareInterface> openCameraHardwareStub(); +  }; // namespace android  #endif diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp index 00bd54eb59..4f684b7ba3 100644 --- a/camera/libcameraservice/CameraService.cpp +++ b/camera/libcameraservice/CameraService.cpp @@ -17,383 +17,448 @@  */  #define LOG_TAG "CameraService" -#include <utils/Log.h> -#include <binder/IServiceManager.h> +#include <stdio.h> +#include <sys/types.h> +#include <pthread.h> +  #include <binder/IPCThreadState.h> -#include <utils/String16.h> -#include <utils/Errors.h> +#include <binder/IServiceManager.h>  #include <binder/MemoryBase.h>  #include <binder/MemoryHeapBase.h> -#include <camera/ICameraService.h> +#include <cutils/atomic.h> +#include <hardware/hardware.h> +#include <media/AudioSystem.h> +#include <media/mediaplayer.h>  #include <surfaceflinger/ISurface.h>  #include <ui/Overlay.h> +#include <utils/Errors.h> +#include <utils/Log.h> +#include <utils/String16.h> -#include <hardware/hardware.h> - -#include <media/mediaplayer.h> -#include <media/AudioSystem.h>  #include "CameraService.h" - -#include <cutils/atomic.h> +#ifdef INCLUDE_CAMERA_STUB +#include "CameraHardwareStub.h" +#endif  namespace android { -extern "C" { -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <pthread.h> -#include <signal.h> -} +/* This determines the number of cameras available */ +#if defined(INCLUDE_CAMERA_HARDWARE) && defined(INCLUDE_CAMERA_STUB) +  #define NUM_CAMERAS 2 +#elif defined(INCLUDE_CAMERA_HARDWARE) || defined(INCLUDE_CAMERA_STUB) +  #define NUM_CAMERAS 1 +#else +  #error "Should have at least one camera" +#endif -// When you enable this, as well as DEBUG_REFS=1 and -// DEBUG_REFS_ENABLED_BY_DEFAULT=0 in libutils/RefBase.cpp, this will track all -// references to the CameraService::Client in order to catch the case where the -// client is being destroyed while a callback from the CameraHardwareInterface -// is outstanding.  This is a serious bug because if we make another call into -// CameraHardwreInterface that itself triggers a callback, we will deadlock. +/* Make sure we have enough array space allocated */ +#if NUM_CAMERAS > MAX_CAMERAS +  #error "Need to increase MAX_CAMERAS" +#endif -#define DEBUG_CLIENT_REFERENCES 0 +/* This defines the "open" function for each camera */ +extern "C" typedef sp<CameraHardwareInterface> (*OpenCameraHardwareFunction)(); +static OpenCameraHardwareFunction sOpenCameraTable[] = { +#ifdef INCLUDE_CAMERA_HARDWARE +    &openCameraHardware, +#endif +#ifdef INCLUDE_CAMERA_STUB +    &openCameraHardwareStub, +#endif +}; -#define PICTURE_TIMEOUT seconds(5) +// ---------------------------------------------------------------------------- +// Logging support -- this is for debugging only +// Use "adb shell dumpsys media.camera -v 1" to change it. +static volatile int32_t gLogLevel = 0; -#define DEBUG_DUMP_PREVIEW_FRAME_TO_FILE 0 /* n-th frame to write */ -#define DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE 0 -#define DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE 0 -#define DEBUG_DUMP_POSTVIEW_SNAPSHOT_TO_FILE 0 +#define LOG1(...) LOGD_IF(gLogLevel >= 1, __VA_ARGS__); +#define LOG2(...) LOGD_IF(gLogLevel >= 2, __VA_ARGS__); -#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE -static int debug_frame_cnt; -#endif +static void setLogLevel(int level) { +    android_atomic_write(level, &gLogLevel); +} + +// ----------------------------------------------------------------------------  static int getCallingPid() {      return IPCThreadState::self()->getCallingPid();  } -// ---------------------------------------------------------------------------- - -void CameraService::instantiate() { -    defaultServiceManager()->addService( -            String16("media.camera"), new CameraService()); +static int getCallingUid() { +    return IPCThreadState::self()->getCallingUid();  }  // ---------------------------------------------------------------------------- -CameraService::CameraService() : -    BnCameraService() +// This is ugly and only safe if we never re-create the CameraService, but +// should be ok for now. +static CameraService *gCameraService; + +CameraService::CameraService() +:mSoundRef(0)  { -    LOGI("CameraService started: pid=%d", getpid()); -    mUsers = 0; +    LOGI("CameraService started (pid=%d)", getpid()); + +    for (int i = 0; i < NUM_CAMERAS; i++) { +        setCameraFree(i); +    } + +    gCameraService = this;  } -CameraService::~CameraService() -{ -    if (mClient != 0) { -        LOGE("mClient was still connected in destructor!"); +CameraService::~CameraService() { +    for (int i = 0; i < NUM_CAMERAS; i++) { +        if (mBusy[i]) { +            LOGE("camera %d is still in use in destructor!", i); +        }      } + +    gCameraService = NULL;  } -sp<ICamera> CameraService::connect(const sp<ICameraClient>& cameraClient) -{ +int32_t CameraService::getNumberOfCameras() { +    return NUM_CAMERAS; +} + +sp<ICamera> CameraService::connect( +        const sp<ICameraClient>& cameraClient, int cameraId) {      int callingPid = getCallingPid(); -    LOGV("CameraService::connect E (pid %d, client %p)", callingPid, -            cameraClient->asBinder().get()); +    LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId); -    Mutex::Autolock lock(mServiceLock);      sp<Client> client; -    if (mClient != 0) { -        sp<Client> currentClient = mClient.promote(); -        if (currentClient != 0) { -            sp<ICameraClient> currentCameraClient(currentClient->getCameraClient()); -            if (cameraClient->asBinder() == currentCameraClient->asBinder()) { -                // This is the same client reconnecting... -                LOGV("CameraService::connect X (pid %d, same client %p) is reconnecting...", -                    callingPid, cameraClient->asBinder().get()); -                return currentClient; -            } else { -                // It's another client... reject it -                LOGV("CameraService::connect X (pid %d, new client %p) rejected. " -                    "(old pid %d, old client %p)", -                    callingPid, cameraClient->asBinder().get(), -                    currentClient->mClientPid, currentCameraClient->asBinder().get()); -                if (kill(currentClient->mClientPid, 0) == -1 && errno == ESRCH) { -                    LOGV("The old client is dead!"); -                } +    if (cameraId < 0 || cameraId >= NUM_CAMERAS) { +        LOGE("CameraService::connect X (pid %d) rejected (invalid cameraId %d).", +            callingPid, cameraId); +        return NULL; +    } + +    Mutex::Autolock lock(mServiceLock); +    if (mClient[cameraId] != 0) { +        client = mClient[cameraId].promote(); +        if (client != 0) { +            if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) { +                LOG1("CameraService::connect X (pid %d) (the same client)", +                    callingPid);                  return client; -            } -        } else { -            // can't promote, the previous client has died... -            LOGV("New client (pid %d) connecting, old reference was dangling...", +            } else { +                LOGW("CameraService::connect X (pid %d) rejected (existing client).",                      callingPid); -            mClient.clear(); +                return NULL; +            }          } +        mClient[cameraId].clear();      } -    if (mUsers > 0) { -        LOGV("Still have client, rejected"); -        return client; +    if (mBusy[cameraId]) { +        LOGW("CameraService::connect X (pid %d) rejected" +             " (camera %d is still busy).", callingPid, cameraId); +        return NULL;      } -    // create a new Client object -    client = new Client(this, cameraClient, callingPid); -    mClient = client; -#if DEBUG_CLIENT_REFERENCES -    // Enable tracking for this object, and track increments and decrements of -    // the refcount. -    client->trackMe(true, true); -#endif -    LOGV("CameraService::connect X"); +    client = new Client(this, cameraClient, cameraId, callingPid); +    mClient[cameraId] = client; +    LOG1("CameraService::connect X");      return client;  } -void CameraService::removeClient(const sp<ICameraClient>& cameraClient) -{ +void CameraService::removeClient(const sp<ICameraClient>& cameraClient) {      int callingPid = getCallingPid(); +    LOG1("CameraService::removeClient E (pid %d)", callingPid); -    // Declare this outside the lock to make absolutely sure the -    // destructor won't be called with the lock held. -    sp<Client> client; +    for (int i = 0; i < NUM_CAMERAS; i++) { +        // Declare this before the lock to make absolutely sure the +        // destructor won't be called with the lock held. +        sp<Client> client; -    Mutex::Autolock lock(mServiceLock); +        Mutex::Autolock lock(mServiceLock); -    if (mClient == 0) { -        // This happens when we have already disconnected. -        LOGV("removeClient (pid %d): already disconnected", callingPid); -        return; -    } +        // This happens when we have already disconnected (or this is +        // just another unused camera). +        if (mClient[i] == 0) continue; -    // Promote mClient. It can fail if we are called from this path: -    // Client::~Client() -> disconnect() -> removeClient(). -    client = mClient.promote(); -    if (client == 0) { -        LOGV("removeClient (pid %d): no more strong reference", callingPid); -        mClient.clear(); -        return; +        // Promote mClient. It can fail if we are called from this path: +        // Client::~Client() -> disconnect() -> removeClient(). +        client = mClient[i].promote(); + +        if (client == 0) { +            mClient[i].clear(); +            continue; +        } + +        if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) { +            // Found our camera, clear and leave. +            LOG1("removeClient: clear camera %d", i); +            mClient[i].clear(); +            break; +        }      } -    if (cameraClient->asBinder() != client->getCameraClient()->asBinder()) { -        // ugh! that's not our client!! -        LOGW("removeClient (pid %d): mClient doesn't match!", callingPid); -    } else { -        // okay, good, forget about mClient -        mClient.clear(); +    LOG1("CameraService::removeClient X (pid %d)", callingPid); +} + +sp<CameraService::Client> CameraService::getClientById(int cameraId) { +    if (cameraId < 0 || cameraId >= NUM_CAMERAS) return NULL; +    return mClient[cameraId].promote(); +} + +void CameraService::instantiate() { +    defaultServiceManager()->addService(String16("media.camera"), +        new CameraService()); +} + +status_t CameraService::onTransact( +    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { +    // Permission checks +    switch (code) { +        case BnCameraService::CONNECT: +            const int pid = getCallingPid(); +            const int self_pid = getpid(); +            if (pid != self_pid) { +                // we're called from a different process, do the real check +                if (!checkCallingPermission( +                        String16("android.permission.CAMERA"))) { +                    const int uid = getCallingUid(); +                    LOGE("Permission Denial: " +                         "can't use the camera pid=%d, uid=%d", pid, uid); +                    return PERMISSION_DENIED; +                } +            } +            break;      } -    LOGV("removeClient (pid %d) done", callingPid); +    return BnCameraService::onTransact(code, data, reply, flags);  } -// The reason we need this count is a new CameraService::connect() request may -// come in while the previous Client's destructor has not been run or is still -// running. If the last strong reference of the previous Client is gone but -// destructor has not been run, we should not allow the new Client to be created -// because we need to wait for the previous Client to tear down the hardware -// first. -void CameraService::incUsers() { -    android_atomic_inc(&mUsers); +// The reason we need this busy bit is a new CameraService::connect() request +// may come in while the previous Client's destructor has not been run or is +// still running. If the last strong reference of the previous Client is gone +// but the destructor has not been finished, we should not allow the new Client +// to be created because we need to wait for the previous Client to tear down +// the hardware first. +void CameraService::setCameraBusy(int cameraId) { +    android_atomic_write(1, &mBusy[cameraId]);  } -void CameraService::decUsers() { -    android_atomic_dec(&mUsers); +void CameraService::setCameraFree(int cameraId) { +    android_atomic_write(0, &mBusy[cameraId]);  } -static sp<MediaPlayer> newMediaPlayer(const char *file) -{ -    sp<MediaPlayer> mp = new MediaPlayer(); -    if (mp->setDataSource(file, NULL /* headers */) == NO_ERROR) { +// We share the media players for shutter and recording sound for all clients. +// A reference count is kept to determine when we will actually release the +// media players. + +static MediaPlayer* newMediaPlayer(const char *file) { +    MediaPlayer* mp = new MediaPlayer(); +    if (mp->setDataSource(file, NULL) == NO_ERROR) {          mp->setAudioStreamType(AudioSystem::ENFORCED_AUDIBLE);          mp->prepare();      } else { -        mp.clear(); -        LOGE("Failed to load CameraService sounds."); +        LOGE("Failed to load CameraService sounds: %s", file); +        return NULL;      }      return mp;  } +void CameraService::loadSound() { +    Mutex::Autolock lock(mSoundLock); +    LOG1("CameraService::loadSound ref=%d", mSoundRef); +    if (mSoundRef++) return; + +    mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/system/media/audio/ui/camera_click.ogg"); +    mSoundPlayer[SOUND_RECORDING] = newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg"); +} + +void CameraService::releaseSound() { +    Mutex::Autolock lock(mSoundLock); +    LOG1("CameraService::releaseSound ref=%d", mSoundRef); +    if (--mSoundRef) return; + +    for (int i = 0; i < NUM_SOUNDS; i++) { +        if (mSoundPlayer[i] != 0) { +            mSoundPlayer[i]->disconnect(); +            mSoundPlayer[i].clear(); +        } +    } +} + +void CameraService::playSound(sound_kind kind) { +    LOG1("playSound(%d)", kind); +    Mutex::Autolock lock(mSoundLock); +    sp<MediaPlayer> player = mSoundPlayer[kind]; +    if (player != 0) { +        // do not play the sound if stream volume is 0 +        // (typically because ringer mode is silent). +        int index; +        AudioSystem::getStreamVolumeIndex(AudioSystem::ENFORCED_AUDIBLE, &index); +        if (index != 0) { +            player->seekTo(0); +            player->start(); +        } +    } +} + +// ---------------------------------------------------------------------------- +  CameraService::Client::Client(const sp<CameraService>& cameraService, -        const sp<ICameraClient>& cameraClient, pid_t clientPid) -{ +        const sp<ICameraClient>& cameraClient, int cameraId, int clientPid) {      int callingPid = getCallingPid(); -    LOGV("Client::Client E (pid %d)", callingPid); +    LOG1("Client::Client E (pid %d)", callingPid); +      mCameraService = cameraService;      mCameraClient = cameraClient; +    mCameraId = cameraId;      mClientPid = clientPid; -    mHardware = openCameraHardware(); + +    mHardware = sOpenCameraTable[cameraId]();      mUseOverlay = mHardware->useOverlay(); +    mMsgEnabled = 0;      mHardware->setCallbacks(notifyCallback,                              dataCallback,                              dataCallbackTimestamp, -                            mCameraService.get()); +                            (void *)cameraId);      // Enable zoom, error, and focus messages by default -    mHardware->enableMsgType(CAMERA_MSG_ERROR | -                             CAMERA_MSG_ZOOM | -                             CAMERA_MSG_FOCUS); - -    mMediaPlayerClick = newMediaPlayer("/system/media/audio/ui/camera_click.ogg"); -    mMediaPlayerBeep = newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg"); +    enableMsgType(CAMERA_MSG_ERROR | +                  CAMERA_MSG_ZOOM | +                  CAMERA_MSG_FOCUS);      mOverlayW = 0;      mOverlayH = 0;      // Callback is disabled by default      mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;      mOrientation = 0; -    cameraService->incUsers(); -    LOGV("Client::Client X (pid %d)", callingPid); +    cameraService->setCameraBusy(cameraId); +    cameraService->loadSound(); +    LOG1("Client::Client X (pid %d)", callingPid);  } -status_t CameraService::Client::checkPid() -{ +static void *unregister_surface(void *arg) { +    ISurface *surface = (ISurface *)arg; +    surface->unregisterBuffers(); +    IPCThreadState::self()->flushCommands(); +    return NULL; +} + +// tear down the client +CameraService::Client::~Client() {      int callingPid = getCallingPid(); -    if (mClientPid == callingPid) return NO_ERROR; -    LOGW("Attempt to use locked camera (client %p) from different process " -        " (old pid %d, new pid %d)", -        getCameraClient()->asBinder().get(), mClientPid, callingPid); -    return -EBUSY; +    LOG1("Client::~Client E (pid %d, this %p)", callingPid, this); + +    if (mSurface != 0 && !mUseOverlay) { +        pthread_t thr; +        // We unregister the buffers in a different thread because binder does +        // not let us make sychronous transactions in a binder destructor (that +        // is, upon our reaching a refcount of zero.) +        pthread_create(&thr, +                       NULL,  // attr +                       unregister_surface, +                       mSurface.get()); +        pthread_join(thr, NULL); +    } + +    // set mClientPid to let disconnet() tear down the hardware +    mClientPid = callingPid; +    disconnect(); +    mCameraService->releaseSound(); +    LOG1("Client::~Client X (pid %d, this %p)", callingPid, this);  } -status_t CameraService::Client::lock() -{ +// ---------------------------------------------------------------------------- + +status_t CameraService::Client::checkPid() const { +    int callingPid = getCallingPid(); +    if (callingPid == mClientPid) return NO_ERROR; +    if (callingPid == getpid()) { +        LOGW("FIXME: use camera from mediaserver without permission."); +        return NO_ERROR; +    } +    LOGW("attempt to use a locked camera from a different process" +         " (old pid %d, new pid %d)", mClientPid, callingPid); +    return EBUSY; +} + +status_t CameraService::Client::checkPidAndHardware() const { +    status_t result = checkPid(); +    if (result != NO_ERROR) return result; +    if (mHardware == 0) { +        LOGE("attempt to use a camera after disconnect() (pid %d)", getCallingPid()); +        return INVALID_OPERATION; +    } +    return NO_ERROR; +} + +status_t CameraService::Client::lock() {      int callingPid = getCallingPid(); -    LOGV("lock from pid %d (mClientPid %d)", callingPid, mClientPid); -    Mutex::Autolock _l(mLock); +    LOG1("lock (pid %d)", callingPid); +    Mutex::Autolock lock(mLock); +      // lock camera to this client if the the camera is unlocked      if (mClientPid == 0) {          mClientPid = callingPid;          return NO_ERROR;      } -    // returns NO_ERROR if the client already owns the camera, -EBUSY otherwise + +    // returns NO_ERROR if the client already owns the camera, EBUSY otherwise      return checkPid();  } -status_t CameraService::Client::unlock() -{ +status_t CameraService::Client::unlock() {      int callingPid = getCallingPid(); -    LOGV("unlock from pid %d (mClientPid %d)", callingPid, mClientPid); -    Mutex::Autolock _l(mLock); -    // allow anyone to use camera +    LOG1("unlock (pid %d)", callingPid); +    Mutex::Autolock lock(mLock); + +    // allow anyone to use camera (after they lock the camera)      status_t result = checkPid();      if (result == NO_ERROR) {          mClientPid = 0; -        LOGV("clear mCameraClient (pid %d)", callingPid); -        // we need to remove the reference so that when app goes -        // away, the reference count goes to 0. +        LOG1("clear mCameraClient (pid %d)", callingPid); +        // we need to remove the reference to ICameraClient so that when the app +        // goes away, the reference count goes to 0.          mCameraClient.clear();      }      return result;  } -status_t CameraService::Client::connect(const sp<ICameraClient>& client) -{ +// connect a new client to the camera +status_t CameraService::Client::connect(const sp<ICameraClient>& client) {      int callingPid = getCallingPid(); +    LOG1("connect E (pid %d)", callingPid); +    Mutex::Autolock lock(mLock); -    // connect a new process to the camera -    LOGV("Client::connect E (pid %d, client %p)", callingPid, client->asBinder().get()); - -    // I hate this hack, but things get really ugly when the media recorder -    // service is handing back the camera to the app. The ICameraClient -    // destructor will be called during the same IPC, making it look like -    // the remote client is trying to disconnect. This hack temporarily -    // sets the mClientPid to an invalid pid to prevent the hardware from -    // being torn down. -    { - -        // hold a reference to the old client or we will deadlock if the client is -        // in the same process and we hold the lock when we remove the reference -        sp<ICameraClient> oldClient; -        { -            Mutex::Autolock _l(mLock); -            if (mClientPid != 0 && checkPid() != NO_ERROR) { -                LOGW("Tried to connect to locked camera (old pid %d, new pid %d)", -                        mClientPid, callingPid); -                return -EBUSY; -            } -            oldClient = mCameraClient; - -            // did the client actually change? -            if ((mCameraClient != NULL) && (client->asBinder() == mCameraClient->asBinder())) { -                LOGV("Connect to the same client"); -                return NO_ERROR; -            } - -            mCameraClient = client; -            mClientPid = -1; -            mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP; -            LOGV("Connect to the new client (pid %d, client %p)", -                callingPid, mCameraClient->asBinder().get()); -        } +    if (mClientPid != 0 && checkPid() != NO_ERROR) { +        LOGW("Tried to connect to a locked camera (old pid %d, new pid %d)", +                mClientPid, callingPid); +        return EBUSY; +    } +    if (mCameraClient != 0 && (client->asBinder() == mCameraClient->asBinder())) { +        LOG1("Connect to the same client"); +        return NO_ERROR;      } -    // the old client destructor is called when oldClient goes out of scope -    // now we set the new PID to lock the interface again + +    mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;      mClientPid = callingPid; +    mCameraClient = client; +    LOG1("connect X (pid %d)", callingPid);      return NO_ERROR;  } -#if HAVE_ANDROID_OS -static void *unregister_surface(void *arg) -{ -    ISurface *surface = (ISurface *)arg; -    surface->unregisterBuffers(); -    IPCThreadState::self()->flushCommands(); -    return NULL; -} -#endif - -CameraService::Client::~Client() -{ +void CameraService::Client::disconnect() {      int callingPid = getCallingPid(); +    LOG1("disconnect E (pid %d)", callingPid); +    Mutex::Autolock lock(mLock); -    // tear down client -    LOGV("Client::~Client E (pid %d, client %p)", -            callingPid, getCameraClient()->asBinder().get()); -    if (mSurface != 0 && !mUseOverlay) { -#if HAVE_ANDROID_OS -        pthread_t thr; -        // We unregister the buffers in a different thread because binder does -        // not let us make sychronous transactions in a binder destructor (that -        // is, upon our reaching a refcount of zero.) -        pthread_create(&thr, NULL, -                       unregister_surface, -                       mSurface.get()); -        pthread_join(thr, NULL); -#else -        mSurface->unregisterBuffers(); -#endif -    } - -    if (mMediaPlayerBeep.get() != NULL) { -        mMediaPlayerBeep->disconnect(); -        mMediaPlayerBeep.clear(); -    } -    if (mMediaPlayerClick.get() != NULL) { -        mMediaPlayerClick->disconnect(); -        mMediaPlayerClick.clear(); +    if (checkPid() != NO_ERROR) { +        LOGW("different client - don't disconnect"); +        return;      } -    // make sure we tear down the hardware -    mClientPid = callingPid; -    disconnect(); -    LOGV("Client::~Client X (pid %d)", mClientPid); -} - -void CameraService::Client::disconnect() -{ -    int callingPid = getCallingPid(); - -    LOGV("Client::disconnect() E (pid %d client %p)", -            callingPid, getCameraClient()->asBinder().get()); - -    Mutex::Autolock lock(mLock);      if (mClientPid <= 0) { -        LOGV("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid); -        return; -    } -    if (checkPid() != NO_ERROR) { -        LOGV("Different client - don't disconnect"); +        LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);          return;      } @@ -401,519 +466,564 @@ void CameraService::Client::disconnect()      // from the user directly, or called by the destructor.      if (mHardware == 0) return; -    LOGV("hardware teardown"); +    LOG1("hardware teardown");      // Before destroying mHardware, we must make sure it's in the      // idle state. +    // Turn off all messages. +    disableMsgType(CAMERA_MSG_ALL_MSGS);      mHardware->stopPreview(); -    // Cancel all picture callbacks. -    mHardware->disableMsgType(CAMERA_MSG_SHUTTER | -                              CAMERA_MSG_POSTVIEW_FRAME | -                              CAMERA_MSG_RAW_IMAGE | -                              CAMERA_MSG_COMPRESSED_IMAGE);      mHardware->cancelPicture(); -    // Turn off remaining messages. -    mHardware->disableMsgType(CAMERA_MSG_ALL_MSGS);      // Release the hardware resources.      mHardware->release();      // Release the held overlay resources. -    if (mUseOverlay) -    { +    if (mUseOverlay) {          mOverlayRef = 0;      }      mHardware.clear();      mCameraService->removeClient(mCameraClient); -    mCameraService->decUsers(); +    mCameraService->setCameraFree(mCameraId); -    LOGV("Client::disconnect() X (pid %d)", callingPid); +    LOG1("disconnect X (pid %d)", callingPid);  } -// pass the buffered ISurface to the camera service -status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface) -{ -    LOGV("setPreviewDisplay(%p) (pid %d)", -         ((surface == NULL) ? NULL : surface.get()), getCallingPid()); +// ---------------------------------------------------------------------------- + +// set the ISurface that the preview will use +status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface) { +    LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());      Mutex::Autolock lock(mLock); -    status_t result = checkPid(); +    status_t result = checkPidAndHardware();      if (result != NO_ERROR) return result; -    Mutex::Autolock surfaceLock(mSurfaceLock);      result = NO_ERROR; -    // asBinder() is safe on NULL (returns NULL) -    if (surface->asBinder() != mSurface->asBinder()) { -        if (mSurface != 0) { -            LOGV("clearing old preview surface %p", mSurface.get()); -            if ( !mUseOverlay) -            { -                mSurface->unregisterBuffers(); -            } -            else -            { -                // Force the destruction of any previous overlay -                sp<Overlay> dummy; -                mHardware->setOverlay( dummy ); -            } -        } -        mSurface = surface; -        mOverlayRef = 0; -        // If preview has been already started, set overlay or register preview -        // buffers now. -        if (mHardware->previewEnabled()) { -            if (mUseOverlay) { -                result = setOverlay(); -            } else if (mSurface != 0) { -                result = registerPreviewBuffers(); -            } -        } -    } -    return result; -} - -// set the preview callback flag to affect how the received frames from -// preview are handled. -void CameraService::Client::setPreviewCallbackFlag(int callback_flag) -{ -    LOGV("setPreviewCallbackFlag (pid %d)", getCallingPid()); -    Mutex::Autolock lock(mLock); -    if (checkPid() != NO_ERROR) return; -    mPreviewCallbackFlag = callback_flag; - -    if(mUseOverlay) { -        if(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK) -            mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME); -        else -            mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME); -    } -} -// start preview mode -status_t CameraService::Client::startCameraMode(camera_mode mode) -{ -    int callingPid = getCallingPid(); - -    LOGV("startCameraMode(%d) (pid %d)", mode, callingPid); - -    /* we cannot call into mHardware with mLock held because -     * mHardware has callbacks onto us which acquire this lock -     */ - -    Mutex::Autolock lock(mLock); -    status_t result = checkPid(); -    if (result != NO_ERROR) return result; - -    if (mHardware == 0) { -        LOGE("mHardware is NULL, returning."); -        return INVALID_OPERATION; +    // return if no change in surface. +    // asBinder() is safe on NULL (returns NULL) +    if (surface->asBinder() == mSurface->asBinder()) { +        return result;      } -    switch(mode) { -    case CAMERA_RECORDING_MODE: -        if (mSurface == 0) { -            LOGE("setPreviewDisplay must be called before startRecordingMode."); -            return INVALID_OPERATION; +    if (mSurface != 0) { +        LOG1("clearing old preview surface %p", mSurface.get()); +        if (mUseOverlay) { +            // Force the destruction of any previous overlay +            sp<Overlay> dummy; +            mHardware->setOverlay(dummy); +        } else { +            mSurface->unregisterBuffers();          } -        return startRecordingMode(); - -    default: // CAMERA_PREVIEW_MODE -        if (mSurface == 0) { -            LOGV("mSurface is not set yet."); +    } +    mSurface = surface; +    mOverlayRef = 0; +    // If preview has been already started, set overlay or register preview +    // buffers now. +    if (mHardware->previewEnabled()) { +        if (mUseOverlay) { +            result = setOverlay(); +        } else if (mSurface != 0) { +            result = registerPreviewBuffers();          } -        return startPreviewMode();      } -} -status_t CameraService::Client::startRecordingMode() -{ -    LOGV("startRecordingMode (pid %d)", getCallingPid()); - -    status_t ret = UNKNOWN_ERROR; +    return result; +} -    // if preview has not been started, start preview first -    if (!mHardware->previewEnabled()) { -        ret = startPreviewMode(); -        if (ret != NO_ERROR) { -            return ret; -        } -    } +status_t CameraService::Client::registerPreviewBuffers() { +    int w, h; +    CameraParameters params(mHardware->getParameters()); +    params.getPreviewSize(&w, &h); -    // if recording has been enabled, nothing needs to be done -    if (mHardware->recordingEnabled()) { -        return NO_ERROR; -    } +    // FIXME: don't use a hardcoded format here. +    ISurface::BufferHeap buffers(w, h, w, h, +                                 HAL_PIXEL_FORMAT_YCrCb_420_SP, +                                 mOrientation, +                                 0, +                                 mHardware->getPreviewHeap()); -    // start recording mode -    ret = mHardware->startRecording(); -    if (ret != NO_ERROR) { -        LOGE("mHardware->startRecording() failed with status %d", ret); +    status_t result = mSurface->registerBuffers(buffers); +    if (result != NO_ERROR) { +        LOGE("registerBuffers failed with status %d", result);      } -    return ret; +    return result;  } -status_t CameraService::Client::setOverlay() -{ -    LOGV("setOverlay"); +status_t CameraService::Client::setOverlay() {      int w, h;      CameraParameters params(mHardware->getParameters());      params.getPreviewSize(&w, &h); -    if ( w != mOverlayW || h != mOverlayH ) -    { +    if (w != mOverlayW || h != mOverlayH) {          // Force the destruction of any previous overlay          sp<Overlay> dummy; -        mHardware->setOverlay( dummy ); +        mHardware->setOverlay(dummy);          mOverlayRef = 0;      } -    status_t ret = NO_ERROR; -    if (mSurface != 0) { -        if (mOverlayRef.get() == NULL) { - +    status_t result = NO_ERROR; +    if (mSurface == 0) { +        result = mHardware->setOverlay(NULL); +    } else { +        if (mOverlayRef == 0) {              // FIXME:              // Surfaceflinger may hold onto the previous overlay reference for some              // time after we try to destroy it. retry a few times. In the future, we              // should make the destroy call block, or possibly specify that we can -            // wait in the createOverlay call if the previous overlay is in the  +            // wait in the createOverlay call if the previous overlay is in the              // process of being destroyed.              for (int retry = 0; retry < 50; ++retry) {                  mOverlayRef = mSurface->createOverlay(w, h, OVERLAY_FORMAT_DEFAULT,                                                        mOrientation); -                if (mOverlayRef != NULL) break; +                if (mOverlayRef != 0) break;                  LOGW("Overlay create failed - retrying");                  usleep(20000);              } -            if ( mOverlayRef.get() == NULL ) -            { +            if (mOverlayRef == 0) {                  LOGE("Overlay Creation Failed!");                  return -EINVAL;              } -            ret = mHardware->setOverlay(new Overlay(mOverlayRef)); +            result = mHardware->setOverlay(new Overlay(mOverlayRef));          } -    } else { -        ret = mHardware->setOverlay(NULL);      } -    if (ret != NO_ERROR) { -        LOGE("mHardware->setOverlay() failed with status %d\n", ret); +    if (result != NO_ERROR) { +        LOGE("mHardware->setOverlay() failed with status %d\n", result); +        return result;      }      mOverlayW = w;      mOverlayH = h; -    return ret; +    return result;  } -status_t CameraService::Client::registerPreviewBuffers() -{ -    int w, h; -    CameraParameters params(mHardware->getParameters()); -    params.getPreviewSize(&w, &h); +// set the preview callback flag to affect how the received frames from +// preview are handled. +void CameraService::Client::setPreviewCallbackFlag(int callback_flag) { +    LOG1("setPreviewCallbackFlag(%d) (pid %d)", callback_flag, getCallingPid()); +    Mutex::Autolock lock(mLock); +    if (checkPidAndHardware() != NO_ERROR) return; -    // don't use a hardcoded format here -    ISurface::BufferHeap buffers(w, h, w, h, -                                 HAL_PIXEL_FORMAT_YCrCb_420_SP, -                                 mOrientation, -                                 0, -                                 mHardware->getPreviewHeap()); +    mPreviewCallbackFlag = callback_flag; -    status_t ret = mSurface->registerBuffers(buffers); -    if (ret != NO_ERROR) { -        LOGE("registerBuffers failed with status %d", ret); +    // If we don't use overlay, we always need the preview frame for display. +    // If we do use overlay, we only need the preview frame if the user +    // wants the data. +    if (mUseOverlay) { +        if(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK) { +            enableMsgType(CAMERA_MSG_PREVIEW_FRAME); +        } else { +            disableMsgType(CAMERA_MSG_PREVIEW_FRAME); +        }      } -    return ret;  } -status_t CameraService::Client::startPreviewMode() -{ -    LOGV("startPreviewMode (pid %d)", getCallingPid()); +// start preview mode +status_t CameraService::Client::startPreview() { +    LOG1("startPreview (pid %d)", getCallingPid()); +    return startCameraMode(CAMERA_PREVIEW_MODE); +} + +// start recording mode +status_t CameraService::Client::startRecording() { +    LOG1("startRecording (pid %d)", getCallingPid()); +    return startCameraMode(CAMERA_RECORDING_MODE); +} + +// start preview or recording +status_t CameraService::Client::startCameraMode(camera_mode mode) { +    LOG1("startCameraMode(%d)", mode); +    Mutex::Autolock lock(mLock); +    status_t result = checkPidAndHardware(); +    if (result != NO_ERROR) return result; + +    switch(mode) { +        case CAMERA_PREVIEW_MODE: +            if (mSurface == 0) { +                LOG1("mSurface is not set yet."); +                // still able to start preview in this case. +            } +            return startPreviewMode(); +        case CAMERA_RECORDING_MODE: +            if (mSurface == 0) { +                LOGE("mSurface must be set before startRecordingMode."); +                return INVALID_OPERATION; +            } +            return startRecordingMode(); +        default: +            return UNKNOWN_ERROR; +    } +} + +status_t CameraService::Client::startPreviewMode() { +    LOG1("startPreviewMode"); +    status_t result = NO_ERROR;      // if preview has been enabled, nothing needs to be done      if (mHardware->previewEnabled()) {          return NO_ERROR;      } -    // start preview mode -#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE -    debug_frame_cnt = 0; -#endif -    status_t ret = NO_ERROR; -      if (mUseOverlay) {          // If preview display has been set, set overlay now.          if (mSurface != 0) { -            ret = setOverlay(); +            result = setOverlay();          } -        if (ret != NO_ERROR) return ret; -        ret = mHardware->startPreview(); +        if (result != NO_ERROR) return result; +        result = mHardware->startPreview();      } else { -        mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME); -        ret = mHardware->startPreview(); -        if (ret != NO_ERROR) return ret; +        enableMsgType(CAMERA_MSG_PREVIEW_FRAME); +        result = mHardware->startPreview(); +        if (result != NO_ERROR) return result;          // If preview display has been set, register preview buffers now.          if (mSurface != 0) { -           // Unregister here because the surface registered with raw heap. +           // Unregister here because the surface may be previously registered +           // with the raw (snapshot) heap.             mSurface->unregisterBuffers(); -           ret = registerPreviewBuffers(); +           result = registerPreviewBuffers();          }      } -    return ret; +    return result;  } -status_t CameraService::Client::startPreview() -{ -    LOGV("startPreview (pid %d)", getCallingPid()); - -    return startCameraMode(CAMERA_PREVIEW_MODE); -} +status_t CameraService::Client::startRecordingMode() { +    LOG1("startRecordingMode"); +    status_t result = NO_ERROR; -status_t CameraService::Client::startRecording() -{ -    LOGV("startRecording (pid %d)", getCallingPid()); +    // if recording has been enabled, nothing needs to be done +    if (mHardware->recordingEnabled()) { +        return NO_ERROR; +    } -    if (mMediaPlayerBeep.get() != NULL) { -        // do not play record jingle if stream volume is 0 -        // (typically because ringer mode is silent). -        int index; -        AudioSystem::getStreamVolumeIndex(AudioSystem::ENFORCED_AUDIBLE, &index); -        if (index != 0) { -            mMediaPlayerBeep->seekTo(0); -            mMediaPlayerBeep->start(); +    // if preview has not been started, start preview first +    if (!mHardware->previewEnabled()) { +        result = startPreviewMode(); +        if (result != NO_ERROR) { +            return result;          }      } -    mHardware->enableMsgType(CAMERA_MSG_VIDEO_FRAME); - -    return startCameraMode(CAMERA_RECORDING_MODE); +    // start recording mode +    enableMsgType(CAMERA_MSG_VIDEO_FRAME); +    mCameraService->playSound(SOUND_RECORDING); +    result = mHardware->startRecording(); +    if (result != NO_ERROR) { +        LOGE("mHardware->startRecording() failed with status %d", result); +    } +    return result;  }  // stop preview mode -void CameraService::Client::stopPreview() -{ -    LOGV("stopPreview (pid %d)", getCallingPid()); - -    // hold main lock during state transition -    { -        Mutex::Autolock lock(mLock); -        if (checkPid() != NO_ERROR) return; - -        if (mHardware == 0) { -            LOGE("mHardware is NULL, returning."); -            return; -        } +void CameraService::Client::stopPreview() { +    LOG1("stopPreview (pid %d)", getCallingPid()); +    Mutex::Autolock lock(mLock); +    if (checkPidAndHardware() != NO_ERROR) return; -        mHardware->stopPreview(); -        mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME); -        LOGV("stopPreview(), hardware stopped OK"); +    disableMsgType(CAMERA_MSG_PREVIEW_FRAME); +    mHardware->stopPreview(); -        if (mSurface != 0 && !mUseOverlay) { -            mSurface->unregisterBuffers(); -        } +    if (mSurface != 0 && !mUseOverlay) { +        mSurface->unregisterBuffers();      } -    // hold preview buffer lock -    { -        Mutex::Autolock lock(mPreviewLock); -        mPreviewBuffer.clear(); -    } +    mPreviewBuffer.clear();  }  // stop recording mode -void CameraService::Client::stopRecording() -{ -    LOGV("stopRecording (pid %d)", getCallingPid()); - -    // hold main lock during state transition -    { -        Mutex::Autolock lock(mLock); -        if (checkPid() != NO_ERROR) return; - -        if (mHardware == 0) { -            LOGE("mHardware is NULL, returning."); -            return; -        } - -        if (mMediaPlayerBeep.get() != NULL) { -            mMediaPlayerBeep->seekTo(0); -            mMediaPlayerBeep->start(); -        } +void CameraService::Client::stopRecording() { +    LOG1("stopRecording (pid %d)", getCallingPid()); +    Mutex::Autolock lock(mLock); +    if (checkPidAndHardware() != NO_ERROR) return; -        mHardware->stopRecording(); -        mHardware->disableMsgType(CAMERA_MSG_VIDEO_FRAME); -        LOGV("stopRecording(), hardware stopped OK"); -    } +    mCameraService->playSound(SOUND_RECORDING); +    disableMsgType(CAMERA_MSG_VIDEO_FRAME); +    mHardware->stopRecording(); -    // hold preview buffer lock -    { -        Mutex::Autolock lock(mPreviewLock); -        mPreviewBuffer.clear(); -    } +    mPreviewBuffer.clear();  }  // release a recording frame -void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem) -{ +void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem) {      Mutex::Autolock lock(mLock); -    if (checkPid() != NO_ERROR) return; - -    if (mHardware == 0) { -        LOGE("mHardware is NULL, returning."); -        return; -    } - +    if (checkPidAndHardware() != NO_ERROR) return;      mHardware->releaseRecordingFrame(mem);  } -bool CameraService::Client::previewEnabled() -{ +bool CameraService::Client::previewEnabled() { +    LOG1("previewEnabled (pid %d)", getCallingPid()); +      Mutex::Autolock lock(mLock); -    if (mHardware == 0) return false; +    if (checkPidAndHardware() != NO_ERROR) return false;      return mHardware->previewEnabled();  } -bool CameraService::Client::recordingEnabled() -{ +bool CameraService::Client::recordingEnabled() { +    LOG1("recordingEnabled (pid %d)", getCallingPid()); +      Mutex::Autolock lock(mLock); -    if (mHardware == 0) return false; +    if (checkPidAndHardware() != NO_ERROR) return false;      return mHardware->recordingEnabled();  } -// Safely retrieves a strong pointer to the client during a hardware callback. -sp<CameraService::Client> CameraService::Client::getClientFromCookie(void* user) -{ -    sp<Client> client = 0; -    CameraService *service = static_cast<CameraService*>(user); -    if (service != NULL) { -        Mutex::Autolock ourLock(service->mServiceLock); -        if (service->mClient != 0) { -            client = service->mClient.promote(); -            if (client == 0) { -                LOGE("getClientFromCookie: client appears to have died"); -                service->mClient.clear(); -            } -        } else { -            LOGE("getClientFromCookie: got callback but client was NULL"); -        } -    } -    return client; -} +status_t CameraService::Client::autoFocus() { +    LOG1("autoFocus (pid %d)", getCallingPid()); +    Mutex::Autolock lock(mLock); +    status_t result = checkPidAndHardware(); +    if (result != NO_ERROR) return result; -#if DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE || \ -    DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE || \ -    DEBUG_DUMP_PREVIEW_FRAME_TO_FILE -static void dump_to_file(const char *fname, -                         uint8_t *buf, uint32_t size) -{ -    int nw, cnt = 0; -    uint32_t written = 0; +    return mHardware->autoFocus(); +} -    LOGV("opening file [%s]\n", fname); -    int fd = open(fname, O_RDWR | O_CREAT); -    if (fd < 0) { -        LOGE("failed to create file [%s]: %s", fname, strerror(errno)); -        return; -    } +status_t CameraService::Client::cancelAutoFocus() { +    LOG1("cancelAutoFocus (pid %d)", getCallingPid()); -    LOGV("writing %d bytes to file [%s]\n", size, fname); -    while (written < size) { -        nw = ::write(fd, -                     buf + written, -                     size - written); -        if (nw < 0) { -            LOGE("failed to write to file [%s]: %s", -                 fname, strerror(errno)); -            break; -        } -        written += nw; -        cnt++; -    } -    LOGV("done writing %d bytes to file [%s] in %d passes\n", -         size, fname, cnt); -    ::close(fd); +    Mutex::Autolock lock(mLock); +    status_t result = checkPidAndHardware(); +    if (result != NO_ERROR) return result; + +    return mHardware->cancelAutoFocus();  } -#endif -status_t CameraService::Client::autoFocus() -{ -    LOGV("autoFocus (pid %d)", getCallingPid()); +// take a picture - image is returned in callback +status_t CameraService::Client::takePicture() { +    LOG1("takePicture (pid %d)", getCallingPid());      Mutex::Autolock lock(mLock); -    status_t result = checkPid(); +    status_t result = checkPidAndHardware();      if (result != NO_ERROR) return result; -    if (mHardware == 0) { -        LOGE("mHardware is NULL, returning."); -        return INVALID_OPERATION; -    } +    enableMsgType(CAMERA_MSG_SHUTTER | +                  CAMERA_MSG_POSTVIEW_FRAME | +                  CAMERA_MSG_RAW_IMAGE | +                  CAMERA_MSG_COMPRESSED_IMAGE); -    return mHardware->autoFocus(); +    return mHardware->takePicture();  } -status_t CameraService::Client::cancelAutoFocus() -{ -    LOGV("cancelAutoFocus (pid %d)", getCallingPid()); +// set preview/capture parameters - key/value pairs +status_t CameraService::Client::setParameters(const String8& params) { +    LOG1("setParameters (pid %d) (%s)", getCallingPid(), params.string());      Mutex::Autolock lock(mLock); -    status_t result = checkPid(); +    status_t result = checkPidAndHardware();      if (result != NO_ERROR) return result; -    if (mHardware == 0) { -        LOGE("mHardware is NULL, returning."); -        return INVALID_OPERATION; -    } - -    return mHardware->cancelAutoFocus(); +    CameraParameters p(params); +    return mHardware->setParameters(p);  } -// take a picture - image is returned in callback -status_t CameraService::Client::takePicture() -{ -    LOGV("takePicture (pid %d)", getCallingPid()); +// get preview/capture parameters - key/value pairs +String8 CameraService::Client::getParameters() const { +    Mutex::Autolock lock(mLock); +    if (checkPidAndHardware() != NO_ERROR) return String8(); +    String8 params(mHardware->getParameters().flatten()); +    LOG1("getParameters (pid %d) (%s)", getCallingPid(), params.string()); +    return params; +} + +status_t CameraService::Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) { +    LOG1("sendCommand (pid %d)", getCallingPid());      Mutex::Autolock lock(mLock); -    status_t result = checkPid(); +    status_t result = checkPidAndHardware();      if (result != NO_ERROR) return result; -    if (mHardware == 0) { -        LOGE("mHardware is NULL, returning."); -        return INVALID_OPERATION; +    if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) { +        // The orientation cannot be set during preview. +        if (mHardware->previewEnabled()) { +            return INVALID_OPERATION; +        } +        switch (arg1) { +            case 0: +                mOrientation = ISurface::BufferHeap::ROT_0; +                break; +            case 90: +                mOrientation = ISurface::BufferHeap::ROT_90; +                break; +            case 180: +                mOrientation = ISurface::BufferHeap::ROT_180; +                break; +            case 270: +                mOrientation = ISurface::BufferHeap::ROT_270; +                break; +            default: +                return BAD_VALUE; +        } +        return OK;      } -    mHardware->enableMsgType(CAMERA_MSG_SHUTTER | -                             CAMERA_MSG_POSTVIEW_FRAME | -                             CAMERA_MSG_RAW_IMAGE | -                             CAMERA_MSG_COMPRESSED_IMAGE); +    return mHardware->sendCommand(cmd, arg1, arg2); +} -    return mHardware->takePicture(); +// ---------------------------------------------------------------------------- + +void CameraService::Client::enableMsgType(int32_t msgType) { +    android_atomic_or(msgType, &mMsgEnabled); +    mHardware->enableMsgType(msgType);  } -// snapshot taken -void CameraService::Client::handleShutter( -    image_rect_type *size // The width and height of yuv picture for -                          // registerBuffer. If this is NULL, use the picture -                          // size from parameters. -) -{ -    // Play shutter sound. -    if (mMediaPlayerClick.get() != NULL) { -        // do not play shutter sound if stream volume is 0 -        // (typically because ringer mode is silent). -        int index; -        AudioSystem::getStreamVolumeIndex(AudioSystem::ENFORCED_AUDIBLE, &index); -        if (index != 0) { -            mMediaPlayerClick->seekTo(0); -            mMediaPlayerClick->start(); +void CameraService::Client::disableMsgType(int32_t msgType) { +    android_atomic_and(~msgType, &mMsgEnabled); +    mHardware->disableMsgType(msgType); +} + +#define CHECK_MESSAGE_INTERVAL 10 // 10ms +bool CameraService::Client::lockIfMessageWanted(int32_t msgType) { +    int sleepCount = 0; +    while (mMsgEnabled & msgType) { +        if (mLock.tryLock() == NO_ERROR) { +            if (sleepCount > 0) { +                LOG1("lockIfMessageWanted(%d): waited for %d ms", +                    msgType, sleepCount * CHECK_MESSAGE_INTERVAL); +            } +            return true;          } +        if (sleepCount++ == 0) { +            LOG1("lockIfMessageWanted(%d): enter sleep", msgType); +        } +        usleep(CHECK_MESSAGE_INTERVAL * 1000); +    } +    LOGW("lockIfMessageWanted(%d): dropped unwanted message", msgType); +    return false; +} + +// ---------------------------------------------------------------------------- + +// Converts from a raw pointer to the client to a strong pointer during a +// hardware callback. This requires the callbacks only happen when the client +// is still alive. +sp<CameraService::Client> CameraService::Client::getClientFromCookie(void* user) { +    sp<Client> client = gCameraService->getClientById((int) user); + +    // This could happen if the Client is in the process of shutting down (the +    // last strong reference is gone, but the destructor hasn't finished +    // stopping the hardware). +    if (client == 0) return NULL; + +    // The checks below are not necessary and are for debugging only. +    if (client->mCameraService.get() != gCameraService) { +        LOGE("mismatch service!"); +        return NULL;      } +    if (client->mHardware == 0) { +        LOGE("mHardware == 0: callback after disconnect()?"); +        return NULL; +    } + +    return client; +} + +// Callback messages can be dispatched to internal handlers or pass to our +// client's callback functions, depending on the message type. +// +// notifyCallback: +//      CAMERA_MSG_SHUTTER              handleShutter +//      (others)                        c->notifyCallback +// dataCallback: +//      CAMERA_MSG_PREVIEW_FRAME        handlePreviewData +//      CAMERA_MSG_POSTVIEW_FRAME       handlePostview +//      CAMERA_MSG_RAW_IMAGE            handleRawPicture +//      CAMERA_MSG_COMPRESSED_IMAGE     handleCompressedPicture +//      (others)                        c->dataCallback +// dataCallbackTimestamp +//      (others)                        c->dataCallbackTimestamp +// +// NOTE: the *Callback functions grab mLock of the client before passing +// control to handle* functions. So the handle* functions must release the +// lock before calling the ICameraClient's callbacks, so those callbacks can +// invoke methods in the Client class again (For example, the preview frame +// callback may want to releaseRecordingFrame). The handle* functions must +// release the lock after all accesses to member variables, so it must be +// handled very carefully. + +void CameraService::Client::notifyCallback(int32_t msgType, int32_t ext1, +        int32_t ext2, void* user) { +    LOG2("notifyCallback(%d)", msgType); + +    sp<Client> client = getClientFromCookie(user); +    if (client == 0) return; +    if (!client->lockIfMessageWanted(msgType)) return; + +    switch (msgType) { +        case CAMERA_MSG_SHUTTER: +            // ext1 is the dimension of the yuv picture. +            client->handleShutter((image_rect_type *)ext1); +            break; +        default: +            client->handleGenericNotify(msgType, ext1, ext2); +            break; +    } +} + +void CameraService::Client::dataCallback(int32_t msgType, +        const sp<IMemory>& dataPtr, void* user) { +    LOG2("dataCallback(%d)", msgType); + +    sp<Client> client = getClientFromCookie(user); +    if (client == 0) return; +    if (!client->lockIfMessageWanted(msgType)) return; + +    if (dataPtr == 0) { +        LOGE("Null data returned in data callback"); +        client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0); +        return; +    } + +    switch (msgType) { +        case CAMERA_MSG_PREVIEW_FRAME: +            client->handlePreviewData(dataPtr); +            break; +        case CAMERA_MSG_POSTVIEW_FRAME: +            client->handlePostview(dataPtr); +            break; +        case CAMERA_MSG_RAW_IMAGE: +            client->handleRawPicture(dataPtr); +            break; +        case CAMERA_MSG_COMPRESSED_IMAGE: +            client->handleCompressedPicture(dataPtr); +            break; +        default: +            client->handleGenericData(msgType, dataPtr); +            break; +    } +} + +void CameraService::Client::dataCallbackTimestamp(nsecs_t timestamp, +        int32_t msgType, const sp<IMemory>& dataPtr, void* user) { +    LOG2("dataCallbackTimestamp(%d)", msgType); + +    sp<Client> client = getClientFromCookie(user); +    if (client == 0) return; +    if (!client->lockIfMessageWanted(msgType)) return; + +    if (dataPtr == 0) { +        LOGE("Null data returned in data with timestamp callback"); +        client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0); +        return; +    } + +    client->handleGenericDataTimestamp(timestamp, msgType, dataPtr); +} + +// snapshot taken callback +// "size" is the width and height of yuv picture for registerBuffer. +// If it is NULL, use the picture size from parameters. +void CameraService::Client::handleShutter(image_rect_type *size) { +    mCameraService->playSound(SOUND_SHUTTER); +      // Screen goes black after the buffer is unregistered.      if (mSurface != 0 && !mUseOverlay) {          mSurface->unregisterBuffers();      }      sp<ICameraClient> c = mCameraClient; -    if (c != NULL) { +    if (c != 0) { +        mLock.unlock();          c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0); +        if (!lockIfMessageWanted(CAMERA_MSG_SHUTTER)) return;      } -    mHardware->disableMsgType(CAMERA_MSG_SHUTTER); +    disableMsgType(CAMERA_MSG_SHUTTER);      // It takes some time before yuvPicture callback to be called.      // Register the buffer for raw image here to reduce latency. @@ -927,7 +1037,7 @@ void CameraService::Client::handleShutter(              h = size->height;              w &= ~1;              h &= ~1; -            LOGV("Snapshot image width=%d, height=%d", w, h); +            LOG1("Snapshot image width=%d, height=%d", w, h);          }          // FIXME: don't use hardcoded format constants here          ISurface::BufferHeap buffers(w, h, w, h, @@ -936,37 +1046,18 @@ void CameraService::Client::handleShutter(          mSurface->registerBuffers(buffers);      } + +    mLock.unlock();  }  // preview callback - frame buffer update -void CameraService::Client::handlePreviewData(const sp<IMemory>& mem) -{ +void CameraService::Client::handlePreviewData(const sp<IMemory>& mem) {      ssize_t offset;      size_t size;      sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); -#if DEBUG_HEAP_LEAKS && 0 // debugging -    if (gWeakHeap == NULL) { -        if (gWeakHeap != heap) { -            LOGV("SETTING PREVIEW HEAP"); -            heap->trackMe(true, true); -            gWeakHeap = heap; -        } -    } -#endif -#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE -    { -        if (debug_frame_cnt++ == DEBUG_DUMP_PREVIEW_FRAME_TO_FILE) { -            dump_to_file("/data/preview.yuv", -                         (uint8_t *)heap->base() + offset, size); -        } -    } -#endif - -    if (!mUseOverlay) -    { -        Mutex::Autolock surfaceLock(mSurfaceLock); -        if (mSurface != NULL) { +    if (!mUseOverlay) { +        if (mSurface != 0) {              mSurface->postBuffer(offset);          }      } @@ -977,7 +1068,8 @@ void CameraService::Client::handlePreviewData(const sp<IMemory>& mem)      // is callback enabled?      if (!(flags & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {          // If the enable bit is off, the copy-out and one-shot bits are ignored -        LOGV("frame callback is diabled"); +        LOG2("frame callback is disabled"); +        mLock.unlock();          return;      } @@ -985,61 +1077,49 @@ void CameraService::Client::handlePreviewData(const sp<IMemory>& mem)      sp<ICameraClient> c = mCameraClient;      // clear callback flags if no client or one-shot mode -    if ((c == NULL) || (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) { -        LOGV("Disable preview callback"); +    if (c == 0 || (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) { +        LOG2("Disable preview callback");          mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK | -                                FRAME_CALLBACK_FLAG_COPY_OUT_MASK | -                                FRAME_CALLBACK_FLAG_ENABLE_MASK); -        // TODO: Shouldn't we use this API for non-overlay hardware as well? -        if (mUseOverlay) -            mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME); +                                  FRAME_CALLBACK_FLAG_COPY_OUT_MASK | +                                  FRAME_CALLBACK_FLAG_ENABLE_MASK); +        if (mUseOverlay) { +            disableMsgType(CAMERA_MSG_PREVIEW_FRAME); +        }      } -    // Is the received frame copied out or not? -    if (flags & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) { -        LOGV("frame is copied"); -        copyFrameAndPostCopiedFrame(c, heap, offset, size); +    if (c != 0) { +        // Is the received frame copied out or not? +        if (flags & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) { +            LOG2("frame is copied"); +            copyFrameAndPostCopiedFrame(c, heap, offset, size); +        } else { +            LOG2("frame is forwarded"); +            mLock.unlock(); +            c->dataCallback(CAMERA_MSG_PREVIEW_FRAME, mem); +        }      } else { -        LOGV("frame is forwarded"); -        c->dataCallback(CAMERA_MSG_PREVIEW_FRAME, mem); +        mLock.unlock();      }  }  // picture callback - postview image ready -void CameraService::Client::handlePostview(const sp<IMemory>& mem) -{ -#if DEBUG_DUMP_POSTVIEW_SNAPSHOT_TO_FILE // for testing pursposes only -    { -        ssize_t offset; -        size_t size; -        sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); -        dump_to_file("/data/postview.yuv", -                     (uint8_t *)heap->base() + offset, size); -    } -#endif +void CameraService::Client::handlePostview(const sp<IMemory>& mem) { +    disableMsgType(CAMERA_MSG_POSTVIEW_FRAME);      sp<ICameraClient> c = mCameraClient; -    if (c != NULL) { +    mLock.unlock(); +    if (c != 0) {          c->dataCallback(CAMERA_MSG_POSTVIEW_FRAME, mem);      } -    mHardware->disableMsgType(CAMERA_MSG_POSTVIEW_FRAME);  }  // picture callback - raw image ready -void CameraService::Client::handleRawPicture(const sp<IMemory>& mem) -{ +void CameraService::Client::handleRawPicture(const sp<IMemory>& mem) { +    disableMsgType(CAMERA_MSG_RAW_IMAGE); +      ssize_t offset;      size_t size;      sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); -#if DEBUG_HEAP_LEAKS && 0 // debugging -    gWeakHeap = heap; // debugging -#endif - -    //LOGV("handleRawPicture(%d, %d)", offset, size); -#if DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE // for testing pursposes only -    dump_to_file("/data/photo.yuv", -                 (uint8_t *)heap->base() + offset, size); -#endif      // Put the YUV version of the snapshot in the preview display.      if (mSurface != 0 && !mUseOverlay) { @@ -1047,250 +1127,90 @@ void CameraService::Client::handleRawPicture(const sp<IMemory>& mem)      }      sp<ICameraClient> c = mCameraClient; -    if (c != NULL) { +    mLock.unlock(); +    if (c != 0) {          c->dataCallback(CAMERA_MSG_RAW_IMAGE, mem);      } -    mHardware->disableMsgType(CAMERA_MSG_RAW_IMAGE);  }  // picture callback - compressed picture ready -void CameraService::Client::handleCompressedPicture(const sp<IMemory>& mem) -{ -#if DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE // for testing pursposes only -    { -        ssize_t offset; -        size_t size; -        sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); -        dump_to_file("/data/photo.jpg", -                     (uint8_t *)heap->base() + offset, size); -    } -#endif +void CameraService::Client::handleCompressedPicture(const sp<IMemory>& mem) { +    disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);      sp<ICameraClient> c = mCameraClient; -    if (c != NULL) { +    mLock.unlock(); +    if (c != 0) {          c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem);      } -    mHardware->disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);  } -void CameraService::Client::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user) -{ -    LOGV("notifyCallback(%d)", msgType); -    sp<Client> client = getClientFromCookie(user); -    if (client == 0) { -        return; -    } - -    switch (msgType) { -        case CAMERA_MSG_SHUTTER: -            // ext1 is the dimension of the yuv picture. -            client->handleShutter((image_rect_type *)ext1); -            break; -        default: -            sp<ICameraClient> c = client->mCameraClient; -            if (c != NULL) { -                c->notifyCallback(msgType, ext1, ext2); -            } -            break; -    } - -#if DEBUG_CLIENT_REFERENCES -    if (client->getStrongCount() == 1) { -        LOGE("++++++++++++++++ (NOTIFY CALLBACK) THIS WILL CAUSE A LOCKUP!"); -        client->printRefs(); +void CameraService::Client::handleGenericNotify(int32_t msgType, +    int32_t ext1, int32_t ext2) { +    sp<ICameraClient> c = mCameraClient; +    mLock.unlock(); +    if (c != 0) { +        c->notifyCallback(msgType, ext1, ext2);      } -#endif  } -void CameraService::Client::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, void* user) -{ -    LOGV("dataCallback(%d)", msgType); - -    sp<Client> client = getClientFromCookie(user); -    if (client == 0) { -        return; -    } - -    sp<ICameraClient> c = client->mCameraClient; -    if (dataPtr == NULL) { -        LOGE("Null data returned in data callback"); -        if (c != NULL) { -            c->notifyCallback(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0); -            c->dataCallback(msgType, NULL); -        } -        return; -    } - -    switch (msgType) { -        case CAMERA_MSG_PREVIEW_FRAME: -            client->handlePreviewData(dataPtr); -            break; -        case CAMERA_MSG_POSTVIEW_FRAME: -            client->handlePostview(dataPtr); -            break; -        case CAMERA_MSG_RAW_IMAGE: -            client->handleRawPicture(dataPtr); -            break; -        case CAMERA_MSG_COMPRESSED_IMAGE: -            client->handleCompressedPicture(dataPtr); -            break; -        default: -            if (c != NULL) { -                c->dataCallback(msgType, dataPtr); -            } -            break; -    } - -#if DEBUG_CLIENT_REFERENCES -    if (client->getStrongCount() == 1) { -        LOGE("++++++++++++++++ (DATA CALLBACK) THIS WILL CAUSE A LOCKUP!"); -        client->printRefs(); +void CameraService::Client::handleGenericData(int32_t msgType, +    const sp<IMemory>& dataPtr) { +    sp<ICameraClient> c = mCameraClient; +    mLock.unlock(); +    if (c != 0) { +        c->dataCallback(msgType, dataPtr);      } -#endif  } -void CameraService::Client::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, -                                                  const sp<IMemory>& dataPtr, void* user) -{ -    LOGV("dataCallbackTimestamp(%d)", msgType); - -    sp<Client> client = getClientFromCookie(user); -    if (client == 0) { -        return; -    } -    sp<ICameraClient> c = client->mCameraClient; - -    if (dataPtr == NULL) { -        LOGE("Null data returned in data with timestamp callback"); -        if (c != NULL) { -            c->notifyCallback(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0); -            c->dataCallbackTimestamp(0, msgType, NULL); -        } -        return; -    } - -    if (c != NULL) { +void CameraService::Client::handleGenericDataTimestamp(nsecs_t timestamp, +    int32_t msgType, const sp<IMemory>& dataPtr) { +    sp<ICameraClient> c = mCameraClient; +    mLock.unlock(); +    if (c != 0) {          c->dataCallbackTimestamp(timestamp, msgType, dataPtr);      } - -#if DEBUG_CLIENT_REFERENCES -    if (client->getStrongCount() == 1) { -        LOGE("++++++++++++++++ (DATA CALLBACK TIMESTAMP) THIS WILL CAUSE A LOCKUP!"); -        client->printRefs(); -    } -#endif  } -// set preview/capture parameters - key/value pairs -status_t CameraService::Client::setParameters(const String8& params) -{ -    LOGV("setParameters(%s)", params.string()); - -    Mutex::Autolock lock(mLock); -    status_t result = checkPid(); -    if (result != NO_ERROR) return result; - -    if (mHardware == 0) { -        LOGE("mHardware is NULL, returning."); -        return INVALID_OPERATION; -    } - -    CameraParameters p(params); - -    return mHardware->setParameters(p); -} - -// get preview/capture parameters - key/value pairs -String8 CameraService::Client::getParameters() const -{ -    Mutex::Autolock lock(mLock); - -    if (mHardware == 0) { -        LOGE("mHardware is NULL, returning."); -        return String8(); -    } - -    String8 params(mHardware->getParameters().flatten()); -    LOGV("getParameters(%s)", params.string()); -    return params; -} - -status_t CameraService::Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) -{ -    LOGV("sendCommand (pid %d)", getCallingPid()); -    Mutex::Autolock lock(mLock); -    status_t result = checkPid(); -    if (result != NO_ERROR) return result; - -    if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) { -        // The orientation cannot be set during preview. -        if (mHardware->previewEnabled()) { -            return INVALID_OPERATION; -        } -        switch (arg1) { -            case 0: -                mOrientation = ISurface::BufferHeap::ROT_0; -                break; -            case 90: -                mOrientation = ISurface::BufferHeap::ROT_90; -                break; -            case 180: -                mOrientation = ISurface::BufferHeap::ROT_180; -                break; -            case 270: -                mOrientation = ISurface::BufferHeap::ROT_270; -                break; -            default: -                return BAD_VALUE; -        } -        return OK; -    } - -    if (mHardware == 0) { -        LOGE("mHardware is NULL, returning."); -        return INVALID_OPERATION; -    } - -    return mHardware->sendCommand(cmd, arg1, arg2); -} - -void CameraService::Client::copyFrameAndPostCopiedFrame(const sp<ICameraClient>& client, -        const sp<IMemoryHeap>& heap, size_t offset, size_t size) -{ -    LOGV("copyFrameAndPostCopiedFrame"); +void CameraService::Client::copyFrameAndPostCopiedFrame( +        const sp<ICameraClient>& client, const sp<IMemoryHeap>& heap, +        size_t offset, size_t size) { +    LOG2("copyFrameAndPostCopiedFrame");      // It is necessary to copy out of pmem before sending this to      // the callback. For efficiency, reuse the same MemoryHeapBase      // provided it's big enough. Don't allocate the memory or      // perform the copy if there's no callback. -      // hold the preview lock while we grab a reference to the preview buffer      sp<MemoryHeapBase> previewBuffer; -    { -        Mutex::Autolock lock(mPreviewLock); -        if (mPreviewBuffer == 0) { -            mPreviewBuffer = new MemoryHeapBase(size, 0, NULL); -        } else if (size > mPreviewBuffer->virtualSize()) { -            mPreviewBuffer.clear(); -            mPreviewBuffer = new MemoryHeapBase(size, 0, NULL); -        } -        if (mPreviewBuffer == 0) { -            LOGE("failed to allocate space for preview buffer"); -            return; -        } -        previewBuffer = mPreviewBuffer; + +    if (mPreviewBuffer == 0) { +        mPreviewBuffer = new MemoryHeapBase(size, 0, NULL); +    } else if (size > mPreviewBuffer->virtualSize()) { +        mPreviewBuffer.clear(); +        mPreviewBuffer = new MemoryHeapBase(size, 0, NULL); +    } +    if (mPreviewBuffer == 0) { +        LOGE("failed to allocate space for preview buffer"); +        mLock.unlock(); +        return;      } -    memcpy(previewBuffer->base(), -           (uint8_t *)heap->base() + offset, size); +    previewBuffer = mPreviewBuffer; + +    memcpy(previewBuffer->base(), (uint8_t *)heap->base() + offset, size);      sp<MemoryBase> frame = new MemoryBase(previewBuffer, 0, size);      if (frame == 0) {          LOGE("failed to allocate space for frame callback"); +        mLock.unlock();          return;      } + +    mLock.unlock();      client->dataCallback(CAMERA_MSG_PREVIEW_FRAME, frame);  } +// ---------------------------------------------------------------------------- +  static const int kDumpLockRetries = 50;  static const int kDumpLockSleep = 60000; @@ -1307,8 +1227,7 @@ static bool tryLock(Mutex& mutex)      return locked;  } -status_t CameraService::dump(int fd, const Vector<String16>& args) -{ +status_t CameraService::dump(int fd, const Vector<String16>& args) {      static const char* kDeadlockedString = "CameraService may be deadlocked\n";      const size_t SIZE = 256; @@ -1318,7 +1237,7 @@ status_t CameraService::dump(int fd, const Vector<String16>& args)          snprintf(buffer, SIZE, "Permission Denial: "                  "can't dump CameraService from pid=%d, uid=%d\n",                  getCallingPid(), -                IPCThreadState::self()->getCallingUid()); +                getCallingUid());          result.append(buffer);          write(fd, result.string(), result.size());      } else { @@ -1329,89 +1248,39 @@ status_t CameraService::dump(int fd, const Vector<String16>& args)              write(fd, result.string(), result.size());          } -        if (mClient != 0) { -            sp<Client> currentClient = mClient.promote(); -            sprintf(buffer, "Client (%p) PID: %d\n", -                    currentClient->getCameraClient()->asBinder().get(), -                    currentClient->mClientPid); +        bool hasClient = false; +        for (int i = 0; i < NUM_CAMERAS; i++) { +            sp<Client> client = mClient[i].promote(); +            if (client == 0) continue; +            hasClient = true; +            sprintf(buffer, "Client[%d] (%p) PID: %d\n", +                    i, +                    client->getCameraClient()->asBinder().get(), +                    client->mClientPid);              result.append(buffer);              write(fd, result.string(), result.size()); -            currentClient->mHardware->dump(fd, args); -        } else { +            client->mHardware->dump(fd, args); +        } +        if (!hasClient) {              result.append("No camera client yet.\n");              write(fd, result.string(), result.size());          }          if (locked) mServiceLock.unlock(); -    } -    return NO_ERROR; -} - -status_t CameraService::onTransact( -    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ -    // permission checks... -    switch (code) { -        case BnCameraService::CONNECT: -            IPCThreadState* ipc = IPCThreadState::self(); -            const int pid = ipc->getCallingPid(); -            const int self_pid = getpid(); -            if (pid != self_pid) { -                // we're called from a different process, do the real check -                if (!checkCallingPermission( -                        String16("android.permission.CAMERA"))) -                { -                    const int uid = ipc->getCallingUid(); -                    LOGE("Permission Denial: " -                            "can't use the camera pid=%d, uid=%d", pid, uid); -                    return PERMISSION_DENIED; -                } -            } -            break; -    } - -    status_t err = BnCameraService::onTransact(code, data, reply, flags); - -#if DEBUG_HEAP_LEAKS -    LOGV("+++ onTransact err %d code %d", err, code); - -    if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) { -        // the 'service' command interrogates this binder for its name, and then supplies it -        // even for the debugging commands.  that means we need to check for it here, using -        // ISurfaceComposer (since we delegated the INTERFACE_TRANSACTION handling to -        // BnSurfaceComposer before falling through to this code). - -        LOGV("+++ onTransact code %d", code); - -        CHECK_INTERFACE(ICameraService, data, reply); - -        switch(code) { -        case 1000: -        { -            if (gWeakHeap != 0) { -                sp<IMemoryHeap> h = gWeakHeap.promote(); -                IMemoryHeap *p = gWeakHeap.unsafe_get(); -                LOGV("CHECKING WEAK REFERENCE %p (%p)", h.get(), p); -                if (h != 0) -                    h->printRefs(); -                bool attempt_to_delete = data.readInt32() == 1; -                if (attempt_to_delete) { -                    // NOT SAFE! -                    LOGV("DELETING WEAK REFERENCE %p (%p)", h.get(), p); -                    if (p) delete p; -                } -                return NO_ERROR; +        // change logging level +        int n = args.size(); +        for (int i = 0; i + 1 < n; i++) { +            if (args[i] == String16("-v")) { +                String8 levelStr(args[i+1]); +                int level = atoi(levelStr.string()); +                sprintf(buffer, "Set Log Level to %d", level); +                result.append(buffer); +                setLogLevel(level);              }          } -        break; -        default: -            break; -        }      } -#endif // DEBUG_HEAP_LEAKS - -    return err; +    return NO_ERROR;  }  }; // namespace android diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h index bc49b1dbd5..86986cab82 100644 --- a/camera/libcameraservice/CameraService.h +++ b/camera/libcameraservice/CameraService.h @@ -21,207 +21,171 @@  #include <camera/ICameraService.h>  #include <camera/CameraHardwareInterface.h> -#include <camera/Camera.h> + +/* This needs to be increased if we can have more cameras */ +#define MAX_CAMERAS 2  namespace android {  class MemoryHeapBase;  class MediaPlayer; -// ---------------------------------------------------------------------------- - -#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  )) -#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false )) - -// When enabled, this feature allows you to send an event to the CameraService -// so that you can cause all references to the heap object gWeakHeap, defined -// below, to be printed. You will also need to set DEBUG_REFS=1 and -// DEBUG_REFS_ENABLED_BY_DEFAULT=0 in libutils/RefBase.cpp. You just have to -// set gWeakHeap to the appropriate heap you want to track. - -#define DEBUG_HEAP_LEAKS 0 - -// ---------------------------------------------------------------------------- - -class CameraService : public BnCameraService +class CameraService: public BnCameraService  {      class Client; -  public: -    static void instantiate(); +    static void         instantiate(); + +                        CameraService(); +    virtual             ~CameraService(); -    // ICameraService interface -    virtual sp<ICamera>     connect(const sp<ICameraClient>& cameraClient); +    virtual int32_t     getNumberOfCameras(); +    virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId); +    virtual void        removeClient(const sp<ICameraClient>& cameraClient); +    virtual sp<Client>  getClientById(int cameraId); -    virtual status_t        dump(int fd, const Vector<String16>& args); +    virtual status_t    dump(int fd, const Vector<String16>& args); +    virtual status_t    onTransact(uint32_t code, const Parcel& data, +                                   Parcel* reply, uint32_t flags); -            void            removeClient(const sp<ICameraClient>& cameraClient); +    enum sound_kind { +        SOUND_SHUTTER = 0, +        SOUND_RECORDING = 1, +        NUM_SOUNDS +    }; -    virtual status_t onTransact( -        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); +    void                loadSound(); +    void                playSound(sound_kind kind); +    void                releaseSound();  private: +    Mutex               mServiceLock; +    wp<Client>          mClient[MAX_CAMERAS];  // protected by mServiceLock -// ---------------------------------------------------------------------------- +    // atomics to record whether the hardware is allocated to some client. +    volatile int32_t    mBusy[MAX_CAMERAS]; +    void                setCameraBusy(int cameraId); +    void                setCameraFree(int cameraId); -    class Client : public BnCamera { +    // sounds +    Mutex               mSoundLock; +    sp<MediaPlayer>     mSoundPlayer[NUM_SOUNDS]; +    int                 mSoundRef;  // reference count (release all MediaPlayer when 0) +    class Client : public BnCamera +    {      public: +        // ICamera interface (see ICamera for details)          virtual void            disconnect(); - -        // connect new client with existing camera remote          virtual status_t        connect(const sp<ICameraClient>& client); - -        // prevent other processes from using this ICamera interface          virtual status_t        lock(); - -        // allow other processes to use this ICamera interface          virtual status_t        unlock(); - -        // pass the buffered ISurface to the camera service          virtual status_t        setPreviewDisplay(const sp<ISurface>& surface); - -        // set the preview callback flag to affect how the received frames from -        // preview are handled. -        virtual void            setPreviewCallbackFlag(int callback_flag); - -        // start preview mode, must call setPreviewDisplay first +        virtual void            setPreviewCallbackFlag(int flag);          virtual status_t        startPreview(); - -        // stop preview mode          virtual void            stopPreview(); - -        // get preview state          virtual bool            previewEnabled(); - -        // start recording mode          virtual status_t        startRecording(); - -        // stop recording mode          virtual void            stopRecording(); - -        // get recording state          virtual bool            recordingEnabled(); - -        // release a recording frame          virtual void            releaseRecordingFrame(const sp<IMemory>& mem); - -        // auto focus          virtual status_t        autoFocus(); - -        // cancel auto focus          virtual status_t        cancelAutoFocus(); - -        // take a picture - returns an IMemory (ref-counted mmap)          virtual status_t        takePicture(); - -        // set preview/capture parameters - key/value pairs          virtual status_t        setParameters(const String8& params); - -        // get preview/capture parameters - key/value pairs          virtual String8         getParameters() const; - -        // send command to camera driver          virtual status_t        sendCommand(int32_t cmd, int32_t arg1, int32_t arg2); - -        // our client... -        const sp<ICameraClient>&    getCameraClient() const { return mCameraClient; } -      private:          friend class CameraService;                                  Client(const sp<CameraService>& cameraService, -                                        const sp<ICameraClient>& cameraClient, -                                        pid_t clientPid); -                                Client(); -        virtual                 ~Client(); - -                    status_t    checkPid(); - -        static      void        notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user); -        static      void        dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, void* user); -        static      void        dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, -                                                      const sp<IMemory>& dataPtr, void* user); +                                       const sp<ICameraClient>& cameraClient, +                                       int cameraId, +                                       int clientPid); +                                ~Client(); -        static      sp<Client>  getClientFromCookie(void* user); +        // return our camera client +        const sp<ICameraClient>&    getCameraClient() { return mCameraClient; } -                    void        handlePreviewData(const sp<IMemory>&); -                    void        handleShutter(image_rect_type *image); -                    void        handlePostview(const sp<IMemory>&); -                    void        handleRawPicture(const sp<IMemory>&); -                    void        handleCompressedPicture(const sp<IMemory>&); +        // check whether the calling process matches mClientPid. +        status_t                checkPid() const; +        status_t                checkPidAndHardware() const;  // also check mHardware != 0 -                    void        copyFrameAndPostCopiedFrame(const sp<ICameraClient>& client, -                                    const sp<IMemoryHeap>& heap, size_t offset, size_t size); +        // these are internal functions used to set up preview buffers +        status_t                registerPreviewBuffers(); +        status_t                setOverlay();          // camera operation mode          enum camera_mode {              CAMERA_PREVIEW_MODE   = 0,  // frame automatically released              CAMERA_RECORDING_MODE = 1,  // frame has to be explicitly released by releaseRecordingFrame()          }; +        // these are internal functions used for preview/recording          status_t                startCameraMode(camera_mode mode);          status_t                startPreviewMode();          status_t                startRecordingMode(); -        status_t                setOverlay(); -        status_t                registerPreviewBuffers(); + +        // these are static callback functions +        static void             notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user); +        static void             dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, void* user); +        static void             dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr, void* user); +        // convert client from cookie +        static sp<Client>       getClientFromCookie(void* user); +        // handlers for messages +        void                    handleShutter(image_rect_type *size); +        void                    handlePreviewData(const sp<IMemory>& mem); +        void                    handlePostview(const sp<IMemory>& mem); +        void                    handleRawPicture(const sp<IMemory>& mem); +        void                    handleCompressedPicture(const sp<IMemory>& mem); +        void                    handleGenericNotify(int32_t msgType, int32_t ext1, int32_t ext2); +        void                    handleGenericData(int32_t msgType, const sp<IMemory>& dataPtr); +        void                    handleGenericDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr); + +        void                    copyFrameAndPostCopiedFrame( +                                    const sp<ICameraClient>& client, +                                    const sp<IMemoryHeap>& heap, +                                    size_t offset, size_t size); + +        // these are initialized in the constructor. +        sp<CameraService>               mCameraService;  // immutable after constructor +        sp<ICameraClient>               mCameraClient; +        int                             mCameraId;       // immutable after constructor +        pid_t                           mClientPid; +        sp<CameraHardwareInterface>     mHardware;       // cleared after disconnect() +        bool                            mUseOverlay;     // immutable after constructor +        sp<OverlayRef>                  mOverlayRef; +        int                             mOverlayW; +        int                             mOverlayH; +        int                             mPreviewCallbackFlag; +        int                             mOrientation;          // Ensures atomicity among the public methods -        mutable     Mutex                       mLock; - -        // mSurfaceLock synchronizes access to mSurface between -        // setPreviewSurface() and postPreviewFrame().  Note that among -        // the public methods, all accesses to mSurface are -        // syncrhonized by mLock.  However, postPreviewFrame() is called -        // by the CameraHardwareInterface callback, and needs to -        // access mSurface.  It cannot hold mLock, however, because -        // stopPreview() may be holding that lock while attempting -        // to stop preview, and stopPreview itself will block waiting -        // for a callback from CameraHardwareInterface.  If this -        // happens, it will cause a deadlock. -        mutable     Mutex                       mSurfaceLock; -        mutable     Condition                   mReady; -                    sp<CameraService>           mCameraService; -                    sp<ISurface>                mSurface; -                    int                         mPreviewCallbackFlag; -                    int                         mOrientation; - -                    sp<MediaPlayer>             mMediaPlayerClick; -                    sp<MediaPlayer>             mMediaPlayerBeep; - -                    // these are immutable once the object is created, -                    // they don't need to be protected by a lock -                    sp<ICameraClient>           mCameraClient; -                    sp<CameraHardwareInterface> mHardware; -                    pid_t                       mClientPid; -                    bool                        mUseOverlay; - -                    sp<OverlayRef>              mOverlayRef; -                    int                         mOverlayW; -                    int                         mOverlayH; - -        mutable     Mutex                       mPreviewLock; -                    sp<MemoryHeapBase>          mPreviewBuffer; +        mutable Mutex                   mLock; +        sp<ISurface>                    mSurface; + +        // If the user want us to return a copy of the preview frame (instead +        // of the original one), we allocate mPreviewBuffer and reuse it if possible. +        sp<MemoryHeapBase>              mPreviewBuffer; + +        // We need to avoid the deadlock when the incoming command thread and +        // the CameraHardwareInterface callback thread both want to grab mLock. +        // An extra flag is used to tell the callback thread that it should stop +        // trying to deliver the callback messages if the client is not +        // interested in it anymore. For example, if the client is calling +        // stopPreview(), the preview frame messages do not need to be delivered +        // anymore. + +        // This function takes the same parameter as the enableMsgType() and +        // disableMsgType() functions in CameraHardwareInterface. +        void                    enableMsgType(int32_t msgType); +        void                    disableMsgType(int32_t msgType); +        volatile int32_t        mMsgEnabled; + +        // This function keeps trying to grab mLock, or give up if the message +        // is found to be disabled. It returns true if mLock is grabbed. +        bool                    lockIfMessageWanted(int32_t msgType);      }; - -// ---------------------------------------------------------------------------- - -                            CameraService(); -    virtual                 ~CameraService(); - -    // We use a count for number of clients (shoule only be 0 or 1). -    volatile    int32_t                     mUsers; -    virtual     void                        incUsers(); -    virtual     void                        decUsers(); - -    mutable     Mutex                       mServiceLock; -                wp<Client>                  mClient; - -#if DEBUG_HEAP_LEAKS -                wp<IMemoryHeap>             gWeakHeap; -#endif  }; -// ---------------------------------------------------------------------------- - -}; // namespace android +} // namespace android  #endif diff --git a/camera/libcameraservice/FakeCamera.cpp b/camera/libcameraservice/FakeCamera.cpp index 6749899827..f3a6a67ee8 100644 --- a/camera/libcameraservice/FakeCamera.cpp +++ b/camera/libcameraservice/FakeCamera.cpp @@ -198,10 +198,11 @@ static const int  SHIFT2 = 16;  static const int  DELTA  = kYb*(1 << SHIFT2);  static const int  GAMMA  = kYr*(1 << SHIFT2); -int32_t ccrgb16toyuv_wo_colorkey(uint8_t *rgb16,uint8_t *yuv422,uint32_t *param,uint8_t *table[]) +int32_t ccrgb16toyuv_wo_colorkey(uint8_t *rgb16, uint8_t *yuv420, +        uint32_t *param, uint8_t *table[])  {      uint16_t *inputRGB = (uint16_t*)rgb16; -    uint8_t *outYUV =  yuv422; +    uint8_t *outYUV = yuv420;      int32_t width_dst = param[0];      int32_t height_dst = param[1];      int32_t pitch_dst = param[2]; @@ -260,12 +261,14 @@ uint32_t temp;              tempY[0] = y0;              tempY[1] = y1; -            tempU[0] = u; -            tempV[0] = v; -              tempY += 2; -            tempU += 2; -            tempV += 2; + +            if ((j&1) == 0) { +                tempU[0] = u; +                tempV[0] = v; +                tempU += 2; +                tempV += 2; +            }          }          inputRGB += pitch_src; @@ -277,7 +280,7 @@ uint32_t temp;  #define min(a,b) ((a)<(b)?(a):(b))  #define max(a,b) ((a)>(b)?(a):(b)) -static void convert_rgb16_to_yuv422(uint8_t *rgb, uint8_t *yuv, int width, int height) +static void convert_rgb16_to_yuv420(uint8_t *rgb, uint8_t *yuv, int width, int height)  {      if (!tables_initialized) {          initYtab(); @@ -326,7 +329,7 @@ void FakeCamera::setSize(int width, int height)      mCheckY = 0;      // This will cause it to be reallocated on the next call -    // to getNextFrameAsYuv422(). +    // to getNextFrameAsYuv420().      delete[] mTmpRgb16Buffer;      mTmpRgb16Buffer = 0;  } @@ -347,13 +350,13 @@ void FakeCamera::getNextFrameAsRgb565(uint16_t *buffer)      mCounter++;  } -void FakeCamera::getNextFrameAsYuv422(uint8_t *buffer) +void FakeCamera::getNextFrameAsYuv420(uint8_t *buffer)  {      if (mTmpRgb16Buffer == 0)          mTmpRgb16Buffer = new uint16_t[mWidth * mHeight];      getNextFrameAsRgb565(mTmpRgb16Buffer); -    convert_rgb16_to_yuv422((uint8_t*)mTmpRgb16Buffer, buffer, mWidth, mHeight); +    convert_rgb16_to_yuv420((uint8_t*)mTmpRgb16Buffer, buffer, mWidth, mHeight);  }  void FakeCamera::drawSquare(uint16_t *dst, int x, int y, int size, int color, int shadow) diff --git a/camera/libcameraservice/FakeCamera.h b/camera/libcameraservice/FakeCamera.h index f7f880328a..724de207f8 100644 --- a/camera/libcameraservice/FakeCamera.h +++ b/camera/libcameraservice/FakeCamera.h @@ -40,7 +40,7 @@ public:      ~FakeCamera();      void setSize(int width, int height); -    void getNextFrameAsYuv422(uint8_t *buffer); +    void getNextFrameAsYuv420(uint8_t *buffer);      // Write to the fd a string representing the current state.      void dump(int fd) const; diff --git a/camera/tests/CameraServiceTest/Android.mk b/camera/tests/CameraServiceTest/Android.mk index 9bb190abcd..cf4e42ff87 100644 --- a/camera/tests/CameraServiceTest/Android.mk +++ b/camera/tests/CameraServiceTest/Android.mk @@ -21,4 +21,6 @@ LOCAL_SHARED_LIBRARIES += \                  libcamera_client \                  libsurfaceflinger_client -include $(BUILD_EXECUTABLE) +# Disable it because the ISurface interface may change, and before we have a +# chance to fix this test, we don't want to break normal builds. +#include $(BUILD_EXECUTABLE) diff --git a/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/camera/tests/CameraServiceTest/CameraServiceTest.cpp index 9fc795b3e1..3c8d55397a 100644 --- a/camera/tests/CameraServiceTest/CameraServiceTest.cpp +++ b/camera/tests/CameraServiceTest/CameraServiceTest.cpp @@ -38,7 +38,7 @@ void assert_fail(const char *file, int line, const char *func, const char *expr)      INFO("assertion failed at file %s, line %d, function %s:",              file, line, func);      INFO("%s", expr); -    exit(1); +    abort();  }  void assert_eq_fail(const char *file, int line, const char *func, @@ -46,7 +46,7 @@ void assert_eq_fail(const char *file, int line, const char *func,      INFO("assertion failed at file %s, line %d, function %s:",              file, line, func);      INFO("(expected) %s != (actual) %d", expr, actual); -    exit(1); +    abort();  }  #define ASSERT(e) \ @@ -155,7 +155,7 @@ public:      virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2);      virtual void dataCallback(int32_t msgType, const sp<IMemory>& data);      virtual void dataCallbackTimestamp(nsecs_t timestamp, -            int32_t msgType, const sp<IMemory>& data) {} +            int32_t msgType, const sp<IMemory>& data);      // new functions      void clearStat(); @@ -176,6 +176,7 @@ private:      DefaultKeyedVector<int32_t, int> mDataCount;      DefaultKeyedVector<int32_t, int> mDataSize;      bool test(OP op, int v1, int v2); +    void assertTest(OP op, int v1, int v2);      ICamera *mReleaser;  }; @@ -199,26 +200,33 @@ bool MCameraClient::test(OP op, int v1, int v2) {      return false;  } +void MCameraClient::assertTest(OP op, int v1, int v2) { +    if (!test(op, v1, v2)) { +        LOGE("assertTest failed: op=%d, v1=%d, v2=%d", op, v1, v2); +        ASSERT(0); +    } +} +  void MCameraClient::assertNotify(int32_t msgType, OP op, int count) {      Mutex::Autolock _l(mLock);      int v = mNotifyCount.valueFor(msgType); -    ASSERT(test(op, v, count)); +    assertTest(op, v, count);  }  void MCameraClient::assertData(int32_t msgType, OP op, int count) {      Mutex::Autolock _l(mLock);      int v = mDataCount.valueFor(msgType); -    ASSERT(test(op, v, count)); +    assertTest(op, v, count);  }  void MCameraClient::assertDataSize(int32_t msgType, OP op, int dataSize) {      Mutex::Autolock _l(mLock);      int v = mDataSize.valueFor(msgType); -    ASSERT(test(op, v, dataSize)); +    assertTest(op, v, dataSize);  }  void MCameraClient::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) { -    INFO(__func__); +    INFO("%s", __func__);      Mutex::Autolock _l(mLock);      ssize_t i = mNotifyCount.indexOfKey(msgType);      if (i < 0) { @@ -230,7 +238,7 @@ void MCameraClient::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)  }  void MCameraClient::dataCallback(int32_t msgType, const sp<IMemory>& data) { -    INFO(__func__); +    INFO("%s", __func__);      int dataSize = data->size();      INFO("data type = %d, size = %d", msgType, dataSize);      Mutex::Autolock _l(mLock); @@ -250,6 +258,11 @@ void MCameraClient::dataCallback(int32_t msgType, const sp<IMemory>& data) {      }  } +void MCameraClient::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, +        const sp<IMemory>& data) { +    dataCallback(msgType, data); +} +  void MCameraClient::waitNotify(int32_t msgType, OP op, int count) {      INFO("waitNotify: %d, %d, %d", msgType, op, count);      Mutex::Autolock _l(mLock); @@ -285,6 +298,7 @@ public:      virtual sp<OverlayRef> createOverlay(              uint32_t w, uint32_t h, int32_t format, int32_t orientation);      virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage); +    virtual status_t setBufferCount(int bufferCount);      // new functions      void clearStat(); @@ -300,7 +314,7 @@ private:  };  status_t MSurface::registerBuffers(const BufferHeap& buffers) { -    INFO(__func__); +    INFO("%s", __func__);      Mutex::Autolock _l(mLock);      ++registerBuffersCount;      mCond.signal(); @@ -308,21 +322,26 @@ status_t MSurface::registerBuffers(const BufferHeap& buffers) {  }  void MSurface::postBuffer(ssize_t offset) { -    // INFO(__func__); +    // INFO("%s", __func__);      Mutex::Autolock _l(mLock);      ++postBufferCount;      mCond.signal();  }  void MSurface::unregisterBuffers() { -    INFO(__func__); +    INFO("%s", __func__);      Mutex::Autolock _l(mLock);      ++unregisterBuffersCount;      mCond.signal();  }  sp<GraphicBuffer> MSurface::requestBuffer(int bufferIdx, int usage) { -    INFO(__func__); +    INFO("%s", __func__); +    return NULL; +} + +status_t MSurface::setBufferCount(int bufferCount) { +    INFO("%s", __func__);      return NULL;  } @@ -348,10 +367,9 @@ void MSurface::waitUntil(int c0, int c1, int c2) {  sp<OverlayRef> MSurface::createOverlay(uint32_t w, uint32_t h, int32_t format,          int32_t orientation) { -    // We don't expect this to be called in current hardware. +    // Not implemented.      ASSERT(0); -    sp<OverlayRef> dummy; -    return dummy; +    return NULL;  }  // @@ -368,17 +386,17 @@ sp<IHolder> getHolder() {  }  void putTempObject(sp<IBinder> obj) { -    INFO(__func__); +    INFO("%s", __func__);      getHolder()->put(obj);  }  sp<IBinder> getTempObject() { -    INFO(__func__); +    INFO("%s", __func__);      return getHolder()->get();  }  void clearTempObject() { -    INFO(__func__); +    INFO("%s", __func__);      getHolder()->clear();  } @@ -395,64 +413,71 @@ sp<ICameraService> getCameraService() {      return cs;  } +int getNumberOfCameras() { +    sp<ICameraService> cs = getCameraService(); +    return cs->getNumberOfCameras(); +} +  //  // Various Connect Tests  // -void testConnect() { -    INFO(__func__); +void testConnect(int cameraId) { +    INFO("%s", __func__);      sp<ICameraService> cs = getCameraService();      sp<MCameraClient> cc = new MCameraClient(); -    sp<ICamera> c = cs->connect(cc); +    sp<ICamera> c = cs->connect(cc, cameraId);      ASSERT(c != 0);      c->disconnect();  } -void testAllowConnectOnceOnly() { -    INFO(__func__); +void testAllowConnectOnceOnly(int cameraId) { +    INFO("%s", __func__);      sp<ICameraService> cs = getCameraService();      // Connect the first client.      sp<MCameraClient> cc = new MCameraClient(); -    sp<ICamera> c = cs->connect(cc); +    sp<ICamera> c = cs->connect(cc, cameraId);      ASSERT(c != 0);      // Same client -- ok. -    ASSERT(cs->connect(cc) != 0); +    ASSERT(cs->connect(cc, cameraId) != 0);      // Different client -- not ok.      sp<MCameraClient> cc2 = new MCameraClient(); -    ASSERT(cs->connect(cc2) == 0); +    ASSERT(cs->connect(cc2, cameraId) == 0);      c->disconnect();  }  void testReconnectFailed() { -    INFO(__func__); +    INFO("%s", __func__);      sp<ICamera> c = interface_cast<ICamera>(getTempObject()); -    sp<MCameraClient> cc2 = new MCameraClient(); -    ASSERT(c->connect(cc2) != NO_ERROR); +    sp<MCameraClient> cc = new MCameraClient(); +    ASSERT(c->connect(cc) != NO_ERROR);  }  void testReconnectSuccess() { -    INFO(__func__); +    INFO("%s", __func__);      sp<ICamera> c = interface_cast<ICamera>(getTempObject());      sp<MCameraClient> cc = new MCameraClient();      ASSERT(c->connect(cc) == NO_ERROR); +    c->disconnect();  }  void testLockFailed() { -    INFO(__func__); +    INFO("%s", __func__);      sp<ICamera> c = interface_cast<ICamera>(getTempObject());      ASSERT(c->lock() != NO_ERROR);  }  void testLockUnlockSuccess() { -    INFO(__func__); +    INFO("%s", __func__);      sp<ICamera> c = interface_cast<ICamera>(getTempObject());      ASSERT(c->lock() == NO_ERROR);      ASSERT(c->unlock() == NO_ERROR);  }  void testLockSuccess() { -    INFO(__func__); +    INFO("%s", __func__);      sp<ICamera> c = interface_cast<ICamera>(getTempObject());      ASSERT(c->lock() == NO_ERROR); +    c->disconnect();  }  // @@ -499,11 +524,11 @@ void runInAnotherProcess(const char *tag) {      }  } -void testReconnect() { -    INFO(__func__); +void testReconnect(int cameraId) { +    INFO("%s", __func__);      sp<ICameraService> cs = getCameraService();      sp<MCameraClient> cc = new MCameraClient(); -    sp<ICamera> c = cs->connect(cc); +    sp<ICamera> c = cs->connect(cc, cameraId);      ASSERT(c != 0);      // Reconnect to the same client -- ok.      ASSERT(c->connect(cc) == NO_ERROR); @@ -514,10 +539,10 @@ void testReconnect() {      cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);  } -void testLockUnlock() { +void testLockUnlock(int cameraId) {      sp<ICameraService> cs = getCameraService();      sp<MCameraClient> cc = new MCameraClient(); -    sp<ICamera> c = cs->connect(cc); +    sp<ICamera> c = cs->connect(cc, cameraId);      ASSERT(c != 0);      // We can lock as many times as we want.      ASSERT(c->lock() == NO_ERROR); @@ -530,16 +555,15 @@ void testLockUnlock() {      runInAnotherProcess("testLockUnlockSuccess");      // Unlock then lock from a different process -- ok.      runInAnotherProcess("testLockSuccess"); -    c->disconnect();      clearTempObject();  } -void testReconnectFromAnotherProcess() { -    INFO(__func__); +void testReconnectFromAnotherProcess(int cameraId) { +    INFO("%s", __func__);      sp<ICameraService> cs = getCameraService();      sp<MCameraClient> cc = new MCameraClient(); -    sp<ICamera> c = cs->connect(cc); +    sp<ICamera> c = cs->connect(cc, cameraId);      ASSERT(c != 0);      // Reconnect from a different process -- not ok.      putTempObject(c->asBinder()); @@ -547,7 +571,6 @@ void testReconnectFromAnotherProcess() {      // Unlock then reconnect from a different process -- ok.      ASSERT(c->unlock() == NO_ERROR);      runInAnotherProcess("testReconnectSuccess"); -    c->disconnect();      clearTempObject();  } @@ -560,10 +583,11 @@ static void flushCommands() {  }  // Run a test case -#define RUN(class_name) do { \ +#define RUN(class_name, cameraId) do { \      { \          INFO(#class_name); \          class_name instance; \ +        instance.init(cameraId); \          instance.run(); \      } \      flushCommands(); \ @@ -571,19 +595,21 @@ static void flushCommands() {  // Base test case after the the camera is connected.  class AfterConnect { -protected: -    sp<ICameraService> cs; -    sp<MCameraClient> cc; -    sp<ICamera> c; - -    AfterConnect() { +public: +    void init(int cameraId) {          cs = getCameraService();          cc = new MCameraClient(); -        c = cs->connect(cc); +        c = cs->connect(cc, cameraId);          ASSERT(c != 0);      } +protected: +    sp<ICameraService> cs; +    sp<MCameraClient> cc; +    sp<ICamera> c; +      ~AfterConnect() { +        c->disconnect();          c.clear();          cc.clear();          cs.clear(); @@ -612,19 +638,16 @@ public:          surface->waitUntil(1, 10, 0); // needs 1 registerBuffers and 10 postBuffer          surface->clearStat(); -        c->disconnect(); -        // TODO: CameraService crashes for this. Fix it. -#if 0          sp<MSurface> another_surface = new MSurface();          c->setPreviewDisplay(another_surface);  // just to make sure unregisterBuffers                                                  // is called.          surface->waitUntil(0, 0, 1);  // needs unregisterBuffers -#endif +          cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);      }  }; -class TestStartPreviewWithoutDisplay : AfterConnect { +class TestStartPreviewWithoutDisplay : public AfterConnect {  public:      void run() {          ASSERT(c->startPreview() == NO_ERROR); @@ -636,15 +659,17 @@ public:  // Base test case after the the camera is connected and the preview is started.  class AfterStartPreview : public AfterConnect { -protected: -    sp<MSurface> surface; - -    AfterStartPreview() { +public: +    void init(int cameraId) { +        AfterConnect::init(cameraId);          surface = new MSurface();          ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);          ASSERT(c->startPreview() == NO_ERROR);      } +protected: +    sp<MSurface> surface; +      ~AfterStartPreview() {          surface.clear();      } @@ -680,9 +705,6 @@ public:          cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);          cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);          c->stopPreview(); -#if 1  // TODO: It crashes if we don't have this. Fix it. -        usleep(100000); -#endif          c->disconnect();          cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);      } @@ -697,7 +719,6 @@ public:              cc->waitNotify(CAMERA_MSG_SHUTTER, MCameraClient::EQ, 1);              cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);              cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1); -            usleep(100000);  // 100ms          }          c->disconnect();          cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0); @@ -708,36 +729,71 @@ class TestGetParameters: public AfterStartPreview {  public:      void run() {          String8 param_str = c->getParameters(); -        INFO(param_str); +        INFO("%s", static_cast<const char*>(param_str));      }  }; +static bool getNextSize(const char **ptrS, int *w, int *h) { +    const char *s = *ptrS; + +    // skip over ',' +    if (*s == ',') s++; + +    // remember start position in p +    const char *p = s; +    while (*s != '\0' && *s != 'x') { +        s++; +    } +    if (*s == '\0') return false; + +    // get the width +    *w = atoi(p); + +    // skip over 'x' +    ASSERT(*s == 'x'); +    p = s + 1; +    while (*s != '\0' && *s != ',') { +        s++; +    } + +    // get the height +    *h = atoi(p); +    *ptrS = s; +    return true; +} +  class TestPictureSize : public AfterStartPreview {  public:      void checkOnePicture(int w, int h) { -        const float rate = 0.5;  // byte per pixel limit +        const float rate = 0.9;  // byte per pixel limit          int pixels = w * h;          CameraParameters param(c->getParameters());          param.setPictureSize(w, h); +        // disable thumbnail to get more accurate size. +        param.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, 0); +        param.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, 0);          c->setParameters(param.flatten());          cc->clearStat();          ASSERT(c->takePicture() == NO_ERROR);          cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1); -        cc->assertDataSize(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, pixels*3/2); +        //cc->assertDataSize(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, pixels*3/2);          cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);          cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::LT,                  int(pixels * rate));          cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::GT, 0);          cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0); -        usleep(100000);  // 100ms      }      void run() { -        checkOnePicture(2048, 1536); -        checkOnePicture(1600, 1200); -        checkOnePicture(1024, 768); +        CameraParameters param(c->getParameters()); +        int w, h; +        const char *s = param.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES); +        while (getNextSize(&s, &w, &h)) { +            LOGD("checking picture size %dx%d", w, h); +            checkOnePicture(w, h); +        }      }  }; @@ -749,6 +805,8 @@ public:          // Try all flag combinations.          for (int v = 0; v < 8; v++) { +            LOGD("TestPreviewCallbackFlag: flag=%d", v); +            usleep(100000); // sleep a while to clear the in-flight callbacks.              cc->clearStat();              c->setPreviewCallbackFlag(v);              ASSERT(c->previewEnabled() == false); @@ -781,6 +839,7 @@ public:          ASSERT(c->recordingEnabled() == true);          sleep(2);          c->stopRecording(); +        usleep(100000); // sleep a while to clear the in-flight callbacks.          cc->setReleaser(NULL);          cc->assertData(CAMERA_MSG_VIDEO_FRAME, MCameraClient::GE, 10);      } @@ -806,9 +865,13 @@ public:      }      void run() { -        checkOnePicture(480, 320); -        checkOnePicture(352, 288); -        checkOnePicture(176, 144); +        CameraParameters param(c->getParameters()); +        int w, h; +        const char *s = param.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES); +        while (getNextSize(&s, &w, &h)) { +            LOGD("checking preview size %dx%d", w, h); +            checkOnePicture(w, h); +        }      }  }; @@ -827,23 +890,30 @@ int main(int argc, char **argv)      INFO("CameraServiceTest start");      gExecutable = argv[0];      runHolderService(); - -    testConnect();                              flushCommands(); -    testAllowConnectOnceOnly();                 flushCommands(); -    testReconnect();                            flushCommands(); -    testLockUnlock();                           flushCommands(); -    testReconnectFromAnotherProcess();          flushCommands(); - -    RUN(TestSetPreviewDisplay); -    RUN(TestStartPreview); -    RUN(TestStartPreviewWithoutDisplay); -    RUN(TestAutoFocus); -    RUN(TestStopPreview); -    RUN(TestTakePicture); -    RUN(TestTakeMultiplePictures); -    RUN(TestGetParameters); -    RUN(TestPictureSize); -    RUN(TestPreviewCallbackFlag); -    RUN(TestRecording); -    RUN(TestPreviewSize); +    int n = getNumberOfCameras(); +    INFO("%d Cameras available", n); + +    for (int id = 0; id < n; id++) { +        INFO("Testing camera %d", id); +        testConnect(id);                              flushCommands(); +        testAllowConnectOnceOnly(id);                 flushCommands(); +        testReconnect(id);                            flushCommands(); +        testLockUnlock(id);                           flushCommands(); +        testReconnectFromAnotherProcess(id);          flushCommands(); + +        RUN(TestSetPreviewDisplay, id); +        RUN(TestStartPreview, id); +        RUN(TestStartPreviewWithoutDisplay, id); +        RUN(TestAutoFocus, id); +        RUN(TestStopPreview, id); +        RUN(TestTakePicture, id); +        RUN(TestTakeMultiplePictures, id); +        RUN(TestGetParameters, id); +        RUN(TestPictureSize, id); +        RUN(TestPreviewCallbackFlag, id); +        RUN(TestRecording, id); +        RUN(TestPreviewSize, id); +    } + +    INFO("CameraServiceTest finished");  } diff --git a/include/binder/IInterface.h b/include/binder/IInterface.h index 273d92231f..5f9f69c042 100644 --- a/include/binder/IInterface.h +++ b/include/binder/IInterface.h @@ -72,21 +72,24 @@ protected:  // ----------------------------------------------------------------------  #define DECLARE_META_INTERFACE(INTERFACE)                               \ -    static const String16 descriptor;                                   \ -    static sp<I##INTERFACE> asInterface(const sp<IBinder>& obj);        \ -    virtual const String16& getInterfaceDescriptor() const;             \ +    static const android::String16 descriptor;                          \ +    static android::sp<I##INTERFACE> asInterface(                       \ +            const android::sp<android::IBinder>& obj);                  \ +    virtual const android::String16& getInterfaceDescriptor() const;    \      I##INTERFACE();                                                     \      virtual ~I##INTERFACE();                                            \  #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \ -    const String16 I##INTERFACE::descriptor(NAME);                      \ -    const String16& I##INTERFACE::getInterfaceDescriptor() const {      \ +    const android::String16 I##INTERFACE::descriptor(NAME);             \ +    const android::String16&                                            \ +            I##INTERFACE::getInterfaceDescriptor() const {              \          return I##INTERFACE::descriptor;                                \      }                                                                   \ -    sp<I##INTERFACE> I##INTERFACE::asInterface(const sp<IBinder>& obj)  \ +    android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \ +            const android::sp<android::IBinder>& obj)                   \      {                                                                   \ -        sp<I##INTERFACE> intr;                                          \ +        android::sp<I##INTERFACE> intr;                                 \          if (obj != NULL) {                                              \              intr = static_cast<I##INTERFACE*>(                          \                  obj->queryLocalInterface(                               \ diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h index 9b5a1e0f53..633b5436d6 100644 --- a/include/private/surfaceflinger/SharedBufferStack.h +++ b/include/private/surfaceflinger/SharedBufferStack.h @@ -43,24 +43,9 @@ namespace android {   * unless they are in use by the server, which is only the case for the last    * dequeue-able buffer. When these various conditions are not met, the caller   * waits until the condition is met. - * - *  - * CAVEATS: - *  - * In the current implementation there are several limitations: - * - buffers must be locked in the same order they've been dequeued - * - buffers must be enqueued in the same order they've been locked - * - dequeue() is not reentrant - * - no error checks are done on the condition above   *    */ -// When changing these values, the COMPILE_TIME_ASSERT at the end of this -// file need to be updated. -const unsigned int NUM_LAYERS_MAX  = 31; -const unsigned int NUM_BUFFER_MAX  = 4; -const unsigned int NUM_DISPLAY_MAX = 4; -  // ----------------------------------------------------------------------------  class Region; @@ -69,7 +54,11 @@ class SharedClient;  // ---------------------------------------------------------------------------- -// should be 128 bytes (32 longs) +// 4 * (11 + 7 + (1 + 2*NUM_RECT_MAX) * NUM_BUFFER_MAX) * NUM_LAYERS_MAX +// 4 * (11 + 7 + (1 + 2*7)*16) * 31 +// 1032 * 31 +// = ~27 KiB (31992) +  class SharedBufferStack  {      friend class SharedClient; @@ -78,21 +67,38 @@ class SharedBufferStack      friend class SharedBufferServer;  public: -    struct FlatRegion { // 12 bytes -        static const unsigned int NUM_RECT_MAX = 1; -        uint32_t    count; -        uint16_t    rects[4*NUM_RECT_MAX]; -    }; -     +    // When changing these values, the COMPILE_TIME_ASSERT at the end of this +    // file need to be updated. +    static const unsigned int NUM_LAYERS_MAX  = 31; +    static const unsigned int NUM_BUFFER_MAX  = 16; +    static const unsigned int NUM_BUFFER_MIN  = 2; +    static const unsigned int NUM_DISPLAY_MAX = 4; +      struct Statistics { // 4 longs          typedef int32_t usecs_t;          usecs_t  totalTime;          usecs_t  reserved[3];      }; + +    struct SmallRect { +        uint16_t l, t, r, b; +    }; + +    struct FlatRegion { // 52 bytes = 4 * (1 + 2*N) +        static const unsigned int NUM_RECT_MAX = 6; +        uint32_t    count; +        SmallRect   rects[NUM_RECT_MAX]; +    }; +     +    struct BufferData { +        FlatRegion dirtyRegion; +        SmallRect  crop; +    };      SharedBufferStack();      void init(int32_t identity);      status_t setDirtyRegion(int buffer, const Region& reg); +    status_t setCrop(int buffer, const Rect& reg);      Region getDirtyRegion(int buffer) const;      // these attributes are part of the conditions/updates @@ -104,24 +110,25 @@ public:      // not part of the conditions      volatile int32_t reallocMask; +    volatile int8_t index[NUM_BUFFER_MAX];      int32_t     identity;       // surface's identity (const) -    int32_t     reserved32[9]; +    int32_t     token;          // surface's token (for debugging) +    int32_t     reserved32[1];      Statistics  stats; -    FlatRegion  dirtyRegion[NUM_BUFFER_MAX];    // 12*4=48 bytes +    int32_t     reserved; +    BufferData  buffers[NUM_BUFFER_MAX];     // 960 bytes  };  // ---------------------------------------------------------------------------- -// 4 KB max +// 32 KB max  class SharedClient  {  public:      SharedClient();      ~SharedClient(); -      status_t validate(size_t token) const; -    uint32_t getIdentity(size_t token) const;  private:      friend class SharedBufferBase; @@ -131,7 +138,7 @@ private:      // FIXME: this should be replaced by a lock-less primitive      Mutex lock;      Condition cv; -    SharedBufferStack surfaces[ NUM_LAYERS_MAX ]; +    SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ];  };  // ============================================================================ @@ -139,18 +146,17 @@ private:  class SharedBufferBase  {  public: -    SharedBufferBase(SharedClient* sharedClient, int surface, int num, +    SharedBufferBase(SharedClient* sharedClient, int surface,              int32_t identity);      ~SharedBufferBase(); -    uint32_t getIdentity();      status_t getStatus() const; +    int32_t getIdentity() const;      size_t getFrontBuffer() const;      String8 dump(char const* prefix) const;  protected:      SharedClient* const mSharedClient;      SharedBufferStack* const mSharedStack; -    const int mNumBuffers;      const int mIdentity;      friend struct Update; @@ -160,61 +166,22 @@ protected:          SharedBufferStack& stack;          inline ConditionBase(SharedBufferBase* sbc)               : stack(*sbc->mSharedStack) { } +        virtual ~ConditionBase() { }; +        virtual bool operator()() const = 0; +        virtual const char* name() const = 0;      }; +    status_t waitForCondition(const ConditionBase& condition);      struct UpdateBase {          SharedBufferStack& stack;          inline UpdateBase(SharedBufferBase* sbb)               : stack(*sbb->mSharedStack) { }      }; - -    template <typename T> -    status_t waitForCondition(T condition); -      template <typename T>      status_t updateCondition(T update);  };  template <typename T> -status_t SharedBufferBase::waitForCondition(T condition)  -{ -    const SharedBufferStack& stack( *mSharedStack ); -    SharedClient& client( *mSharedClient ); -    const nsecs_t TIMEOUT = s2ns(1); -    Mutex::Autolock _l(client.lock); -    while ((condition()==false) && -            (stack.identity == mIdentity) && -            (stack.status == NO_ERROR)) -    { -        status_t err = client.cv.waitRelative(client.lock, TIMEOUT); -         -        // handle errors and timeouts -        if (CC_UNLIKELY(err != NO_ERROR)) { -            if (err == TIMED_OUT) { -                if (condition()) { -                    LOGE("waitForCondition(%s) timed out (identity=%d), " -                        "but condition is true! We recovered but it " -                        "shouldn't happen." , T::name(), -                        stack.identity); -                    break; -                } else { -                    LOGW("waitForCondition(%s) timed out " -                        "(identity=%d, status=%d). " -                        "CPU may be pegged. trying again.", T::name(), -                        stack.identity, stack.status); -                } -            } else { -                LOGE("waitForCondition(%s) error (%s) ", -                        T::name(), strerror(-err)); -                return err; -            } -        } -    } -    return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status; -} - - -template <typename T>  status_t SharedBufferBase::updateCondition(T update) {      SharedClient& client( *mSharedClient );      Mutex::Autolock _l(client.lock); @@ -238,13 +205,21 @@ public:      status_t queue(int buf);      bool needNewBuffer(int buffer) const;      status_t setDirtyRegion(int buffer, const Region& reg); +    status_t setCrop(int buffer, const Rect& reg); + +    class SetBufferCountCallback { +        friend class SharedBufferClient; +        virtual status_t operator()(int bufferCount) const = 0; +    protected: +        virtual ~SetBufferCountCallback() { } +    }; +    status_t setBufferCount(int bufferCount, const SetBufferCountCallback& ipc); +  private:      friend struct Condition;      friend struct DequeueCondition;      friend struct LockCondition; -     -    int32_t computeTail() const;      struct QueueUpdate : public UpdateBase {          inline QueueUpdate(SharedBufferBase* sbb); @@ -260,25 +235,34 @@ private:      struct DequeueCondition : public ConditionBase {          inline DequeueCondition(SharedBufferClient* sbc); -        inline bool operator()(); -        static inline const char* name() { return "DequeueCondition"; } +        inline bool operator()() const; +        inline const char* name() const { return "DequeueCondition"; }      };      struct LockCondition : public ConditionBase {          int buf;          inline LockCondition(SharedBufferClient* sbc, int buf); -        inline bool operator()(); -        static inline const char* name() { return "LockCondition"; } +        inline bool operator()() const; +        inline const char* name() const { return "LockCondition"; }      }; +    int32_t computeTail() const; + +    mutable RWLock mLock; +    int mNumBuffers; +      int32_t tail; +    int32_t undoDequeueTail; +    int32_t queued_head;      // statistics... -    nsecs_t mDequeueTime[NUM_BUFFER_MAX]; +    nsecs_t mDequeueTime[SharedBufferStack::NUM_BUFFER_MAX];  };  // ---------------------------------------------------------------------------- -class SharedBufferServer : public SharedBufferBase +class SharedBufferServer +    : public SharedBufferBase, +      public LightRefBase<SharedBufferServer>  {  public:      SharedBufferServer(SharedClient* sharedClient, int surface, int num, @@ -287,16 +271,74 @@ public:      ssize_t retireAndLock();      status_t unlock(int buffer);      void setStatus(status_t status); -    status_t reallocate(); +    status_t reallocateAll(); +    status_t reallocateAllExcept(int buffer);      status_t assertReallocate(int buffer);      int32_t getQueuedCount() const; -          Region getDirtyRegion(int buffer) const; +    status_t resize(int newNumBuffers); +      SharedBufferStack::Statistics getStats() const;  private: +    friend class LightRefBase<SharedBufferServer>; +    ~SharedBufferServer(); + +    /* +     * BufferList is basically a fixed-capacity sorted-vector of +     * unsigned 5-bits ints using a 32-bits int as storage. +     * it has efficient iterators to find items in the list and not in the list. +     */ +    class BufferList { +        size_t mCapacity; +        uint32_t mList; +    public: +        BufferList(size_t c = SharedBufferStack::NUM_BUFFER_MAX) +            : mCapacity(c), mList(0) { } +        status_t add(int value); +        status_t remove(int value); +        uint32_t getMask() const { return mList; } + +        class const_iterator { +            friend class BufferList; +            uint32_t mask, curr; +            const_iterator(uint32_t mask) : +                mask(mask), curr(__builtin_clz(mask)) { +            } +        public: +            inline bool operator == (const const_iterator& rhs) const { +                return mask == rhs.mask; +            } +            inline bool operator != (const const_iterator& rhs) const { +                return mask != rhs.mask; +            } +            inline int operator *() const { return curr; } +            inline const const_iterator& operator ++() { +                mask &= ~(1<<(31-curr)); +                curr = __builtin_clz(mask); +                return *this; +            } +        }; + +        inline const_iterator begin() const { +            return const_iterator(mList); +        } +        inline const_iterator end() const   { +            return const_iterator(0); +        } +        inline const_iterator free_begin() const { +            uint32_t mask = (1 << (32-mCapacity)) - 1; +            return const_iterator( ~(mList | mask) ); +        } +    }; + +    // this protects mNumBuffers and mBufferList +    mutable RWLock mLock; +    int mNumBuffers; +    BufferList mBufferList; +      struct UnlockUpdate : public UpdateBase {          const int lockedBuffer;          inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer); @@ -318,8 +360,8 @@ private:      struct ReallocateCondition : public ConditionBase {          int buf;          inline ReallocateCondition(SharedBufferBase* sbb, int buf); -        inline bool operator()(); -        static inline const char* name() { return "ReallocateCondition"; } +        inline bool operator()() const; +        inline const char* name() const { return "ReallocateCondition"; }      };  }; @@ -344,13 +386,12 @@ struct surface_flinger_cblk_t   // 4KB max      uint8_t         connected;      uint8_t         reserved[3];      uint32_t        pad[7]; -    display_cblk_t  displays[NUM_DISPLAY_MAX]; +    display_cblk_t  displays[SharedBufferStack::NUM_DISPLAY_MAX];  };  // --------------------------------------------------------------------------- -COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 4096) -COMPILE_TIME_ASSERT(sizeof(SharedBufferStack) == 128) +COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 32768)  COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)  // --------------------------------------------------------------------------- diff --git a/include/surfaceflinger/ISurface.h b/include/surfaceflinger/ISurface.h index 472f759237..ddbe03dbcc 100644 --- a/include/surfaceflinger/ISurface.h +++ b/include/surfaceflinger/ISurface.h @@ -47,13 +47,30 @@ protected:          POST_BUFFER, // one-way transaction          CREATE_OVERLAY,          REQUEST_BUFFER, +        SET_BUFFER_COUNT,      };  public:       DECLARE_META_INTERFACE(Surface); -    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) = 0;  +    /* +     * requests a new buffer for the given index. If w, h, or format are +     * null the buffer is created with the parameters assigned to the +     * surface it is bound to. Otherwise the buffer's parameters are +     * set to those specified. +     */ +    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, +            uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0; + +    /* +     * sets the number of buffers dequeuable for this surface. +     */ +    virtual status_t setBufferCount(int bufferCount) = 0; +    // ------------------------------------------------------------------------ +    // Deprecated... +    // ------------------------------------------------------------------------ +      class BufferHeap {      public:          enum { diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h index d1e7785ccd..dd44aa5afa 100644 --- a/include/surfaceflinger/ISurfaceComposer.h +++ b/include/surfaceflinger/ISurfaceComposer.h @@ -27,7 +27,7 @@  #include <ui/PixelFormat.h> -#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurfaceComposerClient.h>  namespace android {  // ---------------------------------------------------------------------------- @@ -85,8 +85,11 @@ public:      /* create connection with surface flinger, requires       * ACCESS_SURFACE_FLINGER permission       */ +    virtual sp<ISurfaceComposerClient> createConnection() = 0; -    virtual sp<ISurfaceFlingerClient> createConnection() = 0; +    /* create a client connection with surface flinger +     */ +    virtual sp<ISurfaceComposerClient> createClientConnection() = 0;      /* retrieve the control block */      virtual sp<IMemoryHeap> getCblk() const = 0; @@ -123,6 +126,7 @@ public:          // Java by ActivityManagerService.          BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,          CREATE_CONNECTION, +        CREATE_CLIENT_CONNECTION,          GET_CBLK,          OPEN_GLOBAL_TRANSACTION,          CLOSE_GLOBAL_TRANSACTION, diff --git a/include/surfaceflinger/ISurfaceFlingerClient.h b/include/surfaceflinger/ISurfaceComposerClient.h index d257645b65..a1e9e04884 100644 --- a/include/surfaceflinger/ISurfaceFlingerClient.h +++ b/include/surfaceflinger/ISurfaceComposerClient.h @@ -14,8 +14,8 @@   * limitations under the License.   */ -#ifndef ANDROID_SF_ISURFACE_FLINGER_CLIENT_H -#define ANDROID_SF_ISURFACE_FLINGER_CLIENT_H +#ifndef ANDROID_SF_ISURFACE_COMPOSER_CLIENT_H +#define ANDROID_SF_ISURFACE_COMPOSER_CLIENT_H  #include <stdint.h>  #include <sys/types.h> @@ -26,7 +26,7 @@  #include <binder/IInterface.h>  #include <ui/PixelFormat.h> -   +  #include <surfaceflinger/ISurface.h>  namespace android { @@ -42,10 +42,10 @@ typedef int32_t    DisplayID;  class layer_state_t; -class ISurfaceFlingerClient : public IInterface +class ISurfaceComposerClient : public IInterface  { -public:  -    DECLARE_META_INTERFACE(SurfaceFlingerClient); +public: +    DECLARE_META_INTERFACE(SurfaceComposerClient);      struct surface_data_t {          int32_t             token; @@ -56,26 +56,36 @@ public:          status_t readFromParcel(const Parcel& parcel);          status_t writeToParcel(Parcel* parcel) const;      }; -     +      virtual sp<IMemoryHeap> getControlBlock() const = 0; +    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const = 0; +    /* +     * Requires ACCESS_SURFACE_FLINGER permission +     */      virtual sp<ISurface> createSurface( surface_data_t* data, -                                        int pid,  +                                        int pid,                                          const String8& name,                                          DisplayID display,                                          uint32_t w,                                          uint32_t h,                                          PixelFormat format,                                          uint32_t flags) = 0; -                                     + +    /* +     * Requires ACCESS_SURFACE_FLINGER permission +     */      virtual status_t    destroySurface(SurfaceID sid) = 0; +    /* +     * Requires ACCESS_SURFACE_FLINGER permission +     */      virtual status_t    setState(int32_t count, const layer_state_t* states) = 0;  };  // ---------------------------------------------------------------------------- -class BnSurfaceFlingerClient : public BnInterface<ISurfaceFlingerClient> +class BnSurfaceComposerClient : public BnInterface<ISurfaceComposerClient>  {  public:      virtual status_t    onTransact( uint32_t code, @@ -88,4 +98,4 @@ public:  }; // namespace android -#endif // ANDROID_SF_ISURFACE_FLINGER_CLIENT_H +#endif // ANDROID_SF_ISURFACE_COMPOSER_CLIENT_H diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h index 0279d84b64..f3339117d8 100644 --- a/include/surfaceflinger/Surface.h +++ b/include/surfaceflinger/Surface.h @@ -28,12 +28,15 @@  #include <ui/egl/android_natives.h>  #include <surfaceflinger/ISurface.h> -#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurfaceComposerClient.h> + +#define ANDROID_VIEW_SURFACE_JNI_ID    "mNativeSurface"  namespace android {  // --------------------------------------------------------------------------- +class GraphicBuffer;  class GraphicBufferMapper;  class IOMX;  class Rect; @@ -41,6 +44,7 @@ class Surface;  class SurfaceComposerClient;  class SharedClient;  class SharedBufferClient; +class SurfaceClient;  // --------------------------------------------------------------------------- @@ -56,7 +60,6 @@ public:      static bool isSameSurface(              const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs); -    SurfaceID   ID() const      { return mToken; }      uint32_t    getFlags() const { return mFlags; }      uint32_t    getIdentity() const { return mIdentity; } @@ -104,7 +107,7 @@ private:      SurfaceControl(              const sp<SurfaceComposerClient>& client,              const sp<ISurface>& surface, -            const ISurfaceFlingerClient::surface_data_t& data, +            const ISurfaceComposerClient::surface_data_t& data,              uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);      ~SurfaceControl(); @@ -141,17 +144,17 @@ public:          uint32_t    reserved[2];      }; -    Surface(const Parcel& data); +    static status_t writeToParcel( +            const sp<Surface>& control, Parcel* parcel); + +    static sp<Surface> readFromParcel( +            const Parcel& data, const sp<Surface>& other);      static bool isValid(const sp<Surface>& surface) {          return (surface != 0) && surface->isValid();      } -    static bool isSameSurface( -            const sp<Surface>& lhs, const sp<Surface>& rhs); -      bool        isValid(); -    SurfaceID   ID() const          { return mToken; }      uint32_t    getFlags() const    { return mFlags; }      uint32_t    getIdentity() const { return mIdentity; } @@ -163,38 +166,37 @@ public:      // setSwapRectangle() is intended to be used by GL ES clients      void        setSwapRectangle(const Rect& r); -private: -    // can't be copied -    Surface& operator = (Surface& rhs); -    Surface(const Surface& rhs); - -    Surface(const sp<SurfaceControl>& control); -    void init(); -     ~Surface(); -   -    friend class SurfaceComposerClient; -    friend class SurfaceControl; -     +private: +    /* +     * Android frameworks friends +     * (eventually this should go away and be replaced by proper APIs) +     */      // camera and camcorder need access to the ISurface binder interface for preview      friend class Camera;      friend class MediaRecorder; -    // mediaplayer needs access to ISurface for display +    // MediaPlayer needs access to ISurface for display      friend class MediaPlayer;      friend class IOMX;      // this is just to be able to write some unit tests      friend class Test; -    sp<SurfaceComposerClient> getClient() const; -    sp<ISurface> getISurface() const; +private: +    friend class SurfaceComposerClient; +    friend class SurfaceControl; -    status_t getBufferLocked(int index, int usage); -    -           status_t validate() const; +    // can't be copied +    Surface& operator = (Surface& rhs); +    Surface(const Surface& rhs); -    inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; } -    inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; } -     +    Surface(const sp<SurfaceControl>& control); +    Surface(const Parcel& data, const sp<IBinder>& ref); +    ~Surface(); + + +    /* +     *  android_native_window_t hooks +     */      static int setSwapInterval(android_native_window_t* window, int interval);      static int dequeueBuffer(android_native_window_t* window, android_native_buffer_t** buffer);      static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer); @@ -208,44 +210,86 @@ private:      int query(int what, int* value);      int perform(int operation, va_list args); -    status_t dequeueBuffer(sp<GraphicBuffer>* buffer); -      void dispatch_setUsage(va_list args);      int  dispatch_connect(va_list args);      int  dispatch_disconnect(va_list args); +    int  dispatch_crop(va_list args); +    int  dispatch_set_buffer_count(va_list args); +    int  dispatch_set_buffers_geometry(va_list args);      void setUsage(uint32_t reqUsage);      int  connect(int api);      int  disconnect(int api); +    int  crop(Rect const* rect); +    int  setBufferCount(int bufferCount); +    int  setBuffersGeometry(int w, int h, int format); -    uint32_t getUsage() const; -    int      getConnectedApi() const; +    /* +     *  private stuff... +     */ +    void init(); +    status_t validate() const; +    sp<ISurface> getISurface() const; + +    inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; } +    inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; } + +    status_t getBufferLocked(int index, +            uint32_t w, uint32_t h, uint32_t format, uint32_t usage); +    int getBufferIndex(const sp<GraphicBuffer>& buffer) const; + +    int getConnectedApi() const; +    bool needNewBuffer(int bufIdx, +            uint32_t *pWidth, uint32_t *pHeight, +            uint32_t *pFormat, uint32_t *pUsage) const; + +    class BufferInfo { +        uint32_t mWidth; +        uint32_t mHeight; +        uint32_t mFormat; +        uint32_t mUsage; +        mutable uint32_t mDirty; +        enum { +            GEOMETRY = 0x01 +        }; +    public: +        BufferInfo(); +        void set(uint32_t w, uint32_t h, uint32_t format); +        void set(uint32_t usage); +        void get(uint32_t *pWidth, uint32_t *pHeight, +                uint32_t *pFormat, uint32_t *pUsage) const; +        bool validateBuffer(const sp<GraphicBuffer>& buffer) const; +    }; +      // constants -    sp<SurfaceComposerClient>   mClient; +    GraphicBufferMapper&        mBufferMapper; +    SurfaceClient&              mClient; +    SharedBufferClient*         mSharedBufferClient; +    status_t                    mInitCheck;      sp<ISurface>                mSurface; -    SurfaceID                   mToken;      uint32_t                    mIdentity;      PixelFormat                 mFormat;      uint32_t                    mFlags; -    GraphicBufferMapper&        mBufferMapper; -    SharedBufferClient*         mSharedBufferClient;      // protected by mSurfaceLock      Rect                        mSwapRectangle; -    uint32_t                    mUsage;      int                         mConnected; +    Rect                        mNextBufferCrop; +    BufferInfo                  mBufferInfo;      // protected by mSurfaceLock. These are also used from lock/unlock      // but in that case, they must be called form the same thread. -    sp<GraphicBuffer>           mBuffers[2];      mutable Region              mDirtyRegion;      // must be used from the lock/unlock thread      sp<GraphicBuffer>           mLockedBuffer;      sp<GraphicBuffer>           mPostedBuffer;      mutable Region              mOldDirtyRegion; -    bool                        mNeedFullUpdate; +    bool                        mReserved; + +    // only used from dequeueBuffer() +    Vector< sp<GraphicBuffer> > mBuffers;      // query() must be called from dequeueBuffer() thread      uint32_t                    mWidth; diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h index 9d0f0cbeb8..8773d7133b 100644 --- a/include/surfaceflinger/SurfaceComposerClient.h +++ b/include/surfaceflinger/SurfaceComposerClient.h @@ -22,8 +22,9 @@  #include <binder/IBinder.h> -#include <utils/SortedVector.h>  #include <utils/RefBase.h> +#include <utils/Singleton.h> +#include <utils/SortedVector.h>  #include <utils/threads.h>  #include <ui/PixelFormat.h> @@ -39,8 +40,26 @@ class Region;  class SharedClient;  class ISurfaceComposer;  class DisplayInfo; +class surface_flinger_cblk_t; + +// --------------------------------------------------------------------------- + +class ComposerService : public Singleton<ComposerService> +{ +    // these are constants +    sp<ISurfaceComposer> mComposerService; +    sp<IMemoryHeap> mServerCblkMemory; +    surface_flinger_cblk_t volatile* mServerCblk; +    ComposerService(); +    friend class Singleton<ComposerService>; +public: +    static sp<ISurfaceComposer> getComposerService(); +    static surface_flinger_cblk_t const volatile * getControlBlock(); +}; -class SurfaceComposerClient : virtual public RefBase +// --------------------------------------------------------------------------- + +class SurfaceComposerClient : public RefBase  {  public:                      SurfaceComposerClient(); @@ -52,10 +71,6 @@ public:      // Return the connection of this client      sp<IBinder> connection() const; -    // Retrieve a client for an existing connection. -    static sp<SurfaceComposerClient> -                clientForConnection(const sp<IBinder>& conn); -      // Forcibly remove connection before all references have gone away.      void        dispose(); @@ -123,13 +138,6 @@ public:      status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient,              void* cookie = NULL, uint32_t flags = 0); -private: -    friend class Surface; -    friend class SurfaceControl; -     -    SurfaceComposerClient(const sp<ISurfaceComposer>& sm,  -            const sp<IBinder>& conn); -      status_t    hide(SurfaceID id);      status_t    show(SurfaceID id, int32_t layer = -1);      status_t    freeze(SurfaceID id); @@ -142,32 +150,26 @@ private:      status_t    setMatrix(SurfaceID id, float dsdx, float dtdx, float dsdy, float dtdy);      status_t    setPosition(SurfaceID id, int32_t x, int32_t y);      status_t    setSize(SurfaceID id, uint32_t w, uint32_t h); -     -    void        signalServer(); -      status_t    destroySurface(SurfaceID sid); -    void        _init(const sp<ISurfaceComposer>& sm, -                    const sp<ISurfaceFlingerClient>& conn); - -    inline layer_state_t*   _get_state_l(SurfaceID id); -    layer_state_t*          _lockLayerState(SurfaceID id); -    inline void             _unlockLayerState(); +private: +    virtual void onFirstRef(); +    inline layer_state_t*   get_state_l(SurfaceID id); +    layer_state_t*          lockLayerState(SurfaceID id); +    inline void             unlockLayerState();      mutable     Mutex                               mLock; -                layer_state_t*                      mPrebuiltLayerState;                  SortedVector<layer_state_t>         mStates;                  int32_t                             mTransactionOpen; +                layer_state_t*                      mPrebuiltLayerState;                  // these don't need to be protected because they never change                  // after assignment                  status_t                    mStatus; -                SharedClient*               mControl; -                sp<IMemoryHeap>             mControlMemory; -                sp<ISurfaceFlingerClient>   mClient; -                sp<ISurfaceComposer>        mSignalServer; +                sp<ISurfaceComposerClient>  mClient;  }; +// ---------------------------------------------------------------------------  }; // namespace android  #endif // ANDROID_SF_SURFACE_COMPOSER_CLIENT_H diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h index e72b6b3b8e..a3e85a96aa 100644 --- a/include/ui/GraphicBuffer.h +++ b/include/ui/GraphicBuffer.h @@ -93,10 +93,8 @@ public:      void setIndex(int index);      int getIndex() const; -    void setVerticalStride(uint32_t vstride); -    uint32_t getVerticalStride() const; -protected: +private:      virtual ~GraphicBuffer();      enum { @@ -105,8 +103,12 @@ protected:          ownData   = 2,      }; -    inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; } -    inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; } +    inline const GraphicBufferMapper& getBufferMapper() const { +        return mBufferMapper; +    } +    inline GraphicBufferMapper& getBufferMapper() { +        return mBufferMapper; +    }      uint8_t mOwner;  private: @@ -134,7 +136,6 @@ private:      GraphicBufferMapper& mBufferMapper;      ssize_t mInitCheck; -    uint32_t mVStride;      int mIndex;  }; diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h index 741d763561..54b8236e2a 100644 --- a/include/ui/GraphicBufferAllocator.h +++ b/include/ui/GraphicBufferAllocator.h @@ -73,9 +73,9 @@ private:      struct alloc_rec_t {          uint32_t w;          uint32_t h; +        uint32_t s;          PixelFormat format;          uint32_t usage; -        void* vaddr;          size_t size;      }; diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h index 571e47b22d..e81d0f9064 100644..100755 --- a/include/ui/KeycodeLabels.h +++ b/include/ui/KeycodeLabels.h @@ -114,6 +114,10 @@ static const KeycodeLabel KEYCODES[] = {      { "MEDIA_REWIND", 89 },      { "MEDIA_FAST_FORWARD", 90 },      { "MUTE", 91 }, +    { "PAGE_UP", 92 }, +    { "PAGE_DOWN", 93 }, +    { "PICTSYMBOLS", 94 }, +    { "SWITCH_CHARSET", 95 },      // NOTE: If you add a new keycode here you must also add it to:      //   (enum KeyCode, in this file) @@ -218,7 +222,11 @@ typedef enum KeyCode {      kKeyCodePreviousSong = 88,      kKeyCodeRewind = 89,      kKeyCodeForward = 90, -    kKeyCodeMute = 91 +    kKeyCodeMute = 91, +    kKeyCodePageUp = 92, +    kKeyCodePageDown = 93, +    kKeyCodePictSymbols = 94, +    kKeyCodeSwitchCharset = 95  } KeyCode;  static const KeycodeLabel FLAGS[] = { diff --git a/include/ui/android_native_buffer.h b/include/ui/android_native_buffer.h index 9c92af8845..402843e205 100644 --- a/include/ui/android_native_buffer.h +++ b/include/ui/android_native_buffer.h @@ -33,6 +33,15 @@ typedef struct android_native_buffer_t          common.version = sizeof(android_native_buffer_t);          memset(common.reserved, 0, sizeof(common.reserved));      } + +    // Implement the methods that sp<android_native_buffer_t> expects so that it +    // can be used to automatically refcount android_native_buffer_t's. +    void incStrong(const void* id) const { +        common.incRef(const_cast<android_native_base_t*>(&common)); +    } +    void decStrong(const void* id) const { +        common.decRef(const_cast<android_native_base_t*>(&common)); +    }  #endif      struct android_native_base_t common; diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h index 773fd9301f..171f3df3a1 100644 --- a/include/ui/egl/android_natives.h +++ b/include/ui/egl/android_natives.h @@ -41,6 +41,14 @@ extern "C" {  struct android_native_buffer_t; +typedef struct android_native_rect_t +{ +    int32_t left; +    int32_t top; +    int32_t right; +    int32_t bottom; +} android_native_rect_t; +  // ---------------------------------------------------------------------------  typedef struct android_native_base_t @@ -63,15 +71,18 @@ typedef struct android_native_base_t  /* attributes queriable with query() */  enum {      NATIVE_WINDOW_WIDTH     = 0, -    NATIVE_WINDOW_HEIGHT    = 1, -    NATIVE_WINDOW_FORMAT    = 2, +    NATIVE_WINDOW_HEIGHT, +    NATIVE_WINDOW_FORMAT,  };  /* valid operations for the (*perform)() hook */  enum {      NATIVE_WINDOW_SET_USAGE  = 0, -    NATIVE_WINDOW_CONNECT    = 1, -    NATIVE_WINDOW_DISCONNECT = 2 +    NATIVE_WINDOW_CONNECT, +    NATIVE_WINDOW_DISCONNECT, +    NATIVE_WINDOW_SET_CROP, +    NATIVE_WINDOW_SET_BUFFER_COUNT, +    NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,  };  /* parameter for NATIVE_WINDOW_[DIS]CONNECT */ @@ -89,6 +100,15 @@ typedef struct android_native_window_t          common.version = sizeof(android_native_window_t);          memset(common.reserved, 0, sizeof(common.reserved));      } + +    // Implement the methods that sp<android_native_window_t> expects so that it +    // can be used to automatically refcount android_native_window_t's. +    void incStrong(const void* id) const { +        common.incRef(const_cast<android_native_base_t*>(&common)); +    } +    void decStrong(const void* id) const { +        common.decRef(const_cast<android_native_base_t*>(&common)); +    }  #endif      struct android_native_base_t common; @@ -125,7 +145,7 @@ typedef struct android_native_window_t       *        * Returns 0 on success or -errno on error.       */ -    int     (*dequeueBuffer)(struct android_native_window_t* window,  +    int     (*dequeueBuffer)(struct android_native_window_t* window,                  struct android_native_buffer_t** buffer);      /* @@ -171,6 +191,9 @@ typedef struct android_native_window_t       *     NATIVE_WINDOW_SET_USAGE       *     NATIVE_WINDOW_CONNECT       *     NATIVE_WINDOW_DISCONNECT +     *     NATIVE_WINDOW_SET_CROP +     *     NATIVE_WINDOW_SET_BUFFER_COUNT +     *     NATIVE_WINDOW_SET_BUFFERS_GEOMETRY       *         */ @@ -182,8 +205,9 @@ typedef struct android_native_window_t  /* - *  native_window_set_usage() sets the intended usage flags for the next - *  buffers acquired with (*lockBuffer)() and on. + *  native_window_set_usage(..., usage) + *  Sets the intended usage flags for the next buffers + *  acquired with (*lockBuffer)() and on.   *  By default (if this function is never called), a usage of   *      GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE   *  is assumed. @@ -198,8 +222,8 @@ static inline int native_window_set_usage(  }  /* - * native_window_connect(..., NATIVE_WINDOW_API_EGL) must be called - * by EGL when the window is made current. + * native_window_connect(..., NATIVE_WINDOW_API_EGL) + * Must be called by EGL when the window is made current.   * Returns -EINVAL if for some reason the window cannot be connected, which   * can happen if it's connected to some other API.   */ @@ -210,8 +234,8 @@ static inline int native_window_connect(  }  /* - * native_window_disconnect(..., NATIVE_WINDOW_API_EGL) must be called - * by EGL when the window is made not current. + * native_window_disconnect(..., NATIVE_WINDOW_API_EGL) + * Must be called by EGL when the window is made not current.   * An error is returned if for instance the window wasn't connected in the   * first place.   */ @@ -221,6 +245,54 @@ static inline int native_window_disconnect(      return window->perform(window, NATIVE_WINDOW_DISCONNECT, api);  } +/* + * native_window_set_crop(..., crop) + * Sets which region of the next queued buffers needs to be considered. + * A buffer's crop region is scaled to match the surface's size. + * + * The specified crop region applies to all buffers queued after it is called. + * + * if 'crop' is NULL, subsequently queued buffers won't be cropped. + * + * An error is returned if for instance the crop region is invalid, + * out of the buffer's bound or if the window is invalid. + */ +static inline int native_window_set_crop( +        android_native_window_t* window, +        android_native_rect_t const * crop) +{ +    return window->perform(window, NATIVE_WINDOW_SET_CROP, crop); +} + +/* + * native_window_set_buffer_count(..., count) + * Sets the number of buffers associated with this native window. + */ +static inline int native_window_set_buffer_count( +        android_native_window_t* window, +        size_t bufferCount) +{ +    return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount); +} + +/* + * native_window_set_buffers_geometry(..., int w, int h, int format) + * All buffers dequeued after this call will have the geometry specified. + * In particular, all buffers will have a fixed-size, independent form the + * native-window size. They will be appropriately scaled to the window-size + * upon composition. + * + * If all parameters are 0, the normal behavior is restored. That is, + * dequeued buffers following this call will be sized to the window's size. + * + */ +static inline int native_window_set_buffers_geometry( +        android_native_window_t* window, +        int w, int h, int format) +{ +    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY, +            w, h, format); +}  // --------------------------------------------------------------------------- @@ -263,6 +335,15 @@ namespace android {  template <typename NATIVE_TYPE, typename TYPE, typename REF>  class EGLNativeBase : public NATIVE_TYPE, public REF  { +public: +    // Disambiguate between the incStrong in REF and NATIVE_TYPE +    void incStrong(const void* id) const { +        REF::incStrong(id); +    } +    void decStrong(const void* id) const { +        REF::decStrong(id); +    } +  protected:      typedef EGLNativeBase<NATIVE_TYPE, TYPE, REF> BASE;      EGLNativeBase() : NATIVE_TYPE(), REF() { diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index b701ce74d6..c7d9ff1dd6 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -933,6 +933,7 @@ struct ResTable_config          SCREENSIZE_SMALL = 0x01,          SCREENSIZE_NORMAL = 0x02,          SCREENSIZE_LARGE = 0x03, +        SCREENSIZE_XLARGE = 0x04,          // screenLayout bits for wide/long screen variation.          MASK_SCREENLONG = 0x30, @@ -1208,7 +1209,28 @@ struct ResTable_config              if (screenLayout || o.screenLayout) {                  if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0                          && (requested->screenLayout & MASK_SCREENSIZE)) { -                    return (screenLayout & MASK_SCREENSIZE); +                    // A little backwards compatibility here: undefined is +                    // considered equivalent to normal.  But only if the +                    // requested size is at least normal; otherwise, small +                    // is better than the default. +                    int mySL = (screenLayout & MASK_SCREENSIZE); +                    int oSL = (o.screenLayout & MASK_SCREENSIZE); +                    int fixedMySL = mySL; +                    int fixedOSL = oSL; +                    if ((requested->screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) { +                        if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL; +                        if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL; +                    } +                    // For screen size, the best match is the one that is +                    // closest to the requested screen size, but not over +                    // (the not over part is dealt with in match() below). +                    if (fixedMySL == fixedOSL) { +                        // If the two are the same, but 'this' is actually +                        // undefined, then the other is really a better match. +                        if (mySL == 0) return false; +                        return true; +                    } +                    return fixedMySL >= fixedOSL;                  }                  if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0                          && (requested->screenLayout & MASK_SCREENLONG)) { @@ -1370,8 +1392,11 @@ struct ResTable_config          if (screenConfig != 0) {              const int screenSize = screenLayout&MASK_SCREENSIZE;              const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE; -            if (setScreenSize != 0 && screenSize != 0 -                    && screenSize != setScreenSize) { +            // Any screen sizes for larger screens than the setting do not +            // match. +            if ((setScreenSize != 0 && screenSize != 0 +                    && screenSize > setScreenSize) || +                    (setScreenSize == 0 && screenSize != 0)) {                  return false;              } diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h index bc7626a821..3b975b4c44 100644 --- a/include/utils/Singleton.h +++ b/include/utils/Singleton.h @@ -54,11 +54,13 @@ private:   * (eg: <TYPE>.cpp) to create the static instance of Singleton<>'s attributes,   * and avoid to have a copy of them in each compilation units Singleton<TYPE>   * is used. + * NOTE: we use a version of Mutex ctor that takes a parameter, because + * for some unknown reason using the default ctor doesn't emit the variable!   */ -#define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE)             \ -    template class Singleton< TYPE >;                       \ -    template< class TYPE > Mutex Singleton< TYPE >::sLock;  \ +#define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE)                 \ +    template class Singleton< TYPE >;                           \ +    template<> Mutex Singleton< TYPE >::sLock(Mutex::PRIVATE);  \      template<> TYPE* Singleton< TYPE >::sInstance(0); diff --git a/include/utils/ZipFileCRO.h b/include/utils/ZipFileCRO.h index 30e00368e9..e38bf669d7 100644 --- a/include/utils/ZipFileCRO.h +++ b/include/utils/ZipFileCRO.h @@ -47,8 +47,8 @@ extern ZipEntryCRO ZipFileCRO_findEntryByName(ZipFileCRO zip,          const char* fileName);  extern bool ZipFileCRO_getEntryInfo(ZipFileCRO zip, ZipEntryCRO entry, -        int* pMethod, long* pUncompLen, -        long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32); +        int* pMethod, size_t* pUncompLen, +        size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32);  extern bool ZipFileCRO_uncompressEntry(ZipFileCRO zip, ZipEntryCRO entry, int fd); diff --git a/include/utils/ZipFileRO.h b/include/utils/ZipFileRO.h index 51c4f2fb6a..97d31f4db4 100644 --- a/include/utils/ZipFileRO.h +++ b/include/utils/ZipFileRO.h @@ -58,14 +58,19 @@ typedef void* ZipEntryRO;  class ZipFileRO {  public:      ZipFileRO() -        : mFd(-1), mFileMap(NULL), mHashTableSize(-1), mHashTable(NULL) +        : mFd(-1), mFileName(NULL), mFileLength(-1), +          mDirectoryMap(NULL), +          mNumEntries(-1), mDirectoryOffset(-1), +          mHashTableSize(-1), mHashTable(NULL)          {}      ~ZipFileRO() {          free(mHashTable); -        if (mFileMap) -            mFileMap->release(); +        if (mDirectoryMap) +            mDirectoryMap->release();          if (mFd >= 0)              close(mFd); +        if (mFileName) +            free(mFileName);      }      /* @@ -118,8 +123,8 @@ public:       * Returns "false" if "entry" is bogus or if the data in the Zip file       * appears to be bad.       */ -    bool getEntryInfo(ZipEntryRO entry, int* pMethod, long* pUncompLen, -        long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const; +    bool getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, +        size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const;      /*       * Create a new FileMap object that maps a subset of the archive.  For @@ -155,13 +160,13 @@ public:       * Utility function: uncompress deflated data, buffer to buffer.       */      static bool inflateBuffer(void* outBuf, const void* inBuf, -        long uncompLen, long compLen); +        size_t uncompLen, size_t compLen);      /*       * Utility function: uncompress deflated data, buffer to fd.       */      static bool inflateBuffer(int fd, const void* inBuf, -        long uncompLen, long compLen); +        size_t uncompLen, size_t compLen);      /*       * Some basic functions for raw data manipulation.  "LE" means @@ -179,6 +184,9 @@ private:      ZipFileRO(const ZipFileRO& src);      ZipFileRO& operator=(const ZipFileRO& src); +    /* locate and parse the central directory */ +    bool mapCentralDirectory(void); +      /* parse the archive, prepping internal structures */      bool parseZipArchive(void); @@ -203,12 +211,21 @@ private:      /* open Zip archive */      int         mFd; +    /* zip file name */ +    char*       mFileName; + +    /* length of file */ +    size_t      mFileLength; +      /* mapped file */ -    FileMap*    mFileMap; +    FileMap*    mDirectoryMap;      /* number of entries in the Zip archive */      int         mNumEntries; +    /* CD directory offset in the Zip archive */ +    off_t       mDirectoryOffset; +      /*       * We know how many entries are in the Zip archive, so we have a       * fixed-size hash table.  We probe for an empty slot. diff --git a/include/utils/threads.h b/include/utils/threads.h index 5ac0c5ee19..1bcfaede67 100644 --- a/include/utils/threads.h +++ b/include/utils/threads.h @@ -295,6 +295,96 @@ typedef Mutex::Autolock AutoMutex;  /*****************************************************************************/ +#if defined(HAVE_PTHREADS) + +/* + * Simple mutex class.  The implementation is system-dependent. + * + * The mutex must be unlocked by the thread that locked it.  They are not + * recursive, i.e. the same thread can't lock it multiple times. + */ +class RWLock { +public: +    enum { +        PRIVATE = 0, +        SHARED = 1 +    }; + +                RWLock(); +                RWLock(const char* name); +                RWLock(int type, const char* name = NULL); +                ~RWLock(); + +    status_t    readLock(); +    status_t    tryReadLock(); +    status_t    writeLock(); +    status_t    tryWriteLock(); +    void        unlock(); + +    class AutoRLock { +    public: +        inline AutoRLock(RWLock& rwlock) : mLock(rwlock)  { mLock.readLock(); } +        inline ~AutoRLock() { mLock.unlock(); } +    private: +        RWLock& mLock; +    }; + +    class AutoWLock { +    public: +        inline AutoWLock(RWLock& rwlock) : mLock(rwlock)  { mLock.writeLock(); } +        inline ~AutoWLock() { mLock.unlock(); } +    private: +        RWLock& mLock; +    }; + +private: +    // A RWLock cannot be copied +                RWLock(const RWLock&); +   RWLock&      operator = (const RWLock&); + +   pthread_rwlock_t mRWLock; +}; + +inline RWLock::RWLock() { +    pthread_rwlock_init(&mRWLock, NULL); +} +inline RWLock::RWLock(const char* name) { +    pthread_rwlock_init(&mRWLock, NULL); +} +inline RWLock::RWLock(int type, const char* name) { +    if (type == SHARED) { +        pthread_rwlockattr_t attr; +        pthread_rwlockattr_init(&attr); +        pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); +        pthread_rwlock_init(&mRWLock, &attr); +        pthread_rwlockattr_destroy(&attr); +    } else { +        pthread_rwlock_init(&mRWLock, NULL); +    } +} +inline RWLock::~RWLock() { +    pthread_rwlock_destroy(&mRWLock); +} +inline status_t RWLock::readLock() { +    return -pthread_rwlock_rdlock(&mRWLock); +} +inline status_t RWLock::tryReadLock() { +    return -pthread_rwlock_tryrdlock(&mRWLock); +} +inline status_t RWLock::writeLock() { +    return -pthread_rwlock_wrlock(&mRWLock); +} +inline status_t RWLock::tryWriteLock() { +    return -pthread_rwlock_trywrlock(&mRWLock); +} +inline void RWLock::unlock() { +    pthread_rwlock_unlock(&mRWLock); +} + +#endif // HAVE_PTHREADS + +/*****************************************************************************/ +  /*   * Condition variable class.  The implementation is system-dependent.   * diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk index 870c0b8384..22ecc5444a 100644 --- a/libs/audioflinger/Android.mk +++ b/libs/audioflinger/Android.mk @@ -87,7 +87,8 @@ LOCAL_SHARED_LIBRARIES := \      libutils \      libbinder \      libmedia \ -    libhardware_legacy +    libhardware_legacy \ +    libeffects  ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)    LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp index a018b4c225..6c111148a9 100644 --- a/libs/audioflinger/AudioDumpInterface.cpp +++ b/libs/audioflinger/AudioDumpInterface.cpp @@ -32,7 +32,7 @@ namespace android {  // ----------------------------------------------------------------------------  AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw) -    : mFirstHwOutput(true), mPolicyCommands(String8("")), mFileName(String8("")) +    : mPolicyCommands(String8("")), mFileName(String8(""))  {      if(hw == 0) {          LOGE("Dump construct hw = 0"); @@ -47,6 +47,11 @@ AudioDumpInterface::~AudioDumpInterface()      for (size_t i = 0; i < mOutputs.size(); i++) {          closeOutputStream((AudioStreamOut *)mOutputs[i]);      } + +    for (size_t i = 0; i < mInputs.size(); i++) { +        closeInputStream((AudioStreamIn *)mInputs[i]); +    } +      if(mFinalInterface) delete mFinalInterface;  } @@ -60,31 +65,32 @@ AudioStreamOut* AudioDumpInterface::openOutputStream(      uint32_t lRate = 44100; -    if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices) || mFirstHwOutput) { -        outFinal = mFinalInterface->openOutputStream(devices, format, channels, sampleRate, status); -        if (outFinal != 0) { -            lFormat = outFinal->format(); -            lChannels = outFinal->channels(); -            lRate = outFinal->sampleRate(); -            if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) { -                mFirstHwOutput = false; -            } -        } +    outFinal = mFinalInterface->openOutputStream(devices, format, channels, sampleRate, status); +    if (outFinal != 0) { +        lFormat = outFinal->format(); +        lChannels = outFinal->channels(); +        lRate = outFinal->sampleRate();      } else { -        if (format != 0 && *format != 0) { -            lFormat = *format; -        } else { -            lFormat = AudioSystem::PCM_16_BIT; +        if (format != 0) { +            if (*format != 0) { +                lFormat = *format; +            } else { +                *format = lFormat; +            }          } -        if (channels != 0 && *channels != 0) { -            lChannels = *channels; -        } else { -            lChannels = AudioSystem::CHANNEL_OUT_STEREO; +        if (channels != 0) { +            if (*channels != 0) { +                lChannels = *channels; +            } else { +                *channels = lChannels; +            }          } -        if (sampleRate != 0 && *sampleRate != 0) { -            lRate = *sampleRate; -        } else { -            lRate = 44100; +        if (sampleRate != 0) { +            if (*sampleRate != 0) { +                lRate = *sampleRate; +            } else { +                *sampleRate = lRate; +            }          }          if (status) *status = NO_ERROR;      } @@ -111,7 +117,6 @@ void AudioDumpInterface::closeOutputStream(AudioStreamOut* out)      dumpOut->standby();      if (dumpOut->finalStream() != NULL) {          mFinalInterface->closeOutputStream(dumpOut->finalStream()); -        mFirstHwOutput = true;      }      mOutputs.remove(dumpOut); @@ -126,18 +131,33 @@ AudioStreamIn* AudioDumpInterface::openInputStream(uint32_t devices, int *format      uint32_t lChannels = AudioSystem::CHANNEL_IN_MONO;      uint32_t lRate = 8000; - -    if (mInputs.size() == 0) { -        inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics); -        if (inFinal == 0) return 0; - +    inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics); +    if (inFinal != 0) {          lFormat = inFinal->format();          lChannels = inFinal->channels();          lRate = inFinal->sampleRate();      } else { -        if (format != 0 && *format != 0) lFormat = *format; -        if (channels != 0 && *channels != 0) lChannels = *channels; -        if (sampleRate != 0 && *sampleRate != 0) lRate = *sampleRate; +        if (format != 0) { +            if (*format != 0) { +                lFormat = *format; +            } else { +                *format = lFormat; +            } +        } +        if (channels != 0) { +            if (*channels != 0) { +                lChannels = *channels; +            } else { +                *channels = lChannels; +            } +        } +        if (sampleRate != 0) { +            if (*sampleRate != 0) { +                lRate = *sampleRate; +            } else { +                *sampleRate = lRate; +            } +        }          if (status) *status = NO_ERROR;      }      LOGV("openInputStream(), inFinal %p", inFinal); @@ -223,6 +243,15 @@ String8 AudioDumpInterface::getParameters(const String8& keys)      return keyValuePairs;  } +status_t AudioDumpInterface::setMode(int mode) +{ +    return mFinalInterface->setMode(mode); +} + +size_t AudioDumpInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) +{ +    return mFinalInterface->getInputBufferSize(sampleRate, format, channelCount); +}  // ---------------------------------------------------------------------------- @@ -235,7 +264,7 @@ AudioStreamOutDump::AudioStreamOutDump(AudioDumpInterface *interface,                                          uint32_t sampleRate)      : mInterface(interface), mId(id),        mSampleRate(sampleRate), mFormat(format), mChannels(channels), mLatency(0), mDevice(devices), -      mBufferSize(1024), mFinalStream(finalStream), mOutFile(0), mFileCount(0) +      mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0)  {      LOGV("AudioStreamOutDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);  } @@ -254,26 +283,26 @@ ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)      if (mFinalStream) {          ret = mFinalStream->write(buffer, bytes);      } else { -        usleep((bytes * 1000000) / frameSize() / sampleRate()); +        usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000);          ret = bytes;      } -    if(!mOutFile) { +    if(!mFile) {          if (mInterface->fileName() != "") {              char name[255]; -            sprintf(name, "%s_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount); -            mOutFile = fopen(name, "wb"); -            LOGV("Opening dump file %s, fh %p", name, mOutFile); +            sprintf(name, "%s_out_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount); +            mFile = fopen(name, "wb"); +            LOGV("Opening dump file %s, fh %p", name, mFile);          }      } -    if (mOutFile) { -        fwrite(buffer, bytes, 1, mOutFile); +    if (mFile) { +        fwrite(buffer, bytes, 1, mFile);      }      return ret;  }  status_t AudioStreamOutDump::standby()  { -    LOGV("AudioStreamOutDump standby(), mOutFile %p, mFinalStream %p", mOutFile, mFinalStream); +    LOGV("AudioStreamOutDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream);      Close();      if (mFinalStream != 0 ) return mFinalStream->standby(); @@ -330,7 +359,7 @@ status_t AudioStreamOutDump::setParameters(const String8& keyValuePairs)      }      if (param.getInt(String8("format"), valueInt) == NO_ERROR) { -        if (mOutFile == 0) { +        if (mFile == 0) {              mFormat = valueInt;          } else {              status = INVALID_OPERATION; @@ -345,7 +374,7 @@ status_t AudioStreamOutDump::setParameters(const String8& keyValuePairs)      }      if (param.getInt(String8("sampling_rate"), valueInt) == NO_ERROR) {          if (valueInt > 0 && valueInt <= 48000) { -            if (mOutFile == 0) { +            if (mFile == 0) {                  mSampleRate = valueInt;              } else {                  status = INVALID_OPERATION; @@ -373,9 +402,9 @@ status_t AudioStreamOutDump::dump(int fd, const Vector<String16>& args)  void AudioStreamOutDump::Close()  { -    if(mOutFile) { -        fclose(mOutFile); -        mOutFile = 0; +    if(mFile) { +        fclose(mFile); +        mFile = 0;      }  } @@ -396,7 +425,7 @@ AudioStreamInDump::AudioStreamInDump(AudioDumpInterface *interface,                                          uint32_t sampleRate)      : mInterface(interface), mId(id),        mSampleRate(sampleRate), mFormat(format), mChannels(channels), mDevice(devices), -      mBufferSize(1024), mFinalStream(finalStream), mInFile(0) +      mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0)  {      LOGV("AudioStreamInDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);  } @@ -409,55 +438,68 @@ AudioStreamInDump::~AudioStreamInDump()  ssize_t AudioStreamInDump::read(void* buffer, ssize_t bytes)  { -    if (mFinalStream) { -        return mFinalStream->read(buffer, bytes); -    } - -    usleep((bytes * 1000000) / frameSize() / sampleRate()); +    ssize_t ret; -    if(!mInFile) { -        char name[255]; -        strcpy(name, "/sdcard/music/sine440"); -        if (channels() == AudioSystem::CHANNEL_IN_MONO) { -            strcat(name, "_mo"); -        } else { -            strcat(name, "_st"); +    if (mFinalStream) { +        ret = mFinalStream->read(buffer, bytes); +        if(!mFile) { +            if (mInterface->fileName() != "") { +                char name[255]; +                sprintf(name, "%s_in_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount); +                mFile = fopen(name, "wb"); +                LOGV("Opening input dump file %s, fh %p", name, mFile); +            }          } -        if (format() == AudioSystem::PCM_16_BIT) { -            strcat(name, "_16b"); -        } else { -            strcat(name, "_8b"); +        if (mFile) { +            fwrite(buffer, bytes, 1, mFile);          } -        if (sampleRate() < 16000) { -            strcat(name, "_8k"); -        } else if (sampleRate() < 32000) { -            strcat(name, "_22k"); -        } else if (sampleRate() < 48000) { -            strcat(name, "_44k"); -        } else { -            strcat(name, "_48k"); -        } -        strcat(name, ".wav"); -        mInFile = fopen(name, "rb"); -        LOGV("Opening dump file %s, fh %p", name, mInFile); -        if (mInFile) { -            fseek(mInFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); +    } else { +        usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000); +        ret = bytes; +        if(!mFile) { +            char name[255]; +            strcpy(name, "/sdcard/music/sine440"); +            if (channels() == AudioSystem::CHANNEL_IN_MONO) { +                strcat(name, "_mo"); +            } else { +                strcat(name, "_st"); +            } +            if (format() == AudioSystem::PCM_16_BIT) { +                strcat(name, "_16b"); +            } else { +                strcat(name, "_8b"); +            } +            if (sampleRate() < 16000) { +                strcat(name, "_8k"); +            } else if (sampleRate() < 32000) { +                strcat(name, "_22k"); +            } else if (sampleRate() < 48000) { +                strcat(name, "_44k"); +            } else { +                strcat(name, "_48k"); +            } +            strcat(name, ".wav"); +            mFile = fopen(name, "rb"); +            LOGV("Opening input read file %s, fh %p", name, mFile); +            if (mFile) { +                fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); +            }          } - -    } -    if (mInFile) { -        ssize_t bytesRead = fread(buffer, bytes, 1, mInFile); -        if (bytesRead != bytes) { -            fseek(mInFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); -            fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mInFile); +        if (mFile) { +            ssize_t bytesRead = fread(buffer, bytes, 1, mFile); +            if (bytesRead >=0 && bytesRead < bytes) { +                fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); +                fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mFile); +            }          }      } -    return bytes; + +    return ret;  }  status_t AudioStreamInDump::standby()  { -    LOGV("AudioStreamInDump standby(), mInFile %p, mFinalStream %p", mInFile, mFinalStream); +    LOGV("AudioStreamInDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream);      Close();      if (mFinalStream != 0 ) return mFinalStream->standby(); @@ -523,9 +565,9 @@ status_t AudioStreamInDump::dump(int fd, const Vector<String16>& args)  void AudioStreamInDump::Close()  { -    if(mInFile) { -        fclose(mInFile); -        mInFile = 0; +    if(mFile) { +        fclose(mFile); +        mFile = 0;      }  }  }; // namespace android diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h index 4c62b3ed78..814ce5f717 100644 --- a/libs/audioflinger/AudioDumpInterface.h +++ b/libs/audioflinger/AudioDumpInterface.h @@ -69,7 +69,7 @@ private:      uint32_t mDevice;                   // current device this output is routed to      size_t  mBufferSize;      AudioStreamOut      *mFinalStream; -    FILE                *mOutFile;      // output file +    FILE                *mFile;      // output file      int                 mFileCount;  }; @@ -109,7 +109,8 @@ private:      uint32_t mDevice;                   // current device this output is routed to      size_t  mBufferSize;      AudioStreamIn      *mFinalStream; -    FILE                *mInFile;      // output file +    FILE                *mFile;      // output file +    int                 mFileCount;  };  class AudioDumpInterface : public AudioHardwareBase @@ -134,6 +135,8 @@ public:      virtual status_t    setMasterVolume(float volume)                              {return mFinalInterface->setMasterVolume(volume);} +    virtual status_t    setMode(int mode); +      // mic mute      virtual status_t    setMicMute(bool state)                              {return mFinalInterface->setMicMute(state);} @@ -143,6 +146,8 @@ public:      virtual status_t    setParameters(const String8& keyValuePairs);      virtual String8     getParameters(const String8& keys); +    virtual size_t      getInputBufferSize(uint32_t sampleRate, int format, int channelCount); +      virtual AudioStreamIn* openInputStream(uint32_t devices, int *format, uint32_t *channels,              uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics);      virtual    void        closeInputStream(AudioStreamIn* in); @@ -153,8 +158,7 @@ public:  protected:      AudioHardwareInterface          *mFinalInterface; -    SortedVector<AudioStreamOutDump *>    mOutputs; -    bool                            mFirstHwOutput; +    SortedVector<AudioStreamOutDump *>   mOutputs;      SortedVector<AudioStreamInDump *>    mInputs;      Mutex                           mLock;      String8                         mPolicyCommands; diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index 2414e8dc5e..1860793d9f 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -37,7 +37,7 @@  #include <media/AudioRecord.h>  #include <private/media/AudioTrackShared.h> - +#include <private/media/AudioEffectShared.h>  #include <hardware_legacy/AudioHardwareInterface.h>  #include "AudioMixer.h" @@ -51,6 +51,8 @@  #include "lifevibes.h"  #endif +#include <media/EffectFactoryApi.h> +  // ----------------------------------------------------------------------------  // the sim build doesn't have gettid @@ -67,6 +69,7 @@ static const char* kHardwareLockedString = "Hardware lock is taken\n";  //static const nsecs_t kStandbyTimeInNsecs = seconds(3);  static const float MAX_GAIN = 4096.0f; +static const float MAX_GAIN_INT = 0x1000;  // retry counts for buffer fill timeout  // 50 * ~20msecs = 1 second @@ -123,7 +126,7 @@ static bool settingsAllowed() {  AudioFlinger::AudioFlinger()      : BnAudioFlinger(), -        mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextThreadId(0) +        mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)  {      mHardwareStatus = AUDIO_HW_IDLE; @@ -142,6 +145,7 @@ AudioFlinger::AudioFlinger()      }  #ifdef LVMX      LifeVibes::init(); +    mLifeVibesClientPid = -1;  #endif  } @@ -281,6 +285,7 @@ sp<IAudioTrack> AudioFlinger::createTrack(          uint32_t flags,          const sp<IMemory>& sharedBuffer,          int output, +        int *sessionId,          status_t *status)  {      sp<PlaybackThread::Track> track; @@ -288,6 +293,7 @@ sp<IAudioTrack> AudioFlinger::createTrack(      sp<Client> client;      wp<Client> wclient;      status_t lStatus; +    int lSessionId;      if (streamType >= AudioSystem::NUM_STREAM_TYPES) {          LOGE("invalid stream type"); @@ -312,8 +318,23 @@ sp<IAudioTrack> AudioFlinger::createTrack(              client = new Client(this, pid);              mClients.add(pid, client);          } + +        // If no audio session id is provided, create one here +        // TODO: enforce same stream type for all tracks in same audio session? +        // TODO: prevent same audio session on different output threads +        LOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId); +        if (sessionId != NULL && *sessionId != 0) { +            lSessionId = *sessionId; +        } else { +            lSessionId = nextUniqueId(); +            if (sessionId != NULL) { +                *sessionId = lSessionId; +            } +        } +        LOGV("createTrack() lSessionId: %d", lSessionId); +          track = thread->createTrack_l(client, streamType, sampleRate, format, -                channelCount, frameCount, sharedBuffer, &lStatus); +                channelCount, frameCount, sharedBuffer, lSessionId, &lStatus);      }      if (lStatus == NO_ERROR) {          trackHandle = new TrackHandle(track); @@ -596,8 +617,10 @@ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs)      int musicEnabled = -1;      if (NO_ERROR == param.get(key, value)) {          if (value == LifevibesEnable) { +            mLifeVibesClientPid = IPCThreadState::self()->getCallingPid();              musicEnabled = 1;          } else if (value == LifevibesDisable) { +            mLifeVibesClientPid = -1;              musicEnabled = 0;          }      } @@ -609,7 +632,7 @@ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs)          mHardwareStatus = AUDIO_SET_PARAMETER;          result = mAudioHardware->setParameters(keyValuePairs);  #ifdef LVMX -        if ((NO_ERROR == result) && (musicEnabled != -1)) { +        if (musicEnabled != -1) {              LifeVibes::enableMusic((bool) musicEnabled);          }  #endif @@ -713,51 +736,57 @@ status_t AudioFlinger::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrame  void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)  { -    LOGV("registerClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid());      Mutex::Autolock _l(mLock); -    sp<IBinder> binder = client->asBinder(); -    if (mNotificationClients.indexOf(binder) < 0) { -        LOGV("Adding notification client %p", binder.get()); -        binder->linkToDeath(this); -        mNotificationClients.add(binder); -    } +    int pid = IPCThreadState::self()->getCallingPid(); +    if (mNotificationClients.indexOfKey(pid) < 0) { +        sp<NotificationClient> notificationClient = new NotificationClient(this, +                                                                            client, +                                                                            pid); +        LOGV("registerClient() client %p, pid %d", notificationClient.get(), pid); -    // the config change is always sent from playback or record threads to avoid deadlock -    // with AudioSystem::gLock -    for (size_t i = 0; i < mPlaybackThreads.size(); i++) { -        mPlaybackThreads.valueAt(i)->sendConfigEvent(AudioSystem::OUTPUT_OPENED); -    } +        mNotificationClients.add(pid, notificationClient); + +        sp<IBinder> binder = client->asBinder(); +        binder->linkToDeath(notificationClient); + +        // the config change is always sent from playback or record threads to avoid deadlock +        // with AudioSystem::gLock +        for (size_t i = 0; i < mPlaybackThreads.size(); i++) { +            mPlaybackThreads.valueAt(i)->sendConfigEvent(AudioSystem::OUTPUT_OPENED); +        } -    for (size_t i = 0; i < mRecordThreads.size(); i++) { -        mRecordThreads.valueAt(i)->sendConfigEvent(AudioSystem::INPUT_OPENED); +        for (size_t i = 0; i < mRecordThreads.size(); i++) { +            mRecordThreads.valueAt(i)->sendConfigEvent(AudioSystem::INPUT_OPENED); +        }      }  } -void AudioFlinger::binderDied(const wp<IBinder>& who) { - -    LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid()); +void AudioFlinger::removeNotificationClient(pid_t pid) +{      Mutex::Autolock _l(mLock); -    IBinder *binder = who.unsafe_get(); - -    if (binder != NULL) { -        int index = mNotificationClients.indexOf(binder); -        if (index >= 0) { -            LOGV("Removing notification client %p", binder); -            mNotificationClients.removeAt(index); +    int index = mNotificationClients.indexOfKey(pid); +    if (index >= 0) { +        sp <NotificationClient> client = mNotificationClients.valueFor(pid); +        LOGV("removeNotificationClient() %p, pid %d", client.get(), pid); +#ifdef LVMX +        if (pid == mLifeVibesClientPid) { +            LOGV("Disabling lifevibes"); +            LifeVibes::enableMusic(false); +            mLifeVibesClientPid = -1;          } +#endif +        mNotificationClients.removeItem(pid);      }  }  // audioConfigChanged_l() must be called with AudioFlinger::mLock held -void AudioFlinger::audioConfigChanged_l(int event, int ioHandle, void *param2) { +void AudioFlinger::audioConfigChanged_l(int event, int ioHandle, void *param2) +{      size_t size = mNotificationClients.size();      for (size_t i = 0; i < size; i++) { -        sp<IBinder> binder = mNotificationClients.itemAt(i); -        LOGV("audioConfigChanged_l() Notifying change to client %p", binder.get()); -        sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder); -        client->ioConfigChanged(event, ioHandle, param2); +        mNotificationClients.valueAt(i)->client()->ioConfigChanged(event, ioHandle, param2);      }  } @@ -768,12 +797,13 @@ void AudioFlinger::removeClient_l(pid_t pid)      mClients.removeItem(pid);  } +  // ----------------------------------------------------------------------------  AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id)      :   Thread(false),          mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0), -        mFormat(0), mFrameSize(1), mStandby(false), mId(id), mExiting(false) +        mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false)  {  } @@ -806,7 +836,7 @@ uint32_t AudioFlinger::ThreadBase::sampleRate() const  int AudioFlinger::ThreadBase::channelCount() const  { -    return mChannelCount; +    return (int)mChannelCount;  }  int AudioFlinger::ThreadBase::format() const @@ -863,11 +893,12 @@ void AudioFlinger::ThreadBase::processConfigEvents()          LOGV("processConfigEvents() remaining events %d", mConfigEvents.size());          ConfigEvent *configEvent = mConfigEvents[0];          mConfigEvents.removeAt(0); -        // release mLock because audioConfigChanged() will lock AudioFlinger mLock -        // before calling Audioflinger::audioConfigChanged_l() thus creating -        // potential cross deadlock between AudioFlinger::mLock and mLock +        // release mLock before locking AudioFlinger mLock: lock order is always +        // AudioFlinger then ThreadBase to avoid cross deadlock          mLock.unlock(); -        audioConfigChanged(configEvent->mEvent, configEvent->mParam); +        mAudioFlinger->mLock.lock(); +        audioConfigChanged_l(configEvent->mEvent, configEvent->mParam); +        mAudioFlinger->mLock.unlock();          delete configEvent;          mLock.lock();      } @@ -929,10 +960,11 @@ status_t AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args  // ---------------------------------------------------------------------------- -AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id) +AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)      :   ThreadBase(audioFlinger, id),          mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output), -        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false) +        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false), +        mDevice(device)  {      readOutputParameters(); @@ -943,8 +975,6 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge          mStreamTypes[stream].volume = mAudioFlinger->streamVolumeInternal(stream);          mStreamTypes[stream].mute = mAudioFlinger->streamMute(stream);      } -    // notify client processes that a new input has been opened -    sendConfigEvent(AudioSystem::OUTPUT_OPENED);  }  AudioFlinger::PlaybackThread::~PlaybackThread() @@ -956,6 +986,7 @@ status_t AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args  {      dumpInternals(fd, args);      dumpTracks(fd, args); +    dumpEffectChains(fd, args);      return NO_ERROR;  } @@ -967,7 +998,7 @@ status_t AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>      snprintf(buffer, SIZE, "Output thread %p tracks\n", this);      result.append(buffer); -    result.append("   Name Clien Typ Fmt Chn Buf  S M F SRate  LeftV RighV Serv     User\n"); +    result.append("   Name  Clien Typ Fmt Chn Session Buf  S M F SRate LeftV RighV  Serv       User       Main buf   Aux Buf\n");      for (size_t i = 0; i < mTracks.size(); ++i) {          sp<Track> track = mTracks[i];          if (track != 0) { @@ -978,7 +1009,7 @@ status_t AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>      snprintf(buffer, SIZE, "Output thread %p active tracks\n", this);      result.append(buffer); -    result.append("   Name Clien Typ Fmt Chn Buf  S M F SRate  LeftV RighV Serv     User\n"); +    result.append("   Name  Clien Typ Fmt Chn Session Buf  S M F SRate LeftV RighV  Serv       User       Main buf   Aux Buf\n");      for (size_t i = 0; i < mActiveTracks.size(); ++i) {          wp<Track> wTrack = mActiveTracks[i];          if (wTrack != 0) { @@ -993,6 +1024,24 @@ status_t AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>      return NO_ERROR;  } +status_t AudioFlinger::PlaybackThread::dumpEffectChains(int fd, const Vector<String16>& args) +{ +    const size_t SIZE = 256; +    char buffer[SIZE]; +    String8 result; + +    snprintf(buffer, SIZE, "\n- %d Effect Chains:\n", mEffectChains.size()); +    write(fd, buffer, strlen(buffer)); + +    for (size_t i = 0; i < mEffectChains.size(); ++i) { +        sp<EffectChain> chain = mEffectChains[i]; +        if (chain != 0) { +            chain->dump(fd, args); +        } +    } +    return NO_ERROR; +} +  status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)  {      const size_t SIZE = 256; @@ -1011,6 +1060,8 @@ status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String      result.append(buffer);      snprintf(buffer, SIZE, "suspend count: %d\n", mSuspended);      result.append(buffer); +    snprintf(buffer, SIZE, "mix buffer : %p\n", mMixBuffer); +    result.append(buffer);      write(fd, result.string(), result.size());      dumpBase(fd, args); @@ -1048,13 +1099,14 @@ sp<AudioFlinger::PlaybackThread::Track>  AudioFlinger::PlaybackThread::createTra          int channelCount,          int frameCount,          const sp<IMemory>& sharedBuffer, +        int sessionId,          status_t *status)  {      sp<Track> track;      status_t lStatus;      if (mType == DIRECT) { -        if (sampleRate != mSampleRate || format != mFormat || channelCount != mChannelCount) { +        if (sampleRate != mSampleRate || format != mFormat || channelCount != (int)mChannelCount) {              LOGE("createTrack_l() Bad parameter:  sampleRate %d format %d, channelCount %d for output %p",                   sampleRate, format, channelCount, mOutput);              lStatus = BAD_VALUE; @@ -1078,12 +1130,18 @@ sp<AudioFlinger::PlaybackThread::Track>  AudioFlinger::PlaybackThread::createTra      { // scope for mLock          Mutex::Autolock _l(mLock);          track = new Track(this, client, streamType, sampleRate, format, -                channelCount, frameCount, sharedBuffer); +                channelCount, frameCount, sharedBuffer, sessionId);          if (track->getCblk() == NULL || track->name() < 0) {              lStatus = NO_MEMORY;              goto Exit;          }          mTracks.add(track); + +        sp<EffectChain> chain = getEffectChain_l(sessionId); +        if (chain != 0) { +            LOGV("createTrack_l() setting main buffer %p", chain->inBuffer()); +            track->setMainBuffer(chain->inBuffer()); +        }      }      lStatus = NO_ERROR; @@ -1200,6 +1258,14 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)          track->mFillingUpStatus = Track::FS_FILLING;          track->mResetDone = false;          mActiveTracks.add(track); +        if (track->mainBuffer() != mMixBuffer) { +            sp<EffectChain> chain = getEffectChain_l(track->sessionId()); +            if (chain != 0) { +                LOGV("addTrack_l() starting track on chain %p for session %d", chain.get(), track->sessionId()); +                chain->startTrack(); +            } +        } +          status = NO_ERROR;      } @@ -1224,16 +1290,17 @@ String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys)      return mOutput->getParameters(keys);  } -void AudioFlinger::PlaybackThread::audioConfigChanged(int event, int param) { +// destroyTrack_l() must be called with AudioFlinger::mLock held +void AudioFlinger::PlaybackThread::audioConfigChanged_l(int event, int param) {      AudioSystem::OutputDescriptor desc;      void *param2 = 0; -    LOGV("PlaybackThread::audioConfigChanged, thread %p, event %d, param %d", this, event, param); +    LOGV("PlaybackThread::audioConfigChanged_l, thread %p, event %d, param %d", this, event, param);      switch (event) {      case AudioSystem::OUTPUT_OPENED:      case AudioSystem::OUTPUT_CONFIG_CHANGED: -        desc.channels = mChannelCount; +        desc.channels = mChannels;          desc.samplingRate = mSampleRate;          desc.format = mFormat;          desc.frameCount = mFrameCount; @@ -1247,24 +1314,25 @@ void AudioFlinger::PlaybackThread::audioConfigChanged(int event, int param) {      default:          break;      } -    Mutex::Autolock _l(mAudioFlinger->mLock);      mAudioFlinger->audioConfigChanged_l(event, mId, param2);  }  void AudioFlinger::PlaybackThread::readOutputParameters()  {      mSampleRate = mOutput->sampleRate(); -    mChannelCount = AudioSystem::popCount(mOutput->channels()); - +    mChannels = mOutput->channels(); +    mChannelCount = (uint16_t)AudioSystem::popCount(mChannels);      mFormat = mOutput->format(); -    mFrameSize = mOutput->frameSize(); +    mFrameSize = (uint16_t)mOutput->frameSize();      mFrameCount = mOutput->bufferSize() / mFrameSize;      // FIXME - Current mixer implementation only supports stereo output: Always      // Allocate a stereo buffer even if HW output is mono. -    if (mMixBuffer != NULL) delete mMixBuffer; +    if (mMixBuffer != NULL) delete[] mMixBuffer;      mMixBuffer = new int16_t[mFrameCount * 2];      memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t)); + +    //TODO handle effects reconfig  }  status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames) @@ -1280,10 +1348,47 @@ status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, ui      return mOutput->getRenderPosition(dspFrames);  } +bool AudioFlinger::PlaybackThread::hasAudioSession(int sessionId) +{ +    Mutex::Autolock _l(mLock); +    if (getEffectChain_l(sessionId) != 0) { +        return true; +    } + +    for (size_t i = 0; i < mTracks.size(); ++i) { +        sp<Track> track = mTracks[i]; +        if (sessionId == track->sessionId()) { +            return true; +        } +    } + +    return false; +} + +sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain(int sessionId) +{ +    Mutex::Autolock _l(mLock); +    return getEffectChain_l(sessionId); +} + +sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain_l(int sessionId) +{ +    sp<EffectChain> chain; + +    size_t size = mEffectChains.size(); +    for (size_t i = 0; i < size; i++) { +        if (mEffectChains[i]->sessionId() == sessionId) { +            chain = mEffectChains[i]; +            break; +        } +    } +    return chain; +} +  // ---------------------------------------------------------------------------- -AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id) -    :   PlaybackThread(audioFlinger, output, id), +AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device) +    :   PlaybackThread(audioFlinger, output, id, device),          mAudioMixer(0)  {      mType = PlaybackThread::MIXER; @@ -1302,7 +1407,6 @@ AudioFlinger::MixerThread::~MixerThread()  bool AudioFlinger::MixerThread::threadLoop()  { -    int16_t* curBuf = mMixBuffer;      Vector< sp<Track> > tracksToRemove;      uint32_t mixerStatus = MIXER_IDLE;      nsecs_t standbyTime = systemTime(); @@ -1315,6 +1419,7 @@ bool AudioFlinger::MixerThread::threadLoop()      uint32_t activeSleepTime = activeSleepTimeUs();      uint32_t idleSleepTime = idleSleepTimeUs();      uint32_t sleepTime = idleSleepTime; +    Vector< sp<EffectChain> > effectChains;      while (!exitPending())      { @@ -1373,13 +1478,20 @@ bool AudioFlinger::MixerThread::threadLoop()              }              mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove); + +            // prevent any changes in effect chain list and in each effect chain +            // during mixing and effect process as the audio buffers could be deleted +            // or modified if an effect is created or deleted +            effectChains = mEffectChains; +            lockEffectChains_l();         }          if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {              // mix buffers... -            mAudioMixer->process(curBuf); +            mAudioMixer->process();              sleepTime = 0;              standbyTime = systemTime() + kStandbyTimeInNsecs; +            //TODO: delay standby when effects have a tail          } else {              // If no tracks are ready, sleep once for the duration of an output              // buffer size, then write 0s to the output @@ -1391,10 +1503,11 @@ bool AudioFlinger::MixerThread::threadLoop()                  }              } else if (mBytesWritten != 0 ||                         (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) { -                memset (curBuf, 0, mixBufferSize); +                memset (mMixBuffer, 0, mixBufferSize);                  sleepTime = 0;                  LOGV_IF((mBytesWritten == 0 && (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start");              } +            // TODO add standby time extension fct of effect tail          }          if (mSuspended) { @@ -1402,16 +1515,22 @@ bool AudioFlinger::MixerThread::threadLoop()          }          // sleepTime == 0 means we must write to audio hardware          if (sleepTime == 0) { -            mLastWriteTime = systemTime(); -            mInWrite = true; -            mBytesWritten += mixBufferSize; +             for (size_t i = 0; i < effectChains.size(); i ++) { +                 effectChains[i]->process_l(); +             } +             // enable changes in effect chain +             unlockEffectChains();  #ifdef LVMX              int audioOutputType = LifeVibes::getMixerType(mId, mType);              if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { -               LifeVibes::process(audioOutputType, curBuf, mixBufferSize); +               LifeVibes::process(audioOutputType, mMixBuffer, mixBufferSize);              }  #endif -            int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize); +            mLastWriteTime = systemTime(); +            mInWrite = true; +            mBytesWritten += mixBufferSize; + +            int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize);              if (bytesWritten < 0) mBytesWritten -= mixBufferSize;              mNumWrites++;              mInWrite = false; @@ -1430,6 +1549,8 @@ bool AudioFlinger::MixerThread::threadLoop()              }              mStandby = false;          } else { +            // enable changes in effect chain +            unlockEffectChains();              usleep(sleepTime);          } @@ -1437,6 +1558,10 @@ bool AudioFlinger::MixerThread::threadLoop()          // since we can't guarantee the destructors won't acquire that          // same lock.          tracksToRemove.clear(); + +        // Effect chains will be actually deleted here if they were removed from +        // mEffectChains list during mixing or effects processing +        effectChains.clear();      }      if (!mStandby) { @@ -1454,6 +1579,8 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track      uint32_t mixerStatus = MIXER_IDLE;      // find out which tracks need to be processed      size_t count = activeTracks.size(); +    size_t mixedTracks = 0; +    size_t tracksWithEffect = 0;      float masterVolume = mMasterVolume;      bool  masterMute = mMasterMute; @@ -1476,6 +1603,14 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track          LifeVibes::computeVolumes(audioOutputType, activeTypes, tracksConnectedChanged, stateChanged, masterVolume, masterMute);      }  #endif +    // Delegate master volume control to effect in output mix effect chain if needed +    sp<EffectChain> chain = getEffectChain_l(0); +    if (chain != 0) { +        uint32_t v = (uint32_t)(masterVolume * (1 << 24)); +        chain->setVolume(&v, &v); +        masterVolume = (float)((v + (1 << 23)) >> 24); +        chain.clear(); +    }      for (size_t i=0 ; i<count ; i++) {          sp<Track> t = activeTracks[i].promote(); @@ -1492,11 +1627,42 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track          {              //LOGV("track %d u=%08x, s=%08x [OK] on thread %p", track->name(), cblk->user, cblk->server, this); +            mixedTracks++; + +            // track->mainBuffer() != mMixBuffer means there is an effect chain +            // connected to the track +            chain.clear(); +            if (track->mainBuffer() != mMixBuffer) { +                chain = getEffectChain_l(track->sessionId()); +                // Delegate volume control to effect in track effect chain if needed +                if (chain != 0) { +                    tracksWithEffect++; +                } else { +                    LOGW("prepareTracks_l(): track %08x attached to effect but no chain found on session %d", +                            track->name(), track->sessionId()); +                } +            } + + +            int param = AudioMixer::VOLUME; +            if (track->mFillingUpStatus == Track::FS_FILLED) { +                // no ramp for the first volume setting +                track->mFillingUpStatus = Track::FS_ACTIVE; +                if (track->mState == TrackBase::RESUMING) { +                    track->mState = TrackBase::ACTIVE; +                    param = AudioMixer::RAMP_VOLUME; +                } +            } else if (cblk->server != 0) { +                // If the track is stopped before the first frame was mixed, +                // do not apply ramp +                param = AudioMixer::RAMP_VOLUME; +            } +              // compute volume for this track -            int16_t left, right; +            int16_t left, right, aux;              if (track->isMuted() || masterMute || track->isPausing() ||                  mStreamTypes[track->type()].mute) { -                left = right = 0; +                left = right = aux = 0;                  if (track->isPausing()) {                      track->setPaused();                  } @@ -1515,31 +1681,28 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track                  }  #endif                  float v = masterVolume * typeVolume; -                float v_clamped = v * cblk->volume[0]; -                if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; +                uint32_t vl = (uint32_t)(v * cblk->volume[0]) << 12; +                uint32_t vr = (uint32_t)(v * cblk->volume[1]) << 12; + +                // Delegate volume control to effect in track effect chain if needed +                if (chain != 0 && chain->setVolume(&vl, &vr)) { +                    // Do not ramp volume is volume is controlled by effect +                    param = AudioMixer::VOLUME; +                } + +                // Convert volumes from 8.24 to 4.12 format +                uint32_t v_clamped = (vl + (1 << 11)) >> 12; +                if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;                  left = int16_t(v_clamped); -                v_clamped = v * cblk->volume[1]; -                if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; +                v_clamped = (vr + (1 << 11)) >> 12; +                if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;                  right = int16_t(v_clamped); -            } -            // XXX: these things DON'T need to be done each time -            mAudioMixer->setBufferProvider(track); -            mAudioMixer->enable(AudioMixer::MIXING); - -            int param = AudioMixer::VOLUME; -            if (track->mFillingUpStatus == Track::FS_FILLED) { -                // no ramp for the first volume setting -                track->mFillingUpStatus = Track::FS_ACTIVE; -                if (track->mState == TrackBase::RESUMING) { -                    track->mState = TrackBase::ACTIVE; -                    param = AudioMixer::RAMP_VOLUME; -                } -            } else if (cblk->server != 0) { -                // If the track is stopped before the first frame was mixed, -                // do not apply ramp -                param = AudioMixer::RAMP_VOLUME; +                v_clamped = (uint32_t)(v * cblk->sendLevel); +                if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT; +                aux = int16_t(v_clamped);              } +  #ifdef LVMX              if ( tracksConnectedChanged || stateChanged )              { @@ -1547,18 +1710,30 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track                   param = AudioMixer::VOLUME;              }  #endif -            mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left); -            mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right); + +            // XXX: these things DON'T need to be done each time +            mAudioMixer->setBufferProvider(track); +            mAudioMixer->enable(AudioMixer::MIXING); + +            mAudioMixer->setParameter(param, AudioMixer::VOLUME0, (void *)left); +            mAudioMixer->setParameter(param, AudioMixer::VOLUME1, (void *)right); +            mAudioMixer->setParameter(param, AudioMixer::AUXLEVEL, (void *)aux);              mAudioMixer->setParameter(                  AudioMixer::TRACK, -                AudioMixer::FORMAT, track->format()); +                AudioMixer::FORMAT, (void *)track->format());              mAudioMixer->setParameter(                  AudioMixer::TRACK, -                AudioMixer::CHANNEL_COUNT, track->channelCount()); +                AudioMixer::CHANNEL_COUNT, (void *)track->channelCount());              mAudioMixer->setParameter(                  AudioMixer::RESAMPLE,                  AudioMixer::SAMPLE_RATE, -                int(cblk->sampleRate)); +                (void *)(cblk->sampleRate)); +            mAudioMixer->setParameter( +                AudioMixer::TRACK, +                AudioMixer::MAIN_BUFFER, (void *)track->mainBuffer()); +            mAudioMixer->setParameter( +                AudioMixer::TRACK, +                AudioMixer::AUX_BUFFER, (void *)track->auxBuffer());              // reset retry count              track->mRetryCount = kMaxTrackRetries; @@ -1572,7 +1747,6 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track                  // We have consumed all the buffers of this track.                  // Remove it from the list of active tracks.                  tracksToRemove->add(track); -                mAudioMixer->disable(AudioMixer::MIXING);              } else {                  // No buffers for this track. Give it a few chances to                  // fill a buffer, then remove it from active list. @@ -1582,9 +1756,8 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track                  } else if (mixerStatus != MIXER_TRACKS_READY) {                      mixerStatus = MIXER_TRACKS_ENABLED;                  } - -                mAudioMixer->disable(AudioMixer::MIXING);              } +            mAudioMixer->disable(AudioMixer::MIXING);          }      } @@ -1594,6 +1767,13 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track          for (size_t i=0 ; i<count ; i++) {              const sp<Track>& track = tracksToRemove->itemAt(i);              mActiveTracks.remove(track); +            if (track->mainBuffer() != mMixBuffer) { +                chain = getEffectChain_l(track->sessionId()); +                if (chain != 0) { +                    LOGV("stopping track on chain %p for session Id: %d", chain.get(), track->sessionId()); +                    chain->stopTrack(); +                } +            }              if (track->isTerminated()) {                  mTracks.remove(track);                  deleteTrackName_l(track->mName); @@ -1601,69 +1781,32 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track          }      } +    // mix buffer must be cleared if all tracks are connected to an +    // effect chain as in this case the mixer will not write to +    // mix buffer and track effects will accumulate into it +    if (mixedTracks != 0 && mixedTracks == tracksWithEffect) { +        memset(mMixBuffer, 0, mFrameCount * mChannelCount * sizeof(int16_t)); +    } +      return mixerStatus;  } -void AudioFlinger::MixerThread::getTracks( -        SortedVector < sp<Track> >& tracks, -        SortedVector < wp<Track> >& activeTracks, -        int streamType) +void AudioFlinger::MixerThread::invalidateTracks(int streamType)  { -    LOGV ("MixerThread::getTracks() mixer %p, mTracks.size %d, mActiveTracks.size %d", this,  mTracks.size(), mActiveTracks.size()); +    LOGV ("MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d", this,  streamType, mTracks.size());      Mutex::Autolock _l(mLock);      size_t size = mTracks.size();      for (size_t i = 0; i < size; i++) {          sp<Track> t = mTracks[i];          if (t->type() == streamType) { -            tracks.add(t); -            int j = mActiveTracks.indexOf(t); -            if (j >= 0) { -                t = mActiveTracks[j].promote(); -                if (t != NULL) { -                    activeTracks.add(t); +            t->mCblk->lock.lock(); +            t->mCblk->flags |= CBLK_INVALID_ON; +            t->mCblk->cv.signal(); +            t->mCblk->lock.unlock();                  }              }          } -    } - -    size = activeTracks.size(); -    for (size_t i = 0; i < size; i++) { -        mActiveTracks.remove(activeTracks[i]); -    } - -    size = tracks.size(); -    for (size_t i = 0; i < size; i++) { -        sp<Track> t = tracks[i]; -        mTracks.remove(t); -        deleteTrackName_l(t->name()); -    } -} - -void AudioFlinger::MixerThread::putTracks( -        SortedVector < sp<Track> >& tracks, -        SortedVector < wp<Track> >& activeTracks) -{ -    LOGV ("MixerThread::putTracks() mixer %p, tracks.size %d, activeTracks.size %d", this,  tracks.size(), activeTracks.size()); -    Mutex::Autolock _l(mLock); -    size_t size = tracks.size(); -    for (size_t i = 0; i < size ; i++) { -        sp<Track> t = tracks[i]; -        int name = getTrackName_l(); - -        if (name < 0) return; - -        t->mName = name; -        t->mThread = this; -        mTracks.add(t); -        int j = activeTracks.indexOf(t); -        if (j >= 0) { -            mActiveTracks.add(t); -            // force buffer refilling and no ramp volume when the track is mixed for the first time -            t->mFillingUpStatus = Track::FS_FILLING; -        } -    } -}  // getTrackName_l() must be called with ThreadBase::mLock held  int AudioFlinger::MixerThread::getTrackName_l() @@ -1716,6 +1859,15 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l()                  reconfig = true;              }          } +        if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) { +            // forward device change to effects that have requested to be +            // aware of attached audio device. +            mDevice = (uint32_t)value; +            for (size_t i = 0; i < mEffectChains.size(); i++) { +                mEffectChains[i]->setDevice(mDevice); +            } +        } +          if (status == NO_ERROR) {              status = mOutput->setParameters(keyValuePair);              if (!mStandby && status == INVALID_OPERATION) { @@ -1775,9 +1927,8 @@ uint32_t AudioFlinger::MixerThread::idleSleepTimeUs()  }  // ---------------------------------------------------------------------------- -AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id) -    :   PlaybackThread(audioFlinger, output, id), -    mLeftVolume (1.0), mRightVolume(1.0) +AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device) +    :   PlaybackThread(audioFlinger, output, id, device)  {      mType = PlaybackThread::DIRECT;  } @@ -1787,6 +1938,102 @@ AudioFlinger::DirectOutputThread::~DirectOutputThread()  } +static inline int16_t clamp16(int32_t sample) +{ +    if ((sample>>15) ^ (sample>>31)) +        sample = 0x7FFF ^ (sample>>31); +    return sample; +} + +static inline +int32_t mul(int16_t in, int16_t v) +{ +#if defined(__arm__) && !defined(__thumb__) +    int32_t out; +    asm( "smulbb %[out], %[in], %[v] \n" +         : [out]"=r"(out) +         : [in]"%r"(in), [v]"r"(v) +         : ); +    return out; +#else +    return in * int32_t(v); +#endif +} + +void AudioFlinger::DirectOutputThread::applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp) +{ +    // Do not apply volume on compressed audio +    if (!AudioSystem::isLinearPCM(mFormat)) { +        return; +    } + +    // convert to signed 16 bit before volume calculation +    if (mFormat == AudioSystem::PCM_8_BIT) { +        size_t count = mFrameCount * mChannelCount; +        uint8_t *src = (uint8_t *)mMixBuffer + count-1; +        int16_t *dst = mMixBuffer + count-1; +        while(count--) { +            *dst-- = (int16_t)(*src--^0x80) << 8; +        } +    } + +    size_t frameCount = mFrameCount; +    int16_t *out = mMixBuffer; +    if (ramp) { +        if (mChannelCount == 1) { +            int32_t d = ((int32_t)leftVol - (int32_t)mLeftVolShort) << 16; +            int32_t vlInc = d / (int32_t)frameCount; +            int32_t vl = ((int32_t)mLeftVolShort << 16); +            do { +                out[0] = clamp16(mul(out[0], vl >> 16) >> 12); +                out++; +                vl += vlInc; +            } while (--frameCount); + +        } else { +            int32_t d = ((int32_t)leftVol - (int32_t)mLeftVolShort) << 16; +            int32_t vlInc = d / (int32_t)frameCount; +            d = ((int32_t)rightVol - (int32_t)mRightVolShort) << 16; +            int32_t vrInc = d / (int32_t)frameCount; +            int32_t vl = ((int32_t)mLeftVolShort << 16); +            int32_t vr = ((int32_t)mRightVolShort << 16); +            do { +                out[0] = clamp16(mul(out[0], vl >> 16) >> 12); +                out[1] = clamp16(mul(out[1], vr >> 16) >> 12); +                out += 2; +                vl += vlInc; +                vr += vrInc; +            } while (--frameCount); +        } +    } else { +        if (mChannelCount == 1) { +            do { +                out[0] = clamp16(mul(out[0], leftVol) >> 12); +                out++; +            } while (--frameCount); +        } else { +            do { +                out[0] = clamp16(mul(out[0], leftVol) >> 12); +                out[1] = clamp16(mul(out[1], rightVol) >> 12); +                out += 2; +            } while (--frameCount); +        } +    } + +    // convert back to unsigned 8 bit after volume calculation +    if (mFormat == AudioSystem::PCM_8_BIT) { +        size_t count = mFrameCount * mChannelCount; +        int16_t *src = mMixBuffer; +        uint8_t *dst = (uint8_t *)mMixBuffer; +        while(count--) { +            *dst++ = (uint8_t)(((int32_t)*src++ + (1<<7)) >> 8)^0x80; +        } +    } + +    mLeftVolShort = leftVol; +    mRightVolShort = rightVol; +} +  bool AudioFlinger::DirectOutputThread::threadLoop()  {      uint32_t mixerStatus = MIXER_IDLE; @@ -1805,6 +2052,11 @@ bool AudioFlinger::DirectOutputThread::threadLoop()      while (!exitPending())      { +        bool rampVolume; +        uint16_t leftVol; +        uint16_t rightVol; +        Vector< sp<EffectChain> > effectChains; +          processConfigEvents();          mixerStatus = MIXER_IDLE; @@ -1856,6 +2108,8 @@ bool AudioFlinger::DirectOutputThread::threadLoop()                  }              } +            effectChains = mEffectChains; +              // find out which tracks need to be processed              if (mActiveTracks.size() != 0) {                  sp<Track> t = mActiveTracks[0].promote(); @@ -1871,6 +2125,19 @@ bool AudioFlinger::DirectOutputThread::threadLoop()                  {                      //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server); +                    if (track->mFillingUpStatus == Track::FS_FILLED) { +                        track->mFillingUpStatus = Track::FS_ACTIVE; +                        mLeftVolFloat = mRightVolFloat = 0; +                        mLeftVolShort = mRightVolShort = 0; +                        if (track->mState == TrackBase::RESUMING) { +                            track->mState = TrackBase::ACTIVE; +                            rampVolume = true; +                        } +                    } else if (cblk->server != 0) { +                        // If the track is stopped before the first frame was mixed, +                        // do not apply ramp +                        rampVolume = true; +                    }                      // compute volume for this track                      float left, right;                      if (track->isMuted() || mMasterMute || track->isPausing() || @@ -1890,17 +2157,42 @@ bool AudioFlinger::DirectOutputThread::threadLoop()                          right = v_clamped/MAX_GAIN;                      } -                    if (left != mLeftVolume || right != mRightVolume) { -                        mOutput->setVolume(left, right); -                        left = mLeftVolume; -                        right = mRightVolume; -                    } +                    if (left != mLeftVolFloat || right != mRightVolFloat) { +                        mLeftVolFloat = left; +                        mRightVolFloat = right; -                    if (track->mFillingUpStatus == Track::FS_FILLED) { -                        track->mFillingUpStatus = Track::FS_ACTIVE; -                        if (track->mState == TrackBase::RESUMING) { -                            track->mState = TrackBase::ACTIVE; +                        // If audio HAL implements volume control, +                        // force software volume to nominal value +                        if (mOutput->setVolume(left, right) == NO_ERROR) { +                            left = 1.0f; +                            right = 1.0f;                          } + +                        // Convert volumes from float to 8.24 +                        uint32_t vl = (uint32_t)(left * (1 << 24)); +                        uint32_t vr = (uint32_t)(right * (1 << 24)); + +                        // Delegate volume control to effect in track effect chain if needed +                        // only one effect chain can be present on DirectOutputThread, so if +                        // there is one, the track is connected to it +                        if (!effectChains.isEmpty()) { +                            // Do not ramp volume is volume is controlled by effect +                            if(effectChains[0]->setVolume(&vl, &vr)) { +                                rampVolume = false; +                            } +                        } + +                        // Convert volumes from 8.24 to 4.12 format +                        uint32_t v_clamped = (vl + (1 << 11)) >> 12; +                        if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT; +                        leftVol = (uint16_t)v_clamped; +                        v_clamped = (vr + (1 << 11)) >> 12; +                        if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT; +                        rightVol = (uint16_t)v_clamped; +                    } else { +                        leftVol = mLeftVolShort; +                        rightVol = mRightVolShort; +                        rampVolume = false;                      }                      // reset retry count @@ -1932,11 +2224,17 @@ bool AudioFlinger::DirectOutputThread::threadLoop()              // remove all the tracks that need to be...              if (UNLIKELY(trackToRemove != 0)) {                  mActiveTracks.remove(trackToRemove); +                if (!effectChains.isEmpty()) { +                    LOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(), trackToRemove->sessionId()); +                    effectChains[0]->stopTrack(); +                }                  if (trackToRemove->isTerminated()) {                      mTracks.remove(trackToRemove);                      deleteTrackName_l(trackToRemove->mName);                  }              } + +            lockEffectChains_l();         }          if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) { @@ -1944,7 +2242,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop()              size_t frameCount = mFrameCount;              curBuf = (int8_t *)mMixBuffer;              // output audio to hardware -            while(frameCount) { +            while (frameCount) {                  buffer.frameCount = frameCount;                  activeTrack->getNextBuffer(&buffer);                  if (UNLIKELY(buffer.raw == 0)) { @@ -1976,6 +2274,14 @@ bool AudioFlinger::DirectOutputThread::threadLoop()          }          // sleepTime == 0 means we must write to audio hardware          if (sleepTime == 0) { +            if (mixerStatus == MIXER_TRACKS_READY) { +                applyVolume(leftVol, rightVol, rampVolume); +            } +            for (size_t i = 0; i < effectChains.size(); i ++) { +                effectChains[i]->process_l(); +            } +            unlockEffectChains(); +              mLastWriteTime = systemTime();              mInWrite = true;              mBytesWritten += mixBufferSize; @@ -1985,6 +2291,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop()              mInWrite = false;              mStandby = false;          } else { +            unlockEffectChains();              usleep(sleepTime);          } @@ -1993,6 +2300,10 @@ bool AudioFlinger::DirectOutputThread::threadLoop()          // same lock.          trackToRemove.clear();          activeTrack.clear(); + +        // Effect chains will be actually deleted here if they were removed from +        // mEffectChains list during mixing or effects processing +        effectChains.clear();      }      if (!mStandby) { @@ -2083,7 +2394,7 @@ uint32_t AudioFlinger::DirectOutputThread::idleSleepTimeUs()  // ----------------------------------------------------------------------------  AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, int id) -    :   MixerThread(audioFlinger, mainThread->getOutput(), id), mWaitTimeMs(UINT_MAX) +    :   MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->device()), mWaitTimeMs(UINT_MAX)  {      mType = PlaybackThread::DUPLICATING;      addOutputTrack(mainThread); @@ -2099,7 +2410,6 @@ AudioFlinger::DuplicatingThread::~DuplicatingThread()  bool AudioFlinger::DuplicatingThread::threadLoop()  { -    int16_t* curBuf = mMixBuffer;      Vector< sp<Track> > tracksToRemove;      uint32_t mixerStatus = MIXER_IDLE;      nsecs_t standbyTime = systemTime(); @@ -2109,6 +2419,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop()      uint32_t activeSleepTime = activeSleepTimeUs();      uint32_t idleSleepTime = idleSleepTimeUs();      uint32_t sleepTime = idleSleepTime; +    Vector< sp<EffectChain> > effectChains;      while (!exitPending())      { @@ -2169,14 +2480,20 @@ bool AudioFlinger::DuplicatingThread::threadLoop()              }              mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove); + +            // prevent any changes in effect chain list and in each effect chain +            // during mixing and effect process as the audio buffers could be deleted +            // or modified if an effect is created or deleted +            effectChains = mEffectChains; +            lockEffectChains_l();          }          if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {              // mix buffers...              if (outputsReady(outputTracks)) { -                mAudioMixer->process(curBuf); +                mAudioMixer->process();              } else { -                memset(curBuf, 0, mixBufferSize); +                memset(mMixBuffer, 0, mixBufferSize);              }              sleepTime = 0;              writeFrames = mFrameCount; @@ -2193,6 +2510,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop()                      if (outputTracks[i]->isActive()) {                          sleepTime = 0;                          writeFrames = 0; +                        memset(mMixBuffer, 0, mixBufferSize);                          break;                      }                  } @@ -2204,13 +2522,21 @@ bool AudioFlinger::DuplicatingThread::threadLoop()          }          // sleepTime == 0 means we must write to audio hardware          if (sleepTime == 0) { +            for (size_t i = 0; i < effectChains.size(); i ++) { +                effectChains[i]->process_l(); +            } +            // enable changes in effect chain +            unlockEffectChains(); +              standbyTime = systemTime() + kStandbyTimeInNsecs;              for (size_t i = 0; i < outputTracks.size(); i++) { -                outputTracks[i]->write(curBuf, writeFrames); +                outputTracks[i]->write(mMixBuffer, writeFrames);              }              mStandby = false;              mBytesWritten += mixBufferSize;          } else { +            // enable changes in effect chain +            unlockEffectChains();              usleep(sleepTime);          } @@ -2219,6 +2545,10 @@ bool AudioFlinger::DuplicatingThread::threadLoop()          // same lock.          tracksToRemove.clear();          outputTracks.clear(); + +        // Effect chains will be actually deleted here if they were removed from +        // mEffectChains list during mixing or effects processing +        effectChains.clear();      }      return false; @@ -2303,7 +2633,8 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(              int channelCount,              int frameCount,              uint32_t flags, -            const sp<IMemory>& sharedBuffer) +            const sp<IMemory>& sharedBuffer, +            int sessionId)      :   RefBase(),          mThread(thread),          mClient(client), @@ -2312,7 +2643,8 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(          mState(IDLE),          mClientTid(-1),          mFormat(format), -        mFlags(flags & ~SYSTEM_FLAGS_MASK) +        mFlags(flags & ~SYSTEM_FLAGS_MASK), +        mSessionId(sessionId)  {      LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); @@ -2332,13 +2664,13 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(                  // clear all buffers                  mCblk->frameCount = frameCount;                  mCblk->sampleRate = sampleRate; -                mCblk->channels = (uint8_t)channelCount; +                mCblk->channelCount = (uint8_t)channelCount;                  if (sharedBuffer == 0) {                      mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);                      memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));                      // Force underrun condition to avoid false underrun callback until first data is                      // written to buffer -                    mCblk->flowControlFlag = 1; +                    mCblk->flags = CBLK_UNDERRUN_ON;                  } else {                      mBuffer = sharedBuffer->pointer();                  } @@ -2356,12 +2688,12 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(             // clear all buffers             mCblk->frameCount = frameCount;             mCblk->sampleRate = sampleRate; -           mCblk->channels = (uint8_t)channelCount; +           mCblk->channelCount = (uint8_t)channelCount;             mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);             memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));             // Force underrun condition to avoid false underrun callback until first data is             // written to buffer -           mCblk->flowControlFlag = 1; +           mCblk->flags = CBLK_UNDERRUN_ON;             mBufferEnd = (uint8_t *)mBuffer + bufferSize;         }     } @@ -2423,7 +2755,7 @@ int AudioFlinger::ThreadBase::TrackBase::sampleRate() const {  }  int AudioFlinger::ThreadBase::TrackBase::channelCount() const { -    return (int)mCblk->channels; +    return (int)mCblk->channelCount;  }  void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const { @@ -2435,9 +2767,9 @@ void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t f      if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd ||          ((unsigned long)bufferStart & (unsigned long)(cblk->frameSize - 1))) {          LOGE("TrackBase::getBuffer buffer out of range:\n    start: %p, end %p , mBuffer %p mBufferEnd %p\n    \ -                server %d, serverBase %d, user %d, userBase %d, channels %d", +                server %d, serverBase %d, user %d, userBase %d, channelCount %d",                  bufferStart, bufferEnd, mBuffer, mBufferEnd, -                cblk->server, cblk->serverBase, cblk->user, cblk->userBase, cblk->channels); +                cblk->server, cblk->serverBase, cblk->user, cblk->userBase, cblk->channelCount);          return 0;      } @@ -2455,15 +2787,17 @@ AudioFlinger::PlaybackThread::Track::Track(              int format,              int channelCount,              int frameCount, -            const sp<IMemory>& sharedBuffer) -    :   TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer), -    mMute(false), mSharedBuffer(sharedBuffer), mName(-1) +            const sp<IMemory>& sharedBuffer, +            int sessionId) +    :   TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer, sessionId), +    mMute(false), mSharedBuffer(sharedBuffer), mName(-1), mMainBuffer(NULL), mAuxBuffer(NULL), mAuxEffectId(0)  {      if (mCblk != NULL) {          sp<ThreadBase> baseThread = thread.promote();          if (baseThread != 0) {              PlaybackThread *playbackThread = (PlaybackThread *)baseThread.get();              mName = playbackThread->getTrackName_l(); +            mMainBuffer = playbackThread->mixBuffer();          }          LOGV("Track constructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());          if (mName < 0) { @@ -2517,12 +2851,13 @@ void AudioFlinger::PlaybackThread::Track::destroy()  void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size)  { -    snprintf(buffer, size, "  %5d %5d %3u %3u %3u %04u %1d %1d %1d %5u %5u %5u  %08x %08x\n", +    snprintf(buffer, size, "   %05d %05d %03u %03u %03u %05u   %04u %1d %1d %1d %05u %05u %05u  0x%08x 0x%08x 0x%08x 0x%08x\n",              mName - AudioMixer::TRACK0,              (mClient == NULL) ? getpid() : mClient->pid(),              mStreamType,              mFormat, -            mCblk->channels, +            mCblk->channelCount, +            mSessionId,              mFrameCount,              mState,              mMute, @@ -2531,7 +2866,9 @@ void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size)              mCblk->volume[0],              mCblk->volume[1],              mCblk->server, -            mCblk->user); +            mCblk->user, +            (int)mMainBuffer, +            (int)mAuxBuffer);  }  status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer) @@ -2579,9 +2916,9 @@ bool AudioFlinger::PlaybackThread::Track::isReady() const {      if (mFillingUpStatus != FS_FILLING) return true;      if (mCblk->framesReady() >= mCblk->frameCount || -        mCblk->forceReady) { +            (mCblk->flags & CBLK_FORCEREADY_MSK)) {          mFillingUpStatus = FS_FILLED; -        mCblk->forceReady = 0; +        mCblk->flags &= ~CBLK_FORCEREADY_MSK;          return true;      }      return false; @@ -2696,8 +3033,8 @@ void AudioFlinger::PlaybackThread::Track::reset()          TrackBase::reset();          // Force underrun condition to avoid false underrun callback until first data is          // written to buffer -        mCblk->flowControlFlag = 1; -        mCblk->forceReady = 0; +        mCblk->flags |= CBLK_UNDERRUN_ON; +        mCblk->flags &= ~CBLK_FORCEREADY_MSK;          mFillingUpStatus = FS_FILLING;          mResetDone = true;      } @@ -2714,6 +3051,23 @@ void AudioFlinger::PlaybackThread::Track::setVolume(float left, float right)      mVolume[1] = right;  } +status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId) +{ +    status_t status = DEAD_OBJECT; +    sp<ThreadBase> thread = mThread.promote(); +    if (thread != 0) { +       PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); +       status = playbackThread->attachAuxEffect(this, EffectId); +    } +    return status; +} + +void AudioFlinger::PlaybackThread::Track::setAuxBuffer(int EffectId, int32_t *buffer) +{ +    mAuxEffectId = EffectId; +    mAuxBuffer = buffer; +} +  // ----------------------------------------------------------------------------  // RecordTrack constructor must be called with AudioFlinger::mLock held @@ -2724,9 +3078,10 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack(              int format,              int channelCount,              int frameCount, -            uint32_t flags) +            uint32_t flags, +            int sessionId)      :   TrackBase(thread, client, sampleRate, format, -                  channelCount, frameCount, flags, 0), +                  channelCount, frameCount, flags, 0, sessionId),          mOverflow(false)  {      if (mCblk != NULL) { @@ -2808,16 +3163,17 @@ void AudioFlinger::RecordThread::RecordTrack::stop()          TrackBase::reset();          // Force overerrun condition to avoid false overrun callback until first data is          // read from buffer -        mCblk->flowControlFlag = 1; +        mCblk->flags |= CBLK_UNDERRUN_ON;      }  }  void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size)  { -    snprintf(buffer, size, "   %05d %03u %03u %04u %01d %05u  %08x %08x\n", +    snprintf(buffer, size, "   %05d %03u %03u %05d   %04u %01d %05u  %08x %08x\n",              (mClient == NULL) ? getpid() : mClient->pid(),              mFormat, -            mCblk->channels, +            mCblk->channelCount, +            mSessionId,              mFrameCount,              mState,              mCblk->sampleRate, @@ -2835,19 +3191,19 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(              int format,              int channelCount,              int frameCount) -    :   Track(thread, NULL, AudioSystem::NUM_STREAM_TYPES, sampleRate, format, channelCount, frameCount, NULL), +    :   Track(thread, NULL, AudioSystem::NUM_STREAM_TYPES, sampleRate, format, channelCount, frameCount, NULL, 0),      mActive(false), mSourceThread(sourceThread)  {      PlaybackThread *playbackThread = (PlaybackThread *)thread.unsafe_get();      if (mCblk != NULL) { -        mCblk->out = 1; +        mCblk->flags |= CBLK_DIRECTION_OUT;          mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);          mCblk->volume[0] = mCblk->volume[1] = 0x1000;          mOutBuffer.frameCount = 0;          playbackThread->mTracks.add(this); -        LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p", -                mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd); +        LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channelCount %d mBufferEnd %p", +                mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channelCount, mBufferEnd);      } else {          LOGW("Error creating output track on thread %p", playbackThread);      } @@ -2882,7 +3238,7 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr  {      Buffer *pInBuffer;      Buffer inBuffer; -    uint32_t channels = mCblk->channels; +    uint32_t channelCount = mCblk->channelCount;      bool outputBufferFull = false;      inBuffer.frameCount = frames;      inBuffer.i16 = data; @@ -2898,10 +3254,10 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr                  if (mBufferQueue.size() < kMaxOverFlowBuffers) {                      uint32_t startFrames = (mCblk->frameCount - frames);                      pInBuffer = new Buffer; -                    pInBuffer->mBuffer = new int16_t[startFrames * channels]; +                    pInBuffer->mBuffer = new int16_t[startFrames * channelCount];                      pInBuffer->frameCount = startFrames;                      pInBuffer->i16 = pInBuffer->mBuffer; -                    memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t)); +                    memset(pInBuffer->raw, 0, startFrames * channelCount * sizeof(int16_t));                      mBufferQueue.add(pInBuffer);                  } else {                      LOGW ("OutputTrack::write() %p no more buffers in queue", this); @@ -2939,12 +3295,12 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr          }          uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount; -        memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channels * sizeof(int16_t)); +        memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channelCount * sizeof(int16_t));          mCblk->stepUser(outFrames);          pInBuffer->frameCount -= outFrames; -        pInBuffer->i16 += outFrames * channels; +        pInBuffer->i16 += outFrames * channelCount;          mOutBuffer.frameCount -= outFrames; -        mOutBuffer.i16 += outFrames * channels; +        mOutBuffer.i16 += outFrames * channelCount;          if (pInBuffer->frameCount == 0) {              if (mBufferQueue.size()) { @@ -2964,10 +3320,10 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr          if (thread != 0 && !thread->standby()) {              if (mBufferQueue.size() < kMaxOverFlowBuffers) {                  pInBuffer = new Buffer; -                pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels]; +                pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channelCount];                  pInBuffer->frameCount = inBuffer.frameCount;                  pInBuffer->i16 = pInBuffer->mBuffer; -                memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t)); +                memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channelCount * sizeof(int16_t));                  mBufferQueue.add(pInBuffer);                  LOGV("OutputTrack::write() %p thread %p adding overflow buffer %d", this, mThread.unsafe_get(), mBufferQueue.size());              } else { @@ -2983,10 +3339,10 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr          if (mCblk->user < mCblk->frameCount) {              frames = mCblk->frameCount - mCblk->user;              pInBuffer = new Buffer; -            pInBuffer->mBuffer = new int16_t[frames * channels]; +            pInBuffer->mBuffer = new int16_t[frames * channelCount];              pInBuffer->frameCount = frames;              pInBuffer->i16 = pInBuffer->mBuffer; -            memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t)); +            memset(pInBuffer->raw, 0, frames * channelCount * sizeof(int16_t));              mBufferQueue.add(pInBuffer);          } else if (mActive) {              stop(); @@ -3086,6 +3442,28 @@ const sp<MemoryDealer>& AudioFlinger::Client::heap() const  // ---------------------------------------------------------------------------- +AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger, +                                                     const sp<IAudioFlingerClient>& client, +                                                     pid_t pid) +    : mAudioFlinger(audioFlinger), mPid(pid), mClient(client) +{ +} + +AudioFlinger::NotificationClient::~NotificationClient() +{ +    mClient.clear(); +} + +void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who) +{ +    sp<NotificationClient> keep(this); +    { +        mAudioFlinger->removeNotificationClient(mPid); +    } +} + +// ---------------------------------------------------------------------------- +  AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::PlaybackThread::Track>& track)      : BnAudioTrack(),        mTrack(track) @@ -3128,6 +3506,11 @@ sp<IMemory> AudioFlinger::TrackHandle::getCblk() const {      return mTrack->getCblk();  } +status_t AudioFlinger::TrackHandle::attachAuxEffect(int EffectId) +{ +    return mTrack->attachAuxEffect(EffectId); +} +  status_t AudioFlinger::TrackHandle::onTransact(      uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  { @@ -3144,6 +3527,7 @@ sp<IAudioRecord> AudioFlinger::openRecord(          int channelCount,          int frameCount,          uint32_t flags, +        int *sessionId,          status_t *status)  {      sp<RecordThread::RecordTrack> recordTrack; @@ -3153,6 +3537,7 @@ sp<IAudioRecord> AudioFlinger::openRecord(      status_t lStatus;      RecordThread *thread;      size_t inFrameCount; +    int lSessionId;      // check calling permissions      if (!recordingAllowed()) { @@ -3177,9 +3562,18 @@ sp<IAudioRecord> AudioFlinger::openRecord(              mClients.add(pid, client);          } +        // If no audio session id is provided, create one here +        if (sessionId != NULL && *sessionId != 0) { +            lSessionId = *sessionId; +        } else { +            lSessionId = nextUniqueId(); +            if (sessionId != NULL) { +                *sessionId = lSessionId; +            } +        }          // create new record track. The record track uses one track in mHardwareMixerThread by convention.          recordTrack = new RecordThread::RecordTrack(thread, client, sampleRate, -                                                   format, channelCount, frameCount, flags); +                                                   format, channelCount, frameCount, flags, lSessionId);      }      if (recordTrack->getCblk() == NULL) {          // remove local strong reference to Client before deleting the RecordTrack so that the Client @@ -3242,7 +3636,6 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, A      mReqChannelCount = AudioSystem::popCount(channels);      mReqSampleRate = sampleRate;      readInputParameters(); -    sendConfigEvent(AudioSystem::INPUT_OPENED);  } @@ -3339,7 +3732,7 @@ bool AudioFlinger::RecordThread::threadLoop()                                  framesIn = framesOut;                              mRsmpInIndex += framesIn;                              framesOut -= framesIn; -                            if (mChannelCount == mReqChannelCount || +                            if ((int)mChannelCount == mReqChannelCount ||                                  mFormat != AudioSystem::PCM_16_BIT) {                                  memcpy(dst, src, framesIn * mFrameSize);                              } else { @@ -3360,7 +3753,7 @@ bool AudioFlinger::RecordThread::threadLoop()                          }                          if (framesOut && mFrameCount == mRsmpInIndex) {                              if (framesOut == mFrameCount && -                                (mChannelCount == mReqChannelCount || mFormat != AudioSystem::PCM_16_BIT)) { +                                ((int)mChannelCount == mReqChannelCount || mFormat != AudioSystem::PCM_16_BIT)) {                                  mBytesRead = mInput->read(buffer.raw, mInputBytes);                                  framesOut = 0;                              } else { @@ -3518,7 +3911,7 @@ status_t AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)      if (mActiveTrack != 0) {          result.append("Active Track:\n"); -        result.append("   Clien Fmt Chn Buf  S SRate  Serv     User\n"); +        result.append("   Clien Fmt Chn Session Buf  S SRate  Serv     User\n");          mActiveTrack->dump(buffer, SIZE);          result.append(buffer); @@ -3657,14 +4050,14 @@ String8 AudioFlinger::RecordThread::getParameters(const String8& keys)      return mInput->getParameters(keys);  } -void AudioFlinger::RecordThread::audioConfigChanged(int event, int param) { +void AudioFlinger::RecordThread::audioConfigChanged_l(int event, int param) {      AudioSystem::OutputDescriptor desc;      void *param2 = 0;      switch (event) {      case AudioSystem::INPUT_OPENED:      case AudioSystem::INPUT_CONFIG_CHANGED: -        desc.channels = mChannelCount; +        desc.channels = mChannels;          desc.samplingRate = mSampleRate;          desc.format = mFormat;          desc.frameCount = mFrameCount; @@ -3676,7 +4069,6 @@ void AudioFlinger::RecordThread::audioConfigChanged(int event, int param) {      default:          break;      } -    Mutex::Autolock _l(mAudioFlinger->mLock);      mAudioFlinger->audioConfigChanged_l(event, mId, param2);  } @@ -3688,9 +4080,10 @@ void AudioFlinger::RecordThread::readInputParameters()      mResampler = 0;      mSampleRate = mInput->sampleRate(); -    mChannelCount = AudioSystem::popCount(mInput->channels()); +    mChannels = mInput->channels(); +    mChannelCount = (uint16_t)AudioSystem::popCount(mChannels);      mFormat = mInput->format(); -    mFrameSize = mInput->frameSize(); +    mFrameSize = (uint16_t)mInput->frameSize();      mInputBytes = mInput->bufferSize();      mFrameCount = mInputBytes / mFrameSize;      mRsmpInBuffer = new int16_t[mFrameCount * mChannelCount]; @@ -3767,14 +4160,15 @@ int AudioFlinger::openOutput(uint32_t *pDevices,      mHardwareStatus = AUDIO_HW_IDLE;      if (output != 0) { +        int id = nextUniqueId();          if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||              (format != AudioSystem::PCM_16_BIT) ||              (channels != AudioSystem::CHANNEL_OUT_STEREO)) { -            thread = new DirectOutputThread(this, output, ++mNextThreadId); -            LOGV("openOutput() created direct output: ID %d thread %p", mNextThreadId, thread); +            thread = new DirectOutputThread(this, output, id, *pDevices); +            LOGV("openOutput() created direct output: ID %d thread %p", id, thread);          } else { -            thread = new MixerThread(this, output, ++mNextThreadId); -            LOGV("openOutput() created mixer output: ID %d thread %p", mNextThreadId, thread); +            thread = new MixerThread(this, output, id, *pDevices); +            LOGV("openOutput() created mixer output: ID %d thread %p", id, thread);  #ifdef LVMX              unsigned bitsPerSample = @@ -3788,14 +4182,16 @@ int AudioFlinger::openOutput(uint32_t *pDevices,  #endif          } -        mPlaybackThreads.add(mNextThreadId, thread); +        mPlaybackThreads.add(id, thread);          if (pSamplingRate) *pSamplingRate = samplingRate;          if (pFormat) *pFormat = format;          if (pChannels) *pChannels = channels;          if (pLatencyMs) *pLatencyMs = thread->latency(); -        return mNextThreadId; +        // notify client processes of the new output creation +        thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED); +        return id;      }      return 0; @@ -3812,11 +4208,13 @@ int AudioFlinger::openDuplicateOutput(int output1, int output2)          return 0;      } - -    DuplicatingThread *thread = new DuplicatingThread(this, thread1, ++mNextThreadId); +    int id = nextUniqueId(); +    DuplicatingThread *thread = new DuplicatingThread(this, thread1, id);      thread->addOutputTrack(thread2); -    mPlaybackThreads.add(mNextThreadId, thread); -    return mNextThreadId; +    mPlaybackThreads.add(id, thread); +    // notify client processes of the new output creation +    thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED); +    return id;  }  status_t AudioFlinger::closeOutput(int output) @@ -3935,17 +4333,20 @@ int AudioFlinger::openInput(uint32_t *pDevices,      }      if (input != 0) { +        int id = nextUniqueId();           // Start record thread -        thread = new RecordThread(this, input, reqSamplingRate, reqChannels, ++mNextThreadId); -        mRecordThreads.add(mNextThreadId, thread); -        LOGV("openInput() created record thread: ID %d thread %p", mNextThreadId, thread); +        thread = new RecordThread(this, input, reqSamplingRate, reqChannels, id); +        mRecordThreads.add(id, thread); +        LOGV("openInput() created record thread: ID %d thread %p", id, thread);          if (pSamplingRate) *pSamplingRate = reqSamplingRate;          if (pFormat) *pFormat = format;          if (pChannels) *pChannels = reqChannels;          input->standby(); -        return mNextThreadId; +        // notify client processes of the new input creation +        thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED); +        return id;      }      return 0; @@ -3985,26 +4386,26 @@ status_t AudioFlinger::setStreamOutput(uint32_t stream, int output)      }      LOGV("setStreamOutput() stream %d to output %d", stream, output); +    audioConfigChanged_l(AudioSystem::STREAM_CONFIG_CHANGED, output, &stream);      for (size_t i = 0; i < mPlaybackThreads.size(); i++) {          PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();          if (thread != dstThread &&              thread->type() != PlaybackThread::DIRECT) {              MixerThread *srcThread = (MixerThread *)thread; -            SortedVector < sp<MixerThread::Track> > tracks; -            SortedVector < wp<MixerThread::Track> > activeTracks; -            srcThread->getTracks(tracks, activeTracks, stream); -            if (tracks.size()) { -                dstThread->putTracks(tracks, activeTracks); +            srcThread->invalidateTracks(stream);              }          } -    } - -    dstThread->sendConfigEvent(AudioSystem::STREAM_CONFIG_CHANGED, stream);      return NO_ERROR;  } + +int AudioFlinger::newAudioSessionId() +{ +    return nextUniqueId(); +} +  // checkPlaybackThread_l() must be called with AudioFlinger::mLock held  AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const  { @@ -4037,6 +4438,1475 @@ AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(int input) const      return thread;  } +int AudioFlinger::nextUniqueId() +{ +    return android_atomic_inc(&mNextUniqueId); +} + +// ---------------------------------------------------------------------------- +//  Effect management +// ---------------------------------------------------------------------------- + + +status_t AudioFlinger::loadEffectLibrary(const char *libPath, int *handle) +{ +    Mutex::Autolock _l(mLock); +    return EffectLoadLibrary(libPath, handle); +} + +status_t AudioFlinger::unloadEffectLibrary(int handle) +{ +    Mutex::Autolock _l(mLock); +    return EffectUnloadLibrary(handle); +} + +status_t AudioFlinger::queryNumberEffects(uint32_t *numEffects) +{ +    Mutex::Autolock _l(mLock); +    return EffectQueryNumberEffects(numEffects); +} + +status_t AudioFlinger::queryNextEffect(effect_descriptor_t *descriptor) +{ +    Mutex::Autolock _l(mLock); +    return EffectQueryNext(descriptor); +} + +status_t AudioFlinger::getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor) +{ +    Mutex::Autolock _l(mLock); +    return EffectGetDescriptor(pUuid, descriptor); +} + +sp<IEffect> AudioFlinger::createEffect(pid_t pid, +        effect_descriptor_t *pDesc, +        const sp<IEffectClient>& effectClient, +        int32_t priority, +        int output, +        int sessionId, +        status_t *status, +        int *id, +        int *enabled) +{ +    status_t lStatus = NO_ERROR; +    sp<EffectHandle> handle; +    effect_interface_t itfe; +    effect_descriptor_t desc; +    sp<Client> client; +    wp<Client> wclient; + +    LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, output %d", pid, effectClient.get(), priority, sessionId, output); + +    if (pDesc == NULL) { +        lStatus = BAD_VALUE; +        goto Exit; +    } + +    { +        Mutex::Autolock _l(mLock); + +        if (!EffectIsNullUuid(&pDesc->uuid)) { +            // if uuid is specified, request effect descriptor +            lStatus = EffectGetDescriptor(&pDesc->uuid, &desc); +            if (lStatus < 0) { +                LOGW("createEffect() error %d from EffectGetDescriptor", lStatus); +                goto Exit; +            } +        } else { +            // if uuid is not specified, look for an available implementation +            // of the required type in effect factory +            if (EffectIsNullUuid(&pDesc->type)) { +                LOGW("createEffect() no effect type"); +                lStatus = BAD_VALUE; +                goto Exit; +            } +            uint32_t numEffects = 0; +            effect_descriptor_t d; +            bool found = false; + +            lStatus = EffectQueryNumberEffects(&numEffects); +            if (lStatus < 0) { +                LOGW("createEffect() error %d from EffectQueryNumberEffects", lStatus); +                goto Exit; +            } +            for (; numEffects > 0; numEffects--) { +                lStatus = EffectQueryNext(&desc); +                if (lStatus < 0) { +                    LOGW("createEffect() error %d from EffectQueryNext", lStatus); +                    continue; +                } +                if (memcmp(&desc.type, &pDesc->type, sizeof(effect_uuid_t)) == 0) { +                    // If matching type found save effect descriptor. If the session is +                    // 0 and the effect is not auxiliary, continue enumeration in case +                    // an auxiliary version of this effect type is available +                    found = true; +                    memcpy(&d, &desc, sizeof(effect_descriptor_t)); +                    if (sessionId != 0 || +                            (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { +                        break; +                    } +                } +            } +            if (!found) { +                lStatus = BAD_VALUE; +                LOGW("createEffect() effect not found"); +                goto Exit; +            } +            // For same effect type, chose auxiliary version over insert version if +            // connect to output mix (Compliance to OpenSL ES) +            if (sessionId == 0 && +                    (d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) { +                memcpy(&desc, &d, sizeof(effect_descriptor_t)); +            } +        } + +        // Do not allow auxiliary effects on a session different from 0 (output mix) +        if (sessionId != 0 && +             (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { +            lStatus = INVALID_OPERATION; +            goto Exit; +        } + +        // return effect descriptor +        memcpy(pDesc, &desc, sizeof(effect_descriptor_t)); + +        // If output is not specified try to find a matching audio session ID in one of the +        // output threads. +        // TODO: allow attachment of effect to inputs +        if (output == 0) { +            if (sessionId == 0) { +                // default to first output +                // TODO: define criteria to choose output when not specified. Or +                // receive output from audio policy manager +                if (mPlaybackThreads.size() != 0) { +                    output = mPlaybackThreads.keyAt(0); +                } +            } else { +                 // look for the thread where the specified audio session is present +                for (size_t i = 0; i < mPlaybackThreads.size(); i++) { +                    if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId)) { +                        output = mPlaybackThreads.keyAt(i); +                        break; +                    } +                } +            } +        } +        PlaybackThread *thread = checkPlaybackThread_l(output); +        if (thread == NULL) { +            LOGE("unknown output thread"); +            lStatus = BAD_VALUE; +            goto Exit; +        } + +        wclient = mClients.valueFor(pid); + +        if (wclient != NULL) { +            client = wclient.promote(); +        } else { +            client = new Client(this, pid); +            mClients.add(pid, client); +        } + +        // create effect on selected output trhead +        handle = thread->createEffect_l(client, effectClient, priority, sessionId, &desc, enabled, &lStatus); +        if (handle != 0 && id != NULL) { +            *id = handle->id(); +        } +    } + +Exit: +    if(status) { +        *status = lStatus; +    } +    return handle; +} + +// PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held +sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( +        const sp<AudioFlinger::Client>& client, +        const sp<IEffectClient>& effectClient, +        int32_t priority, +        int sessionId, +        effect_descriptor_t *desc, +        int *enabled, +        status_t *status +        ) +{ +    sp<EffectModule> effect; +    sp<EffectHandle> handle; +    status_t lStatus; +    sp<Track> track; +    sp<EffectChain> chain; +    bool effectCreated = false; + +    if (mOutput == 0) { +        LOGW("createEffect_l() Audio driver not initialized."); +        lStatus = NO_INIT; +        goto Exit; +    } + +    // Do not allow auxiliary effect on session other than 0 +    if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY && +        sessionId != 0) { +        LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId); +        lStatus = BAD_VALUE; +        goto Exit; +    } + +    // Do not allow effects with session ID 0 on direct output or duplicating threads +    // TODO: add rule for hw accelerated effects on direct outputs with non PCM format +    if (sessionId == 0 && mType != MIXER) { +        LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId); +        lStatus = BAD_VALUE; +        goto Exit; +    } + +    LOGV("createEffect_l() thread %p effect %s on session %d", this, desc->name, sessionId); + +    { // scope for mLock +        Mutex::Autolock _l(mLock); + +        // check for existing effect chain with the requested audio session +        chain = getEffectChain_l(sessionId); +        if (chain == 0) { +            // create a new chain for this session +            LOGV("createEffect_l() new effect chain for session %d", sessionId); +            chain = new EffectChain(this, sessionId); +            addEffectChain_l(chain); +        } else { +            effect = chain->getEffectFromDesc(desc); +        } + +        LOGV("createEffect_l() got effect %p on chain %p", effect == 0 ? 0 : effect.get(), chain.get()); + +        if (effect == 0) { +            // create a new effect module if none present in the chain +            effectCreated = true; +            effect = new EffectModule(this, chain, desc, mAudioFlinger->nextUniqueId(), sessionId); +            lStatus = effect->status(); +            if (lStatus != NO_ERROR) { +                goto Exit; +            } +            //TODO: handle CPU load and memory usage here +            lStatus = chain->addEffect(effect); +            if (lStatus != NO_ERROR) { +                goto Exit; +            } + +            effect->setDevice(mDevice); +        } +        // create effect handle and connect it to effect module +        handle = new EffectHandle(effect, client, effectClient, priority); +        lStatus = effect->addHandle(handle); +        if (enabled) { +            *enabled = (int)effect->isEnabled(); +        } +    } + +Exit: +    if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) { +        if (chain != 0 && effectCreated) { +            if (chain->removeEffect(effect) == 0) { +                removeEffectChain_l(chain); +            } +        } +        handle.clear(); +    } + +    if(status) { +        *status = lStatus; +    } +    return handle; +} + +status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain) +{ +    int session = chain->sessionId(); +    int16_t *buffer = mMixBuffer; + +    LOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session); +    if (session == 0) { +        chain->setInBuffer(buffer, false); +        chain->setOutBuffer(buffer); +        // Effect chain for session 0 is inserted at end of effect chains list +        // to be processed last as it contains output mix effects to apply after +        // all track specific effects +        mEffectChains.add(chain); +    } else { +        bool ownsBuffer = false; +        // Only one effect chain can be present in direct output thread and it uses +        // the mix buffer as input +        if (mType != DIRECT) { +            size_t numSamples = mFrameCount * mChannelCount; +            buffer = new int16_t[numSamples]; +            memset(buffer, 0, numSamples * sizeof(int16_t)); +            LOGV("addEffectChain_l() creating new input buffer %p session %d", buffer, session); +            ownsBuffer = true; +        } +        chain->setInBuffer(buffer, ownsBuffer); +        chain->setOutBuffer(mMixBuffer); +        // Effect chain for session other than 0 is inserted at beginning of effect +        // chains list to be processed before output mix effects. Relative order between +        // sessions other than 0 is not important +        mEffectChains.insertAt(chain, 0); +    } + +    // Attach all tracks with same session ID to this chain. +    for (size_t i = 0; i < mTracks.size(); ++i) { +        sp<Track> track = mTracks[i]; +        if (session == track->sessionId()) { +            LOGV("addEffectChain_l() track->setMainBuffer track %p buffer %p", track.get(), buffer); +            track->setMainBuffer(buffer); +        } +    } + +    // indicate all active tracks in the chain +    for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) { +        sp<Track> track = mActiveTracks[i].promote(); +        if (track == 0) continue; +        if (session == track->sessionId()) { +            LOGV("addEffectChain_l() activating track %p on session %d", track.get(), session); +            chain->startTrack(); +        } +    } + +    return NO_ERROR; +} + +size_t AudioFlinger::PlaybackThread::removeEffectChain_l(const sp<EffectChain>& chain) +{ +    int session = chain->sessionId(); + +    LOGV("removeEffectChain_l() %p from thread %p for session %d", chain.get(), this, session); + +    for (size_t i = 0; i < mEffectChains.size(); i++) { +        if (chain == mEffectChains[i]) { +            mEffectChains.removeAt(i); +            // detach all tracks with same session ID from this chain +            for (size_t i = 0; i < mTracks.size(); ++i) { +                sp<Track> track = mTracks[i]; +                if (session == track->sessionId()) { +                    track->setMainBuffer(mMixBuffer); +                } +            } +        } +    } +    return mEffectChains.size(); +} + +void AudioFlinger::PlaybackThread::lockEffectChains_l() +{ +    for (size_t i = 0; i < mEffectChains.size(); i++) { +        mEffectChains[i]->lock(); +    } +} + +void AudioFlinger::PlaybackThread::unlockEffectChains() +{ +    Mutex::Autolock _l(mLock); +    for (size_t i = 0; i < mEffectChains.size(); i++) { +        mEffectChains[i]->unlock(); +    } +} + +sp<AudioFlinger::EffectModule> AudioFlinger::PlaybackThread::getEffect_l(int sessionId, int effectId) +{ +    sp<EffectModule> effect; + +    sp<EffectChain> chain = getEffectChain_l(sessionId); +    if (chain != 0) { +        effect = chain->getEffectFromId(effectId); +    } +    return effect; +} + +status_t AudioFlinger::PlaybackThread::attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId) +{ +    Mutex::Autolock _l(mLock); +    return attachAuxEffect_l(track, EffectId); +} + +status_t AudioFlinger::PlaybackThread::attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId) +{ +    status_t status = NO_ERROR; + +    if (EffectId == 0) { +        track->setAuxBuffer(0, NULL); +    } else { +        // Auxiliary effects are always in audio session 0 +        sp<EffectModule> effect = getEffect_l(0, EffectId); +        if (effect != 0) { +            if ((effect->desc().flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { +                track->setAuxBuffer(EffectId, (int32_t *)effect->inBuffer()); +            } else { +                status = INVALID_OPERATION; +            } +        } else { +            status = BAD_VALUE; +        } +    } +    return status; +} + +void AudioFlinger::PlaybackThread::detachAuxEffect_l(int effectId) +{ +     for (size_t i = 0; i < mTracks.size(); ++i) { +        sp<Track> track = mTracks[i]; +        if (track->auxEffectId() == effectId) { +            attachAuxEffect_l(track, 0); +        } +    } +} + +// ---------------------------------------------------------------------------- +//  EffectModule implementation +// ---------------------------------------------------------------------------- + +#undef LOG_TAG +#define LOG_TAG "AudioFlinger::EffectModule" + +AudioFlinger::EffectModule::EffectModule(const wp<ThreadBase>& wThread, +                                        const wp<AudioFlinger::EffectChain>& chain, +                                        effect_descriptor_t *desc, +                                        int id, +                                        int sessionId) +    : mThread(wThread), mChain(chain), mId(id), mSessionId(sessionId), mEffectInterface(NULL), +      mStatus(NO_INIT), mState(IDLE) +{ +    LOGV("Constructor %p", this); +    int lStatus; +    sp<ThreadBase> thread = mThread.promote(); +    if (thread == 0) { +        return; +    } +    PlaybackThread *p = (PlaybackThread *)thread.get(); + +    memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t)); + +    // create effect engine from effect factory +    mStatus = EffectCreate(&desc->uuid, &mEffectInterface); +    if (mStatus != NO_ERROR) { +        return; +    } +    lStatus = init(); +    if (lStatus < 0) { +        mStatus = lStatus; +        goto Error; +    } + +    LOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface); +    return; +Error: +    EffectRelease(mEffectInterface); +    mEffectInterface = NULL; +    LOGV("Constructor Error %d", mStatus); +} + +AudioFlinger::EffectModule::~EffectModule() +{ +    LOGV("Destructor %p", this); +    if (mEffectInterface != NULL) { +        // release effect engine +        EffectRelease(mEffectInterface); +    } +} + +status_t AudioFlinger::EffectModule::addHandle(sp<EffectHandle>& handle) +{ +    status_t status; + +    Mutex::Autolock _l(mLock); +    // First handle in mHandles has highest priority and controls the effect module +    int priority = handle->priority(); +    size_t size = mHandles.size(); +    sp<EffectHandle> h; +    size_t i; +    for (i = 0; i < size; i++) { +        h = mHandles[i].promote(); +        if (h == 0) continue; +        if (h->priority() <= priority) break; +    } +    // if inserted in first place, move effect control from previous owner to this handle +    if (i == 0) { +        if (h != 0) { +            h->setControl(false, true); +        } +        handle->setControl(true, false); +        status = NO_ERROR; +    } else { +        status = ALREADY_EXISTS; +    } +    mHandles.insertAt(handle, i); +    return status; +} + +size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle) +{ +    Mutex::Autolock _l(mLock); +    size_t size = mHandles.size(); +    size_t i; +    for (i = 0; i < size; i++) { +        if (mHandles[i] == handle) break; +    } +    if (i == size) { +        return size; +    } +    mHandles.removeAt(i); +    size = mHandles.size(); +    // if removed from first place, move effect control from this handle to next in line +    if (i == 0 && size != 0) { +        sp<EffectHandle> h = mHandles[0].promote(); +        if (h != 0) { +            h->setControl(true, true); +        } +    } + +    return size; +} + +void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle) +{ +    // keep a strong reference on this EffectModule to avoid calling the +    // destructor before we exit +    sp<EffectModule> keep(this); +    sp<ThreadBase> thread = mThread.promote(); +    if (thread != 0) { +        Mutex::Autolock _l(thread->mLock); +        // delete the effect module if removing last handle on it +        if (removeHandle(handle) == 0) { +            PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); +            if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { +                playbackThread->detachAuxEffect_l(mId); +            } +            sp<EffectChain> chain = mChain.promote(); +            if (chain != 0) { +                // remove effect chain if remove last effect +                if (chain->removeEffect(keep) == 0) { +                    playbackThread->removeEffectChain_l(chain); +                } +            } +        } +    } +} + +void AudioFlinger::EffectModule::process() +{ +    Mutex::Autolock _l(mLock); + +    if (mEffectInterface == NULL || mConfig.inputCfg.buffer.raw == NULL || mConfig.outputCfg.buffer.raw == NULL) { +        return; +    } + +    if (mState != IDLE) { +        // do 32 bit to 16 bit conversion for auxiliary effect input buffer +        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { +            AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32, +                                        mConfig.inputCfg.buffer.s32, +                                        mConfig.inputCfg.buffer.frameCount); +        } + +        // TODO: handle effects with buffer provider +        if (mState != ACTIVE) { +            uint32_t count = mConfig.inputCfg.buffer.frameCount; +            int32_t amp = 32767L << 16; +            int32_t step = amp / count; +            int16_t *pIn = mConfig.inputCfg.buffer.s16; +            int16_t *pOut = mConfig.outputCfg.buffer.s16; +            int inChannels; +            int outChannels; + +            if (mConfig.inputCfg.channels == CHANNEL_MONO) { +                inChannels = 1; +            } else { +                inChannels = 2; +            } +            if (mConfig.outputCfg.channels == CHANNEL_MONO) { +                outChannels = 1; +            } else { +                outChannels = 2; +            } + +            switch (mState) { +            case RESET: +                reset(); +                // clear auxiliary effect input buffer for next accumulation +                if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { +                    memset(mConfig.inputCfg.buffer.raw, 0, mConfig.inputCfg.buffer.frameCount*sizeof(int32_t)); +                } +                step = -step; +                mState = STARTING; +                break; +            case STARTING: +                start(); +                amp = 0; +                pOut = mConfig.inputCfg.buffer.s16; +                outChannels = inChannels; +                mState = ACTIVE; +                break; +            case STOPPING: +                step = -step; +                pOut = mConfig.inputCfg.buffer.s16; +                outChannels = inChannels; +                mState = STOPPED; +                break; +            case STOPPED: +                stop(); +                amp = 0; +                mState = IDLE; +                break; +            } + +            // ramp volume down or up before activating or deactivating the effect +            if (inChannels == 1) { +                if (outChannels == 1) { +                    while (count--) { +                        *pOut++ = (int16_t)(((int32_t)*pIn++ * (amp >> 16)) >> 15); +                        amp += step; +                    } +                } else { +                    while (count--) { +                        int32_t smp = (int16_t)(((int32_t)*pIn++ * (amp >> 16)) >> 15); +                        *pOut++ = smp; +                        *pOut++ = smp; +                        amp += step; +                    } +                } +            } else { +                if (outChannels == 1) { +                    while (count--) { +                        int32_t smp = (((int32_t)*pIn * (amp >> 16)) >> 16) + +                                      (((int32_t)*(pIn + 1) * (amp >> 16)) >> 16); +                        pIn += 2; +                        *pOut++ = (int16_t)smp; +                        amp += step; +                    } +                } else { +                    while (count--) { +                        *pOut++ = (int16_t)((int32_t)*pIn++ * (amp >> 16)) >> 15; +                        *pOut++ = (int16_t)((int32_t)*pIn++ * (amp >> 16)) >> 15; +                         amp += step; +                    } +                } +            } +            if (mState == STARTING || mState == IDLE) { +                return; +            } +        } + +        // do the actual processing in the effect engine +        (*mEffectInterface)->process(mEffectInterface, &mConfig.inputCfg.buffer, &mConfig.outputCfg.buffer); + +        // clear auxiliary effect input buffer for next accumulation +        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { +            memset(mConfig.inputCfg.buffer.raw, 0, mConfig.inputCfg.buffer.frameCount*sizeof(int32_t)); +        } +    } else if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT && +                mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw){ +        // If an insert effect is idle and input buffer is different from output buffer, copy input to +        // output +        sp<EffectChain> chain = mChain.promote(); +        if (chain != 0 && chain->activeTracks() != 0) { +            size_t size = mConfig.inputCfg.buffer.frameCount * sizeof(int16_t); +            if (mConfig.inputCfg.channels == CHANNEL_STEREO) { +                size *= 2; +            } +            memcpy(mConfig.outputCfg.buffer.raw, mConfig.inputCfg.buffer.raw, size); +        } +    } +} + +void AudioFlinger::EffectModule::reset() +{ +    if (mEffectInterface == NULL) { +        return; +    } +    (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_RESET, 0, NULL, 0, NULL); +} + +status_t AudioFlinger::EffectModule::configure() +{ +    uint32_t channels; +    if (mEffectInterface == NULL) { +        return NO_INIT; +    } + +    sp<ThreadBase> thread = mThread.promote(); +    if (thread == 0) { +        return DEAD_OBJECT; +    } + +    // TODO: handle configuration of effects replacing track process +    if (thread->channelCount() == 1) { +        channels = CHANNEL_MONO; +    } else { +        channels = CHANNEL_STEREO; +    } + +    if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { +        mConfig.inputCfg.channels = CHANNEL_MONO; +    } else { +        mConfig.inputCfg.channels = channels; +    } +    mConfig.outputCfg.channels = channels; +    mConfig.inputCfg.format = PCM_FORMAT_S15; +    mConfig.outputCfg.format = PCM_FORMAT_S15; +    mConfig.inputCfg.samplingRate = thread->sampleRate(); +    mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate; +    mConfig.inputCfg.bufferProvider.cookie = NULL; +    mConfig.inputCfg.bufferProvider.getBuffer = NULL; +    mConfig.inputCfg.bufferProvider.releaseBuffer = NULL; +    mConfig.outputCfg.bufferProvider.cookie = NULL; +    mConfig.outputCfg.bufferProvider.getBuffer = NULL; +    mConfig.outputCfg.bufferProvider.releaseBuffer = NULL; +    mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; +    // Insert effect: +    // - in session 0, always overwrites output buffer: input buffer == output buffer +    // - in other sessions: +    //      last effect in the chain accumulates in output buffer: input buffer != output buffer +    //      other effect: overwrites output buffer: input buffer == output buffer +    // Auxiliary effect: +    //      accumulates in output buffer: input buffer != output buffer +    // Therefore: accumulate <=> input buffer != output buffer +    if (mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) { +        mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; +    } else { +        mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE; +    } +    mConfig.inputCfg.mask = EFFECT_CONFIG_ALL; +    mConfig.outputCfg.mask = EFFECT_CONFIG_ALL; +    mConfig.inputCfg.buffer.frameCount = thread->frameCount(); +    mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount; + +    status_t cmdStatus; +    int size = sizeof(int); +    status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_CONFIGURE, sizeof(effect_config_t), &mConfig, &size, &cmdStatus); +    if (status == 0) { +        status = cmdStatus; +    } +    return status; +} + +status_t AudioFlinger::EffectModule::init() +{ +    if (mEffectInterface == NULL) { +        return NO_INIT; +    } +    status_t cmdStatus; +    int size = sizeof(status_t); +    status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_INIT, 0, NULL, &size, &cmdStatus); +    if (status == 0) { +        status = cmdStatus; +    } +    return status; +} + +status_t AudioFlinger::EffectModule::start() +{ +    if (mEffectInterface == NULL) { +        return NO_INIT; +    } +    status_t cmdStatus; +    int size = sizeof(status_t); +    status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_ENABLE, 0, NULL, &size, &cmdStatus); +    if (status == 0) { +        status = cmdStatus; +    } +    return status; +} + +status_t AudioFlinger::EffectModule::stop() +{ +    if (mEffectInterface == NULL) { +        return NO_INIT; +    } +    status_t cmdStatus; +    int size = sizeof(status_t); +    status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_DISABLE, 0, NULL, &size, &cmdStatus); +    if (status == 0) { +        status = cmdStatus; +    } +    return status; +} + +status_t AudioFlinger::EffectModule::command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData) +{ +    LOGV("command(), cmdCode: %d, mEffectInterface: %p", cmdCode, mEffectInterface); + +    if (mEffectInterface == NULL) { +        return NO_INIT; +    } +    status_t status = (*mEffectInterface)->command(mEffectInterface, cmdCode, cmdSize, pCmdData, replySize, pReplyData); +    if (cmdCode != EFFECT_CMD_GET_PARAM && status == NO_ERROR) { +        int size = (replySize == NULL) ? 0 : *replySize; +        Mutex::Autolock _l(mLock); +        for (size_t i = 1; i < mHandles.size(); i++) { +            sp<EffectHandle> h = mHandles[i].promote(); +            if (h != 0) { +                h->commandExecuted(cmdCode, cmdSize, pCmdData, size, pReplyData); +            } +        } +    } +    return status; +} + +status_t AudioFlinger::EffectModule::setEnabled(bool enabled) +{ +    Mutex::Autolock _l(mLock); +    LOGV("setEnabled %p enabled %d", this, enabled); + +    if (enabled != isEnabled()) { +        switch (mState) { +        // going from disabled to enabled +        case IDLE: +            mState = RESET; +            break; +        case STOPPING: +            mState = ACTIVE; +            break; +        case STOPPED: +            mState = STARTING; +            break; + +        // going from enabled to disabled +        case RESET: +            mState = IDLE; +            break; +        case STARTING: +            mState = STOPPED; +            break; +        case ACTIVE: +            mState = STOPPING; +            break; +        } +        for (size_t i = 1; i < mHandles.size(); i++) { +            sp<EffectHandle> h = mHandles[i].promote(); +            if (h != 0) { +                h->setEnabled(enabled); +            } +        } +    } +    return NO_ERROR; +} + +bool AudioFlinger::EffectModule::isEnabled() +{ +    switch (mState) { +    case RESET: +    case STARTING: +    case ACTIVE: +        return true; +    case IDLE: +    case STOPPING: +    case STOPPED: +    default: +        return false; +    } +} + +status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller) +{ +    status_t status = NO_ERROR; + +    // Send volume indication if EFFECT_FLAG_VOLUME_IND is set and read back altered volume +    // if controller flag is set (Note that controller == TRUE => EFFECT_FLAG_VOLUME_CTRL set) +    if ((mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) & (EFFECT_FLAG_VOLUME_CTRL|EFFECT_FLAG_VOLUME_IND)) { +        status_t cmdStatus; +        uint32_t volume[2]; +        uint32_t *pVolume = NULL; +        int size = sizeof(volume); +        volume[0] = *left; +        volume[1] = *right; +        if (controller) { +            pVolume = volume; +        } +        status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_VOLUME, size, volume, &size, pVolume); +        if (controller && status == NO_ERROR && size == sizeof(volume)) { +            *left = volume[0]; +            *right = volume[1]; +        } +    } +    return status; +} + +status_t AudioFlinger::EffectModule::setDevice(uint32_t device) +{ +    status_t status = NO_ERROR; +    if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_MASK) { +        status_t cmdStatus; +        int size = sizeof(status_t); +        status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_DEVICE, sizeof(uint32_t), &device, &size, &cmdStatus); +        if (status == NO_ERROR) { +            status = cmdStatus; +        } +    } +    return status; +} + + +status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args) +{ +    const size_t SIZE = 256; +    char buffer[SIZE]; +    String8 result; + +    snprintf(buffer, SIZE, "\tEffect ID %d:\n", mId); +    result.append(buffer); + +    bool locked = tryLock(mLock); +    // failed to lock - AudioFlinger is probably deadlocked +    if (!locked) { +        result.append("\t\tCould not lock Fx mutex:\n"); +    } + +    result.append("\t\tSession Status State Engine:\n"); +    snprintf(buffer, SIZE, "\t\t%05d   %03d    %03d   0x%08x\n", +            mSessionId, mStatus, mState, (uint32_t)mEffectInterface); +    result.append(buffer); + +    result.append("\t\tDescriptor:\n"); +    snprintf(buffer, SIZE, "\t\t- UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n", +            mDescriptor.uuid.timeLow, mDescriptor.uuid.timeMid, mDescriptor.uuid.timeHiAndVersion, +            mDescriptor.uuid.clockSeq, mDescriptor.uuid.node[0], mDescriptor.uuid.node[1],mDescriptor.uuid.node[2], +            mDescriptor.uuid.node[3],mDescriptor.uuid.node[4],mDescriptor.uuid.node[5]); +    result.append(buffer); +    snprintf(buffer, SIZE, "\t\t- TYPE: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n", +                mDescriptor.type.timeLow, mDescriptor.type.timeMid, mDescriptor.type.timeHiAndVersion, +                mDescriptor.type.clockSeq, mDescriptor.type.node[0], mDescriptor.type.node[1],mDescriptor.type.node[2], +                mDescriptor.type.node[3],mDescriptor.type.node[4],mDescriptor.type.node[5]); +    result.append(buffer); +    snprintf(buffer, SIZE, "\t\t- apiVersion: %04X\n\t\t- flags: %08X\n", +            mDescriptor.apiVersion, +            mDescriptor.flags); +    result.append(buffer); +    snprintf(buffer, SIZE, "\t\t- name: %s\n", +            mDescriptor.name); +    result.append(buffer); +    snprintf(buffer, SIZE, "\t\t- implementor: %s\n", +            mDescriptor.implementor); +    result.append(buffer); + +    result.append("\t\t- Input configuration:\n"); +    result.append("\t\t\tBuffer     Frames  Smp rate Channels Format\n"); +    snprintf(buffer, SIZE, "\t\t\t0x%08x %05d   %05d    %08x %d\n", +            (uint32_t)mConfig.inputCfg.buffer.raw, +            mConfig.inputCfg.buffer.frameCount, +            mConfig.inputCfg.samplingRate, +            mConfig.inputCfg.channels, +            mConfig.inputCfg.format); +    result.append(buffer); + +    result.append("\t\t- Output configuration:\n"); +    result.append("\t\t\tBuffer     Frames  Smp rate Channels Format\n"); +    snprintf(buffer, SIZE, "\t\t\t0x%08x %05d   %05d    %08x %d\n", +            (uint32_t)mConfig.outputCfg.buffer.raw, +            mConfig.outputCfg.buffer.frameCount, +            mConfig.outputCfg.samplingRate, +            mConfig.outputCfg.channels, +            mConfig.outputCfg.format); +    result.append(buffer); + +    snprintf(buffer, SIZE, "\t\t%d Clients:\n", mHandles.size()); +    result.append(buffer); +    result.append("\t\t\tPid   Priority Ctrl Locked client server\n"); +    for (size_t i = 0; i < mHandles.size(); ++i) { +        sp<EffectHandle> handle = mHandles[i].promote(); +        if (handle != 0) { +            handle->dump(buffer, SIZE); +            result.append(buffer); +        } +    } + +    result.append("\n"); + +    write(fd, result.string(), result.length()); + +    if (locked) { +        mLock.unlock(); +    } + +    return NO_ERROR; +} + +// ---------------------------------------------------------------------------- +//  EffectHandle implementation +// ---------------------------------------------------------------------------- + +#undef LOG_TAG +#define LOG_TAG "AudioFlinger::EffectHandle" + +AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect, +                                        const sp<AudioFlinger::Client>& client, +                                        const sp<IEffectClient>& effectClient, +                                        int32_t priority) +    : BnEffect(), +    mEffect(effect), mEffectClient(effectClient), mClient(client), mPriority(priority), mHasControl(false) +{ +    LOGV("constructor %p", this); + +    int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int); +    mCblkMemory = client->heap()->allocate(EFFECT_PARAM_BUFFER_SIZE + bufOffset); +    if (mCblkMemory != 0) { +        mCblk = static_cast<effect_param_cblk_t *>(mCblkMemory->pointer()); + +        if (mCblk) { +            new(mCblk) effect_param_cblk_t(); +            mBuffer = (uint8_t *)mCblk + bufOffset; +         } +    } else { +        LOGE("not enough memory for Effect size=%u", EFFECT_PARAM_BUFFER_SIZE + sizeof(effect_param_cblk_t)); +        return; +    } +} + +AudioFlinger::EffectHandle::~EffectHandle() +{ +    LOGV("Destructor %p", this); +    disconnect(); +} + +status_t AudioFlinger::EffectHandle::enable() +{ +    if (!mHasControl) return INVALID_OPERATION; +    if (mEffect == 0) return DEAD_OBJECT; + +    return mEffect->setEnabled(true); +} + +status_t AudioFlinger::EffectHandle::disable() +{ +    if (!mHasControl) return INVALID_OPERATION; +    if (mEffect == NULL) return DEAD_OBJECT; + +    return mEffect->setEnabled(false); +} + +void AudioFlinger::EffectHandle::disconnect() +{ +    if (mEffect == 0) { +        return; +    } +    mEffect->disconnect(this); +    // release sp on module => module destructor can be called now +    mEffect.clear(); +    if (mCblk) { +        mCblk->~effect_param_cblk_t();   // destroy our shared-structure. +    } +    mCblkMemory.clear();            // and free the shared memory +    if (mClient != 0) { +        Mutex::Autolock _l(mClient->audioFlinger()->mLock); +        mClient.clear(); +    } +} + +status_t AudioFlinger::EffectHandle::command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData) +{ +    LOGV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p", cmdCode, mHasControl, (mEffect == 0) ? 0 : mEffect.get()); + +    // only get parameter command is permitted for applications not controlling the effect +    if (!mHasControl && cmdCode != EFFECT_CMD_GET_PARAM) { +        return INVALID_OPERATION; +    } +    if (mEffect == 0) return DEAD_OBJECT; + +    // handle commands that are not forwarded transparently to effect engine +    if (cmdCode == EFFECT_CMD_SET_PARAM_COMMIT) { +        // No need to trylock() here as this function is executed in the binder thread serving a particular client process: +        // no risk to block the whole media server process or mixer threads is we are stuck here +        Mutex::Autolock _l(mCblk->lock); +        if (mCblk->clientIndex > EFFECT_PARAM_BUFFER_SIZE || +            mCblk->serverIndex > EFFECT_PARAM_BUFFER_SIZE) { +            mCblk->serverIndex = 0; +            mCblk->clientIndex = 0; +            return BAD_VALUE; +        } +        status_t status = NO_ERROR; +        while (mCblk->serverIndex < mCblk->clientIndex) { +            int reply; +            int rsize = sizeof(int); +            int *p = (int *)(mBuffer + mCblk->serverIndex); +            int size = *p++; +            effect_param_t *param = (effect_param_t *)p; +            int psize = sizeof(effect_param_t) + ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize; +            status_t ret = mEffect->command(EFFECT_CMD_SET_PARAM, psize, p, &rsize, &reply); +            if (ret == NO_ERROR) { +                if (reply != NO_ERROR) { +                    status = reply; +                } +            } else { +                status = ret; +            } +            mCblk->serverIndex += size; +        } +        mCblk->serverIndex = 0; +        mCblk->clientIndex = 0; +        return status; +    } else if (cmdCode == EFFECT_CMD_ENABLE) { +        return enable(); +    } else if (cmdCode == EFFECT_CMD_DISABLE) { +        return disable(); +    } + +    return mEffect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData); +} + +sp<IMemory> AudioFlinger::EffectHandle::getCblk() const { +    return mCblkMemory; +} + +void AudioFlinger::EffectHandle::setControl(bool hasControl, bool signal) +{ +    LOGV("setControl %p control %d", this, hasControl); + +    mHasControl = hasControl; +    if (signal && mEffectClient != 0) { +        mEffectClient->controlStatusChanged(hasControl); +    } +} + +void AudioFlinger::EffectHandle::commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData) +{ +    if (mEffectClient != 0) { +        mEffectClient->commandExecuted(cmdCode, cmdSize, pCmdData, replySize, pReplyData); +    } +} + + + +void AudioFlinger::EffectHandle::setEnabled(bool enabled) +{ +    if (mEffectClient != 0) { +        mEffectClient->enableStatusChanged(enabled); +    } +} + +status_t AudioFlinger::EffectHandle::onTransact( +    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ +    return BnEffect::onTransact(code, data, reply, flags); +} + + +void AudioFlinger::EffectHandle::dump(char* buffer, size_t size) +{ +    bool locked = tryLock(mCblk->lock); + +    snprintf(buffer, size, "\t\t\t%05d %05d    %01u    %01u      %05u  %05u\n", +            (mClient == NULL) ? getpid() : mClient->pid(), +            mPriority, +            mHasControl, +            !locked, +            mCblk->clientIndex, +            mCblk->serverIndex +            ); + +    if (locked) { +        mCblk->lock.unlock(); +    } +} + +#undef LOG_TAG +#define LOG_TAG "AudioFlinger::EffectChain" + +AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& wThread, +                                        int sessionId) +    : mThread(wThread), mSessionId(sessionId), mVolumeCtrlIdx(-1), mActiveTrackCnt(0), mOwnInBuffer(false) +{ + +} + +AudioFlinger::EffectChain::~EffectChain() +{ +    if (mOwnInBuffer) { +        delete mInBuffer; +    } + +} + +sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromDesc(effect_descriptor_t *descriptor) +{ +    sp<EffectModule> effect; +    size_t size = mEffects.size(); + +    for (size_t i = 0; i < size; i++) { +        if (memcmp(&mEffects[i]->desc().uuid, &descriptor->uuid, sizeof(effect_uuid_t)) == 0) { +            effect = mEffects[i]; +            break; +        } +    } +    return effect; +} + +sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId(int id) +{ +    sp<EffectModule> effect; +    size_t size = mEffects.size(); + +    for (size_t i = 0; i < size; i++) { +        if (mEffects[i]->id() == id) { +            effect = mEffects[i]; +            break; +        } +    } +    return effect; +} + +// Must be called with EffectChain::mLock locked +void AudioFlinger::EffectChain::process_l() +{ +    size_t size = mEffects.size(); +    for (size_t i = 0; i < size; i++) { +        mEffects[i]->process(); +    } +    // if no track is active, input buffer must be cleared here as the mixer process +    // will not do it +    if (mSessionId != 0 && activeTracks() == 0) { +        sp<ThreadBase> thread = mThread.promote(); +        if (thread != 0) { +            size_t numSamples = thread->frameCount() * thread->channelCount(); +            memset(mInBuffer, 0, numSamples * sizeof(int16_t)); +        } +    } +} + +status_t AudioFlinger::EffectChain::addEffect(sp<EffectModule>& effect) +{ +    effect_descriptor_t desc = effect->desc(); +    uint32_t insertPref = desc.flags & EFFECT_FLAG_INSERT_MASK; + +    Mutex::Autolock _l(mLock); + +    if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { +        // Auxiliary effects are inserted at the beginning of mEffects vector as +        // they are processed first and accumulated in chain input buffer +        mEffects.insertAt(effect, 0); +        sp<ThreadBase> thread = mThread.promote(); +        if (thread == 0) { +            return NO_INIT; +        } +        // the input buffer for auxiliary effect contains mono samples in +        // 32 bit format. This is to avoid saturation in AudoMixer +        // accumulation stage. Saturation is done in EffectModule::process() before +        // calling the process in effect engine +        size_t numSamples = thread->frameCount(); +        int32_t *buffer = new int32_t[numSamples]; +        memset(buffer, 0, numSamples * sizeof(int32_t)); +        effect->setInBuffer((int16_t *)buffer); +        // auxiliary effects output samples to chain input buffer for further processing +        // by insert effects +        effect->setOutBuffer(mInBuffer); +    } else { +        // Insert effects are inserted at the end of mEffects vector as they are processed +        //  after track and auxiliary effects. +        // Insert effect order: +        //  if EFFECT_FLAG_INSERT_FIRST or EFFECT_FLAG_INSERT_EXCLUSIVE insert as first insert effect +        //  else if EFFECT_FLAG_INSERT_ANY insert after first or before last +        //  else insert as last insert effect +        // Reject insertion if: +        //  - EFFECT_FLAG_INSERT_EXCLUSIVE and another effect is present +        //  - an effect with EFFECT_FLAG_INSERT_EXCLUSIVE is present +        //  - EFFECT_FLAG_INSERT_FIRST or EFFECT_FLAG_INSERT_LAST and an effect with same +        //  preference is present + +        int size = (int)mEffects.size(); +        int idx_insert = size; +        int idx_insert_first = -1; +        int idx_insert_last = -1; + +        for (int i = 0; i < size; i++) { +            effect_descriptor_t d = mEffects[i]->desc(); +            uint32_t iMode = d.flags & EFFECT_FLAG_TYPE_MASK; +            uint32_t iPref = d.flags & EFFECT_FLAG_INSERT_MASK; +            if (iMode == EFFECT_FLAG_TYPE_INSERT) { +                // check invalid effect chaining combinations +                if (insertPref == EFFECT_FLAG_INSERT_EXCLUSIVE || +                    iPref == EFFECT_FLAG_INSERT_EXCLUSIVE || +                    (insertPref != EFFECT_FLAG_INSERT_ANY +                                && insertPref == iPref)) { +                    return INVALID_OPERATION; +                } +                // remember position of first insert effect +                if (idx_insert == size) { +                    idx_insert = i; +                } +                // remember position of insert effect claiming +                // first place +                if (iPref == EFFECT_FLAG_INSERT_FIRST) { +                    idx_insert_first = i; +                } +                // remember position of insert effect claiming +                // last place +                if (iPref == EFFECT_FLAG_INSERT_LAST) { +                    idx_insert_last = i; +                } +            } +        } + +        // modify idx_insert from first place if needed +        if (idx_insert_first != -1) { +            idx_insert = idx_insert_first + 1; +        } else if (idx_insert_last != -1) { +            idx_insert = idx_insert_last; +        } else if (insertPref == EFFECT_FLAG_INSERT_LAST) { +            idx_insert = size; +        } + +        // always read samples from chain input buffer +        effect->setInBuffer(mInBuffer); + +        // if last effect in the chain, output samples to chain +        // output buffer, otherwise to chain input buffer +        if (idx_insert == size) { +            if (idx_insert != 0) { +                mEffects[idx_insert-1]->setOutBuffer(mInBuffer); +                mEffects[idx_insert-1]->configure(); +            } +            effect->setOutBuffer(mOutBuffer); +        } else { +            effect->setOutBuffer(mInBuffer); +        } +        status_t status = mEffects.insertAt(effect, idx_insert); +        // Always give volume control to last effect in chain with volume control capability +        if (((desc.flags & EFFECT_FLAG_VOLUME_MASK) & EFFECT_FLAG_VOLUME_CTRL) && +                mVolumeCtrlIdx < idx_insert) { +            mVolumeCtrlIdx = idx_insert; +        } + +        LOGV("addEffect() effect %p, added in chain %p at rank %d status %d", effect.get(), this, idx_insert, status); +    } +    effect->configure(); +    return NO_ERROR; +} + +size_t AudioFlinger::EffectChain::removeEffect(const sp<EffectModule>& effect) +{ +    Mutex::Autolock _l(mLock); + +    int size = (int)mEffects.size(); +    int i; +    uint32_t type = effect->desc().flags & EFFECT_FLAG_TYPE_MASK; + +    for (i = 0; i < size; i++) { +        if (effect == mEffects[i]) { +            if (type == EFFECT_FLAG_TYPE_AUXILIARY) { +                delete[] effect->inBuffer(); +            } else { +                if (i == size - 1 && i != 0) { +                    mEffects[i - 1]->setOutBuffer(mOutBuffer); +                    mEffects[i - 1]->configure(); +                } +            } +            mEffects.removeAt(i); +            LOGV("removeEffect() effect %p, removed from chain %p at rank %d", effect.get(), this, i); +            break; +        } +    } +    // Return volume control to last effect in chain with volume control capability +    if (mVolumeCtrlIdx == i) { +        size = (int)mEffects.size(); +        for (i = size; i > 0; i--) { +            if ((mEffects[i - 1]->desc().flags & EFFECT_FLAG_VOLUME_MASK) & EFFECT_FLAG_VOLUME_CTRL) { +                break; +            } +        } +        // mVolumeCtrlIdx reset to -1 if no effect found with volume control flag set +        mVolumeCtrlIdx = i - 1; +    } + +    return mEffects.size(); +} + +void AudioFlinger::EffectChain::setDevice(uint32_t device) +{ +    size_t size = mEffects.size(); +    for (size_t i = 0; i < size; i++) { +        mEffects[i]->setDevice(device); +    } +} + +bool AudioFlinger::EffectChain::setVolume(uint32_t *left, uint32_t *right) +{ +    uint32_t newLeft = *left; +    uint32_t newRight = *right; +    bool hasControl = false; + +    // first get volume update from volume controller +    if (mVolumeCtrlIdx >= 0) { +        mEffects[mVolumeCtrlIdx]->setVolume(&newLeft, &newRight, true); +        hasControl = true; +    } +    // then indicate volume to all other effects in chain. +    // Pass altered volume to effects before volume controller +    // and requested volume to effects after controller +    uint32_t lVol = newLeft; +    uint32_t rVol = newRight; +    size_t size = mEffects.size(); +    for (size_t i = 0; i < size; i++) { +        if ((int)i == mVolumeCtrlIdx) continue; +        // this also works for mVolumeCtrlIdx == -1 when there is no volume controller +        if ((int)i > mVolumeCtrlIdx) { +            lVol = *left; +            rVol = *right; +        } +        mEffects[i]->setVolume(&lVol, &rVol, false); +    } +    *left = newLeft; +    *right = newRight; + +    return hasControl; +} + +sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getVolumeController() +{ +    sp<EffectModule> effect; +    if (mVolumeCtrlIdx >= 0) { +        effect = mEffects[mVolumeCtrlIdx]; +    } +    return effect; +} + + +status_t AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args) +{ +    const size_t SIZE = 256; +    char buffer[SIZE]; +    String8 result; + +    snprintf(buffer, SIZE, "Effects for session %d:\n", mSessionId); +    result.append(buffer); + +    bool locked = tryLock(mLock); +    // failed to lock - AudioFlinger is probably deadlocked +    if (!locked) { +        result.append("\tCould not lock mutex:\n"); +    } + +    result.append("\tNum fx In buffer   Out buffer   Vol ctrl Active tracks:\n"); +    snprintf(buffer, SIZE, "\t%02d     0x%08x  0x%08x   %02d       %d\n", +            mEffects.size(), +            (uint32_t)mInBuffer, +            (uint32_t)mOutBuffer, +            (mVolumeCtrlIdx == -1) ? 0 : mEffects[mVolumeCtrlIdx]->id(), +            mActiveTrackCnt); +    result.append(buffer); +    write(fd, result.string(), result.size()); + +    for (size_t i = 0; i < mEffects.size(); ++i) { +        sp<EffectModule> effect = mEffects[i]; +        if (effect != 0) { +            effect->dump(fd, args); +        } +    } + +    if (locked) { +        mLock.unlock(); +    } + +    return NO_ERROR; +} + +#undef LOG_TAG +#define LOG_TAG "AudioFlinger" +  // ----------------------------------------------------------------------------  status_t AudioFlinger::onTransact( diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h index 739ec33311..e543334cb7 100644 --- a/libs/audioflinger/AudioFlinger.h +++ b/libs/audioflinger/AudioFlinger.h @@ -42,6 +42,7 @@  namespace android {  class audio_track_cblk_t; +class effect_param_cblk_t;  class AudioMixer;  class AudioBuffer;  class AudioResampler; @@ -57,7 +58,7 @@ class AudioResampler;  static const nsecs_t kStandbyTimeInNsecs = seconds(3); -class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient +class AudioFlinger : public BnAudioFlinger  {  public:      static void instantiate(); @@ -75,6 +76,7 @@ public:                                  uint32_t flags,                                  const sp<IMemory>& sharedBuffer,                                  int output, +                                int *sessionId,                                  status_t *status);      virtual     uint32_t    sampleRate(int output) const; @@ -139,8 +141,27 @@ public:      virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output); -    // IBinder::DeathRecipient -    virtual     void        binderDied(const wp<IBinder>& who); +    virtual int newAudioSessionId(); + +    virtual status_t loadEffectLibrary(const char *libPath, int *handle); + +    virtual status_t unloadEffectLibrary(int handle); + +    virtual status_t queryNumberEffects(uint32_t *numEffects); + +    virtual status_t queryNextEffect(effect_descriptor_t *descriptor); + +    virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor); + +    virtual sp<IEffect> createEffect(pid_t pid, +                        effect_descriptor_t *pDesc, +                        const sp<IEffectClient>& effectClient, +                        int32_t priority, +                        int output, +                        int sessionId, +                        status_t *status, +                        int *id, +                        int *enabled);      enum hardware_call_state {          AUDIO_HW_IDLE = 0, @@ -170,6 +191,7 @@ public:                                  int channelCount,                                  int frameCount,                                  uint32_t flags, +                                int *sessionId,                                  status_t *status);      virtual     status_t    onTransact( @@ -205,6 +227,27 @@ private:          pid_t               mPid;      }; +    // --- Notification Client --- +    class NotificationClient : public IBinder::DeathRecipient { +    public: +                            NotificationClient(const sp<AudioFlinger>& audioFlinger, +                                                const sp<IAudioFlingerClient>& client, +                                                pid_t pid); +        virtual             ~NotificationClient(); + +                sp<IAudioFlingerClient>    client() { return mClient; } + +                // IBinder::DeathRecipient +                virtual     void        binderDied(const wp<IBinder>& who); + +    private: +                            NotificationClient(const NotificationClient&); +                            NotificationClient& operator = (const NotificationClient&); + +        sp<AudioFlinger>        mAudioFlinger; +        pid_t                   mPid; +        sp<IAudioFlingerClient> mClient; +    };      class TrackHandle;      class RecordHandle; @@ -215,6 +258,9 @@ private:      class DuplicatingThread;      class Track;      class RecordTrack; +    class EffectModule; +    class EffectHandle; +    class EffectChain;      class ThreadBase : public Thread {      public: @@ -250,13 +296,15 @@ private:                                          int channelCount,                                          int frameCount,                                          uint32_t flags, -                                        const sp<IMemory>& sharedBuffer); +                                        const sp<IMemory>& sharedBuffer, +                                        int sessionId);                                  ~TrackBase();              virtual status_t    start() = 0;              virtual void        stop() = 0;                      sp<IMemory> getCblk() const;                      audio_track_cblk_t* cblk() const { return mCblk; } +                    int         sessionId() { return mSessionId; }          protected:              friend class ThreadBase; @@ -305,6 +353,7 @@ private:              int                 mClientTid;              uint8_t             mFormat;              uint32_t            mFlags; +            int                 mSessionId;          };          class ConfigEvent { @@ -324,7 +373,7 @@ private:          virtual     bool        checkForNewParameters_l() = 0;          virtual     status_t    setParameters(const String8& keyValuePairs);          virtual     String8     getParameters(const String8& keys) = 0; -        virtual     void        audioConfigChanged(int event, int param = 0) = 0; +        virtual     void        audioConfigChanged_l(int event, int param = 0) = 0;                      void        sendConfigEvent(int event, int param = 0);                      void        sendConfigEvent_l(int event, int param = 0);                      void        processConfigEvents(); @@ -348,9 +397,10 @@ private:                      sp<AudioFlinger>        mAudioFlinger;                      uint32_t                mSampleRate;                      size_t                  mFrameCount; -                    int                     mChannelCount; +                    uint32_t                mChannels; +                    uint16_t                mChannelCount; +                    uint16_t                mFrameSize;                      int                     mFormat; -                    uint32_t                mFrameSize;                      Condition               mParamCond;                      Vector<String8>         mNewParameters;                      status_t                mParamStatus; @@ -386,7 +436,8 @@ private:                                          int format,                                          int channelCount,                                          int frameCount, -                                        const sp<IMemory>& sharedBuffer); +                                        const sp<IMemory>& sharedBuffer, +                                        int sessionId);                                  ~Track();                      void        dump(char* buffer, size_t size); @@ -405,6 +456,12 @@ private:                      int type() const {                          return mStreamType;                      } +                    status_t    attachAuxEffect(int EffectId); +                    void        setAuxBuffer(int EffectId, int32_t *buffer); +                    int32_t     *auxBuffer() { return mAuxBuffer; } +                    void        setMainBuffer(int16_t *buffer) { mMainBuffer = buffer; } +                    int16_t     *mainBuffer() { return mMainBuffer; } +                    int         auxEffectId() { return mAuxEffectId; }          protected: @@ -445,6 +502,9 @@ private:              bool                mResetDone;              int                 mStreamType;              int                 mName; +            int16_t             *mMainBuffer; +            int32_t             *mAuxBuffer; +            int                 mAuxEffectId;          };  // end of Track @@ -486,7 +546,7 @@ private:              DuplicatingThread*          mSourceThread;          };  // end of OutputTrack -        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id); +        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);          virtual             ~PlaybackThread();          virtual     status_t    dump(int fd, const Vector<String16>& args); @@ -519,6 +579,7 @@ private:                                      int channelCount,                                      int frameCount,                                      const sp<IMemory>& sharedBuffer, +                                    int sessionId,                                      status_t *status);                      AudioStreamOut* getOutput() { return mOutput; } @@ -528,8 +589,31 @@ private:                      void        restore() { if (mSuspended) mSuspended--; }                      bool        isSuspended() { return (mSuspended != 0); }          virtual     String8     getParameters(const String8& keys); -        virtual     void        audioConfigChanged(int event, int param = 0); +        virtual     void        audioConfigChanged_l(int event, int param = 0);          virtual     status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames); +                    int16_t     *mixBuffer() { return mMixBuffer; }; + +                    sp<EffectHandle> createEffect_l( +                                        const sp<AudioFlinger::Client>& client, +                                        const sp<IEffectClient>& effectClient, +                                        int32_t priority, +                                        int sessionId, +                                        effect_descriptor_t *desc, +                                        int *enabled, +                                        status_t *status); + +                    bool hasAudioSession(int sessionId); +                    sp<EffectChain> getEffectChain(int sessionId); +                    sp<EffectChain> getEffectChain_l(int sessionId); +                    status_t addEffectChain_l(const sp<EffectChain>& chain); +                    size_t removeEffectChain_l(const sp<EffectChain>& chain); +                    void lockEffectChains_l(); +                    void unlockEffectChains(); + +                    sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId); +                    void detachAuxEffect_l(int effectId); +                    status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId); +                    status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);          struct  stream_type_t {              stream_type_t() @@ -572,8 +656,11 @@ private:          void        readOutputParameters(); +        uint32_t    device() { return mDevice; } +          virtual status_t    dumpInternals(int fd, const Vector<String16>& args);          status_t    dumpTracks(int fd, const Vector<String16>& args); +        status_t    dumpEffectChains(int fd, const Vector<String16>& args);          SortedVector< sp<Track> >       mTracks;          // mStreamTypes[] uses 1 additionnal stream type internally for the OutputTrack used by DuplicatingThread @@ -584,21 +671,19 @@ private:          int                             mNumWrites;          int                             mNumDelayedWrites;          bool                            mInWrite; +        Vector< sp<EffectChain> >       mEffectChains; +        uint32_t                        mDevice;      };      class MixerThread : public PlaybackThread {      public: -        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id); +        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);          virtual             ~MixerThread();          // Thread virtuals          virtual     bool        threadLoop(); -                    void        getTracks(SortedVector < sp<Track> >& tracks, -                                      SortedVector < wp<Track> >& activeTracks, -                                      int streamType); -                    void        putTracks(SortedVector < sp<Track> >& tracks, -                                      SortedVector < wp<Track> >& activeTracks); +                    void        invalidateTracks(int streamType);          virtual     bool        checkForNewParameters_l();          virtual     status_t    dumpInternals(int fd, const Vector<String16>& args); @@ -615,7 +700,7 @@ private:      class DirectOutputThread : public PlaybackThread {      public: -        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id); +        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);          ~DirectOutputThread();          // Thread virtuals @@ -630,8 +715,12 @@ private:          virtual     uint32_t    idleSleepTimeUs();      private: -        float mLeftVolume; -        float mRightVolume; +        void applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp); + +        float mLeftVolFloat; +        float mRightVolFloat; +        uint16_t mLeftVolShort; +        uint16_t mRightVolShort;      };      class DuplicatingThread : public MixerThread { @@ -661,6 +750,8 @@ private:                float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }                void audioConfigChanged_l(int event, int ioHandle, void *param2); +              int  nextUniqueId(); +      friend class AudioBuffer;      class TrackHandle : public android::BnAudioTrack { @@ -674,6 +765,7 @@ private:          virtual void        pause();          virtual void        setVolume(float left, float right);          virtual sp<IMemory> getCblk() const; +        virtual status_t    attachAuxEffect(int effectId);          virtual status_t onTransact(              uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);      private: @@ -685,6 +777,7 @@ private:                  void        removeClient_l(pid_t pid); +                void        removeNotificationClient(pid_t pid);      // record thread @@ -701,7 +794,8 @@ private:                                          int format,                                          int channelCount,                                          int frameCount, -                                        uint32_t flags); +                                        uint32_t flags, +                                        int sessionId);                                  ~RecordTrack();              virtual status_t    start(); @@ -744,7 +838,7 @@ private:          virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);          virtual bool        checkForNewParameters_l();          virtual String8     getParameters(const String8& keys); -        virtual void        audioConfigChanged(int event, int param = 0); +        virtual void        audioConfigChanged_l(int event, int param = 0);                  void        readInputParameters();          virtual unsigned int  getInputFramesLost(); @@ -776,6 +870,215 @@ private:          sp<RecordThread::RecordTrack> mRecordTrack;      }; +    //--- Audio Effect Management + +    // EffectModule and EffectChain classes both have their own mutex to protect +    // state changes or resource modifications. Always respect the following order +    // if multiple mutexes must be acquired to avoid cross deadlock: +    // AudioFlinger -> ThreadBase -> EffectChain -> EffectModule + +    // The EffectModule class is a wrapper object controlling the effect engine implementation +    // in the effect library. It prevents concurrent calls to process() and command() functions +    // from different client threads. It keeps a list of EffectHandle objects corresponding +    // to all client applications using this effect and notifies applications of effect state, +    // control or parameter changes. It manages the activation state machine to send appropriate +    // reset, enable, disable commands to effect engine and provide volume +    // ramping when effects are activated/deactivated. +    // When controlling an auxiliary effect, the EffectModule also provides an input buffer used by +    // the attached track(s) to accumulate their auxiliary channel. +    class EffectModule: public RefBase { +    public: +        EffectModule(const wp<ThreadBase>& wThread, +                        const wp<AudioFlinger::EffectChain>& chain, +                        effect_descriptor_t *desc, +                        int id, +                        int sessionId); +        ~EffectModule(); + +        enum effect_state { +            IDLE, +            RESET, +            STARTING, +            ACTIVE, +            STOPPING, +            STOPPED +        }; + +        int         id() { return mId; } +        void process(); +        status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData); + +        void reset(); +        status_t configure(); +        status_t init(); +        uint32_t state() { +            return mState; +        } +        uint32_t status() { +            return mStatus; +        } +        status_t    setEnabled(bool enabled); +        bool isEnabled(); + +        void        setInBuffer(int16_t *buffer) { mConfig.inputCfg.buffer.s16 = buffer; } +        int16_t     *inBuffer() { return mConfig.inputCfg.buffer.s16; } +        void        setOutBuffer(int16_t *buffer) { mConfig.outputCfg.buffer.s16 = buffer; } +        int16_t     *outBuffer() { return mConfig.outputCfg.buffer.s16; } + +        status_t addHandle(sp<EffectHandle>& handle); +        void disconnect(const wp<EffectHandle>& handle); +        size_t removeHandle (const wp<EffectHandle>& handle); + +        effect_descriptor_t& desc() { return mDescriptor; } + +        status_t         setDevice(uint32_t device); +        status_t         setVolume(uint32_t *left, uint32_t *right, bool controller); + +        status_t         dump(int fd, const Vector<String16>& args); + +    protected: + +        EffectModule(const EffectModule&); +        EffectModule& operator = (const EffectModule&); + +        status_t start(); +        status_t stop(); + +        Mutex               mLock;      // mutex for process, commands and handles list protection +        wp<ThreadBase>      mThread;    // parent thread +        wp<EffectChain>     mChain;     // parent effect chain +        int                 mId;        // this instance unique ID +        int                 mSessionId; // audio session ID +        effect_descriptor_t mDescriptor;// effect descriptor received from effect engine +        effect_config_t     mConfig;    // input and output audio configuration +        effect_interface_t  mEffectInterface; // Effect module C API +        status_t mStatus;               // initialization status +        uint32_t mState;                // current activation state (effect_state) +        Vector< wp<EffectHandle> > mHandles;    // list of client handles +    }; + +    // The EffectHandle class implements the IEffect interface. It provides resources +    // to receive parameter updates, keeps track of effect control +    // ownership and state and has a pointer to the EffectModule object it is controlling. +    // There is one EffectHandle object for each application controlling (or using) +    // an effect module. +    // The EffectHandle is obtained by calling AudioFlinger::createEffect(). +    class EffectHandle: public android::BnEffect { +    public: + +        EffectHandle(const sp<EffectModule>& effect, +                const sp<AudioFlinger::Client>& client, +                const sp<IEffectClient>& effectClient, +                int32_t priority); +        virtual ~EffectHandle(); + +        // IEffect +        virtual status_t enable(); +        virtual status_t disable(); +        virtual status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData); +        virtual void disconnect(); +        virtual sp<IMemory> getCblk() const; +        virtual status_t onTransact(uint32_t code, const Parcel& data, +                Parcel* reply, uint32_t flags); + + +        // Give or take control of effect module +        void setControl(bool hasControl, bool signal); +        void commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData); +        void setEnabled(bool enabled); + +        // Getters +        int id() { return mEffect->id(); } +        int priority() { return mPriority; } +        bool hasControl() { return mHasControl; } +        sp<EffectModule> effect() { return mEffect; } + +        void dump(char* buffer, size_t size); + +    protected: + +        EffectHandle(const EffectHandle&); +        EffectHandle& operator =(const EffectHandle&); + +        sp<EffectModule> mEffect;           // pointer to controlled EffectModule +        sp<IEffectClient> mEffectClient;    // callback interface for client notifications +        sp<Client>          mClient;        // client for shared memory allocation +        sp<IMemory>         mCblkMemory;    // shared memory for control block +        effect_param_cblk_t* mCblk;         // control block for deferred parameter setting via shared memory +        uint8_t*            mBuffer;        // pointer to parameter area in shared memory +        int mPriority;                      // client application priority to control the effect +        bool mHasControl;                   // true if this handle is controlling the effect +    }; + +    // the EffectChain class represents a group of effects associated to one audio session. +    // There can be any number of EffectChain objects per output mixer thread (PlaybackThread). +    // The EffecChain with session ID 0 contains global effects applied to the output mix. +    // Effects in this chain can be insert or auxiliary. Effects in other chains (attached to tracks) +    // are insert only. The EffectChain maintains an ordered list of effect module, the order corresponding +    // in the effect process order. When attached to a track (session ID != 0), it also provide it's own +    // input buffer used by the track as accumulation buffer. +    class EffectChain: public RefBase { +    public: +        EffectChain(const wp<ThreadBase>& wThread, int sessionId); +        ~EffectChain(); + +        void process_l(); + +        void lock() { +            mLock.lock(); +        } +        void unlock() { +            mLock.unlock(); +        } + +        status_t addEffect(sp<EffectModule>& handle); +        size_t removeEffect(const sp<EffectModule>& handle); + +        int sessionId() { +            return mSessionId; +        } +        sp<EffectModule> getEffectFromDesc(effect_descriptor_t *descriptor); +        sp<EffectModule> getEffectFromId(int id); +        sp<EffectModule> getVolumeController(); +        bool setVolume(uint32_t *left, uint32_t *right); +        void setDevice(uint32_t device); + +        void setInBuffer(int16_t *buffer, bool ownsBuffer = false) { +            mInBuffer = buffer; +            mOwnInBuffer = ownsBuffer; +        } +        int16_t *inBuffer() { +            return mInBuffer; +        } +        void setOutBuffer(int16_t *buffer) { +            mOutBuffer = buffer; +        } +        int16_t *outBuffer() { +            return mOutBuffer; +        } + +        void startTrack() {mActiveTrackCnt++;} +        void stopTrack() {mActiveTrackCnt--;} +        int activeTracks() { return mActiveTrackCnt;} + +        status_t dump(int fd, const Vector<String16>& args); + +    protected: + +        EffectChain(const EffectChain&); +        EffectChain& operator =(const EffectChain&); + +        wp<ThreadBase> mThread;     // parent mixer thread +        Mutex mLock;                // mutex protecting effect list +        Vector<sp<EffectModule> > mEffects; // list of effect modules +        int mSessionId;             // audio session ID +        int16_t *mInBuffer;         // chain input buffer +        int16_t *mOutBuffer;        // chain output buffer +        int mVolumeCtrlIdx;         // index of insert effect having control over volume +        int mActiveTrackCnt;        // number of active tracks connected +        bool mOwnInBuffer;          // true if the chain owns its input buffer +    }; +      friend class RecordThread;      friend class PlaybackThread; @@ -796,8 +1099,11 @@ private:                  DefaultKeyedVector< int, sp<RecordThread> >    mRecordThreads; -                SortedVector< sp<IBinder> >         mNotificationClients; -                int                                 mNextThreadId; +                DefaultKeyedVector< pid_t, sp<NotificationClient> >    mNotificationClients; +                volatile int32_t                    mNextUniqueId; +#ifdef LVMX +                int mLifeVibesClientPid; +#endif  };  // ---------------------------------------------------------------------------- diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp index 19a442a864..8aaa325486 100644 --- a/libs/audioflinger/AudioMixer.cpp +++ b/libs/audioflinger/AudioMixer.cpp @@ -56,6 +56,8 @@ AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate)          t->volume[1] = UNITY_GAIN;          t->volumeInc[0] = 0;          t->volumeInc[1] = 0; +        t->auxLevel = 0; +        t->auxInc = 0;          t->channelCount = 2;          t->enabled = 0;          t->format = 16; @@ -65,6 +67,8 @@ AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate)          t->resampler = 0;          t->sampleRate = mSampleRate;          t->in = 0; +        t->mainBuffer = NULL; +        t->auxBuffer = NULL;          t++;      }  } @@ -169,28 +173,48 @@ status_t AudioMixer::setActiveTrack(int track)      return NO_ERROR;  } -status_t AudioMixer::setParameter(int target, int name, int value) +status_t AudioMixer::setParameter(int target, int name, void *value)  { +    int valueInt = (int)value; +    int32_t *valueBuf = (int32_t *)value; +      switch (target) {      case TRACK:          if (name == CHANNEL_COUNT) { -            if ((uint32_t(value) <= MAX_NUM_CHANNELS) && (value)) { -                if (mState.tracks[ mActiveTrack ].channelCount != value) { -                    mState.tracks[ mActiveTrack ].channelCount = value; -                    LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", value); +            if ((uint32_t(valueInt) <= MAX_NUM_CHANNELS) && (valueInt)) { +                if (mState.tracks[ mActiveTrack ].channelCount != valueInt) { +                    mState.tracks[ mActiveTrack ].channelCount = valueInt; +                    LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", valueInt);                      invalidateState(1<<mActiveTrack);                  }                  return NO_ERROR;              }          } +        if (name == MAIN_BUFFER) { +            if (mState.tracks[ mActiveTrack ].mainBuffer != valueBuf) { +                mState.tracks[ mActiveTrack ].mainBuffer = valueBuf; +                LOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf); +                invalidateState(1<<mActiveTrack); +            } +            return NO_ERROR; +        } +        if (name == AUX_BUFFER) { +            if (mState.tracks[ mActiveTrack ].auxBuffer != valueBuf) { +                mState.tracks[ mActiveTrack ].auxBuffer = valueBuf; +                LOGV("setParameter(TRACK, AUX_BUFFER, %p)", valueBuf); +                invalidateState(1<<mActiveTrack); +            } +            return NO_ERROR; +        } +          break;      case RESAMPLE:          if (name == SAMPLE_RATE) { -            if (value > 0) { +            if (valueInt > 0) {                  track_t& track = mState.tracks[ mActiveTrack ]; -                if (track.setResampler(uint32_t(value), mSampleRate)) { +                if (track.setResampler(uint32_t(valueInt), mSampleRate)) {                      LOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)", -                            uint32_t(value)); +                            uint32_t(valueInt));                      invalidateState(1<<mActiveTrack);                  }                  return NO_ERROR; @@ -201,18 +225,39 @@ status_t AudioMixer::setParameter(int target, int name, int value)      case VOLUME:          if ((uint32_t(name-VOLUME0) < MAX_NUM_CHANNELS)) {              track_t& track = mState.tracks[ mActiveTrack ]; -            if (track.volume[name-VOLUME0] != value) { +            if (track.volume[name-VOLUME0] != valueInt) { +                LOGV("setParameter(VOLUME, VOLUME0/1: %04x)", valueInt);                  track.prevVolume[name-VOLUME0] = track.volume[name-VOLUME0] << 16; -                track.volume[name-VOLUME0] = value; +                track.volume[name-VOLUME0] = valueInt;                  if (target == VOLUME) { -                    track.prevVolume[name-VOLUME0] = value << 16; +                    track.prevVolume[name-VOLUME0] = valueInt << 16;                      track.volumeInc[name-VOLUME0] = 0;                  } else { -                    int32_t d = (value<<16) - track.prevVolume[name-VOLUME0]; +                    int32_t d = (valueInt<<16) - track.prevVolume[name-VOLUME0];                      int32_t volInc = d / int32_t(mState.frameCount);                      track.volumeInc[name-VOLUME0] = volInc;                      if (volInc == 0) { -                        track.prevVolume[name-VOLUME0] = value << 16; +                        track.prevVolume[name-VOLUME0] = valueInt << 16; +                    } +                } +                invalidateState(1<<mActiveTrack); +            } +            return NO_ERROR; +        } else if (name == AUXLEVEL) { +            track_t& track = mState.tracks[ mActiveTrack ]; +            if (track.auxLevel != valueInt) { +                LOGV("setParameter(VOLUME, AUXLEVEL: %04x)", valueInt); +                track.prevAuxLevel = track.auxLevel << 16; +                track.auxLevel = valueInt; +                if (target == VOLUME) { +                    track.prevAuxLevel = valueInt << 16; +                    track.auxInc = 0; +                } else { +                    int32_t d = (valueInt<<16) - track.prevAuxLevel; +                    int32_t volInc = d / int32_t(mState.frameCount); +                    track.auxInc = volInc; +                    if (volInc == 0) { +                        track.prevAuxLevel = valueInt << 16;                      }                  }                  invalidateState(1<<mActiveTrack); @@ -245,7 +290,7 @@ bool AudioMixer::track_t::doesResample() const  }  inline -void AudioMixer::track_t::adjustVolumeRamp() +void AudioMixer::track_t::adjustVolumeRamp(bool aux)  {      for (int i=0 ; i<2 ; i++) {          if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) || @@ -254,6 +299,13 @@ void AudioMixer::track_t::adjustVolumeRamp()              prevVolume[i] = volume[i]<<16;          }      } +    if (aux) { +        if (((auxInc>0) && (((prevAuxLevel+auxInc)>>16) >= auxLevel)) || +            ((auxInc<0) && (((prevAuxLevel+auxInc)>>16) <= auxLevel))) { +            auxInc = 0; +            prevAuxLevel = auxLevel<<16; +        } +    }  } @@ -265,13 +317,13 @@ status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer) -void AudioMixer::process(void* output) +void AudioMixer::process()  { -    mState.hook(&mState, output); +    mState.hook(&mState);  } -void AudioMixer::process__validate(state_t* state, void* output) +void AudioMixer::process__validate(state_t* state)  {      LOGW_IF(!state->needsChanged,          "in process__validate() but nothing's invalid"); @@ -308,7 +360,10 @@ void AudioMixer::process__validate(state_t* state, void* output)          n |= NEEDS_CHANNEL_1 + t.channelCount - 1;          n |= NEEDS_FORMAT_16;          n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED; -        +        if (t.auxLevel != 0 && t.auxBuffer != NULL) { +            n |= NEEDS_AUX_ENABLED; +        } +          if (t.volumeInc[0]|t.volumeInc[1]) {              volumeRamp = 1;          } else if (!t.doesResample() && t.volumeRL == 0) { @@ -319,6 +374,9 @@ void AudioMixer::process__validate(state_t* state, void* output)          if ((n & NEEDS_MUTE__MASK) == NEEDS_MUTE_ENABLED) {              t.hook = track__nop;          } else { +            if ((n & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) { +                all16BitsStereoNoResample = 0; +            }              if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {                  all16BitsStereoNoResample = 0;                  resampling = 1; @@ -369,7 +427,7 @@ void AudioMixer::process__validate(state_t* state, void* output)          countActiveTracks, state->enabledTracks,          all16BitsStereoNoResample, resampling, volumeRamp); -   state->hook(state, output); +   state->hook(state);     // Now that the volume ramp has been done, set optimal state and     // track hooks for subsequent mixer process @@ -390,7 +448,7 @@ void AudioMixer::process__validate(state_t* state, void* output)         }         if (allMuted) {             state->hook = process__nop; -       } else if (!resampling && all16BitsStereoNoResample) { +       } else if (all16BitsStereoNoResample) {             if (countActiveTracks == 1) {                state->hook = process__OneTrack16BitsStereoNoResampling;             } @@ -481,30 +539,44 @@ int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)  } -void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp) +void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux)  {      t->resampler->setSampleRate(t->sampleRate);      // ramp gain - resample to temp buffer and scale/mix in 2nd step -    if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) { +    if (aux != NULL) { +        // always resample with unity gain when sending to auxiliary buffer to be able +        // to apply send level after resampling +        // TODO: modify each resampler to support aux channel?          t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);          memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));          t->resampler->resample(temp, outFrameCount, t->bufferProvider); -        volumeRampStereo(t, out, outFrameCount, temp); -    } +        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) { +            volumeRampStereo(t, out, outFrameCount, temp, aux); +        } else { +            volumeStereo(t, out, outFrameCount, temp, aux); +        } +    } else { +        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) { +            t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN); +            memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t)); +            t->resampler->resample(temp, outFrameCount, t->bufferProvider); +            volumeRampStereo(t, out, outFrameCount, temp, aux); +        } -    // constant gain -    else { -        t->resampler->setVolume(t->volume[0], t->volume[1]); -        t->resampler->resample(out, outFrameCount, t->bufferProvider); +        // constant gain +        else { +            t->resampler->setVolume(t->volume[0], t->volume[1]); +            t->resampler->resample(out, outFrameCount, t->bufferProvider); +        }      }  } -void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp) +void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux)  {  } -void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp) +void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)  {      int32_t vl = t->prevVolume[0];      int32_t vr = t->prevVolume[1]; @@ -514,98 +586,238 @@ void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, i      //LOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",      //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0],      //       (vl + vlInc*frameCount)/65536.0f, frameCount); -    +      // ramp volume -    do { -        *out++ += (vl >> 16) * (*temp++ >> 12); -        *out++ += (vr >> 16) * (*temp++ >> 12); -        vl += vlInc; -        vr += vrInc; -    } while (--frameCount); +    if UNLIKELY(aux != NULL) { +        int32_t va = t->prevAuxLevel; +        const int32_t vaInc = t->auxInc; +        int32_t l; +        int32_t r; +        do { +            l = (*temp++ >> 12); +            r = (*temp++ >> 12); +            *out++ += (vl >> 16) * l; +            *out++ += (vr >> 16) * r; +            *aux++ += (va >> 17) * (l + r); +            vl += vlInc; +            vr += vrInc; +            va += vaInc; +        } while (--frameCount); +        t->prevAuxLevel = va; +    } else { +        do { +            *out++ += (vl >> 16) * (*temp++ >> 12); +            *out++ += (vr >> 16) * (*temp++ >> 12); +            vl += vlInc; +            vr += vrInc; +        } while (--frameCount); +    }      t->prevVolume[0] = vl;      t->prevVolume[1] = vr; -    t->adjustVolumeRamp(); +    t->adjustVolumeRamp((aux != NULL));  } -void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp) +void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)  { -    int16_t const *in = static_cast<int16_t const *>(t->in); - -    // ramp gain -    if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) { -        int32_t vl = t->prevVolume[0]; -        int32_t vr = t->prevVolume[1]; -        const int32_t vlInc = t->volumeInc[0]; -        const int32_t vrInc = t->volumeInc[1]; - -        // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", -        //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0], -        //        (vl + vlInc*frameCount)/65536.0f, frameCount); +    const int16_t vl = t->volume[0]; +    const int16_t vr = t->volume[1]; +    if UNLIKELY(aux != NULL) { +        const int16_t va = (int16_t)t->auxLevel;          do { -            *out++ += (vl >> 16) * (int32_t) *in++; -            *out++ += (vr >> 16) * (int32_t) *in++; -            vl += vlInc; -            vr += vrInc; +            int16_t l = (int16_t)(*temp++ >> 12); +            int16_t r = (int16_t)(*temp++ >> 12); +            out[0] = mulAdd(l, vl, out[0]); +            int16_t a = (int16_t)(((int32_t)l + r) >> 1); +            out[1] = mulAdd(r, vr, out[1]); +            out += 2; +            aux[0] = mulAdd(a, va, aux[0]); +            aux++;          } while (--frameCount); -        -        t->prevVolume[0] = vl; -        t->prevVolume[1] = vr; -        t->adjustVolumeRamp(); -    } - -    // constant gain -    else { -        const uint32_t vrl = t->volumeRL; +    } else {          do { -            uint32_t rl = *reinterpret_cast<uint32_t const *>(in); -            in += 2; -            out[0] = mulAddRL(1, rl, vrl, out[0]); -            out[1] = mulAddRL(0, rl, vrl, out[1]); +            int16_t l = (int16_t)(*temp++ >> 12); +            int16_t r = (int16_t)(*temp++ >> 12); +            out[0] = mulAdd(l, vl, out[0]); +            out[1] = mulAdd(r, vr, out[1]);              out += 2;          } while (--frameCount);      } +} + +void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux) +{ +    int16_t const *in = static_cast<int16_t const *>(t->in); + +    if UNLIKELY(aux != NULL) { +        int32_t l; +        int32_t r; +        // ramp gain +        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) { +            int32_t vl = t->prevVolume[0]; +            int32_t vr = t->prevVolume[1]; +            int32_t va = t->prevAuxLevel; +            const int32_t vlInc = t->volumeInc[0]; +            const int32_t vrInc = t->volumeInc[1]; +            const int32_t vaInc = t->auxInc; +            // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", +            //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0], +            //        (vl + vlInc*frameCount)/65536.0f, frameCount); + +            do { +                l = (int32_t)*in++; +                r = (int32_t)*in++; +                *out++ += (vl >> 16) * l; +                *out++ += (vr >> 16) * r; +                *aux++ += (va >> 17) * (l + r); +                vl += vlInc; +                vr += vrInc; +                va += vaInc; +            } while (--frameCount); + +            t->prevVolume[0] = vl; +            t->prevVolume[1] = vr; +            t->prevAuxLevel = va; +            t->adjustVolumeRamp(true); +        } + +        // constant gain +        else { +            const uint32_t vrl = t->volumeRL; +            const int16_t va = (int16_t)t->auxLevel; +            do { +                uint32_t rl = *reinterpret_cast<uint32_t const *>(in); +                int16_t a = (int16_t)(((int32_t)in[0] + in[1]) >> 1); +                in += 2; +                out[0] = mulAddRL(1, rl, vrl, out[0]); +                out[1] = mulAddRL(0, rl, vrl, out[1]); +                out += 2; +                aux[0] = mulAdd(a, va, aux[0]); +                aux++; +            } while (--frameCount); +        } +    } else { +        // ramp gain +        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) { +            int32_t vl = t->prevVolume[0]; +            int32_t vr = t->prevVolume[1]; +            const int32_t vlInc = t->volumeInc[0]; +            const int32_t vrInc = t->volumeInc[1]; + +            // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", +            //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0], +            //        (vl + vlInc*frameCount)/65536.0f, frameCount); + +            do { +                *out++ += (vl >> 16) * (int32_t) *in++; +                *out++ += (vr >> 16) * (int32_t) *in++; +                vl += vlInc; +                vr += vrInc; +            } while (--frameCount); + +            t->prevVolume[0] = vl; +            t->prevVolume[1] = vr; +            t->adjustVolumeRamp(false); +        } + +        // constant gain +        else { +            const uint32_t vrl = t->volumeRL; +            do { +                uint32_t rl = *reinterpret_cast<uint32_t const *>(in); +                in += 2; +                out[0] = mulAddRL(1, rl, vrl, out[0]); +                out[1] = mulAddRL(0, rl, vrl, out[1]); +                out += 2; +            } while (--frameCount); +        } +    }      t->in = in;  } -void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp) +void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)  {      int16_t const *in = static_cast<int16_t const *>(t->in); -    // ramp gain -    if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) { -        int32_t vl = t->prevVolume[0]; -        int32_t vr = t->prevVolume[1]; -        const int32_t vlInc = t->volumeInc[0]; -        const int32_t vrInc = t->volumeInc[1]; +    if UNLIKELY(aux != NULL) { +        // ramp gain +        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) { +            int32_t vl = t->prevVolume[0]; +            int32_t vr = t->prevVolume[1]; +            int32_t va = t->prevAuxLevel; +            const int32_t vlInc = t->volumeInc[0]; +            const int32_t vrInc = t->volumeInc[1]; +            const int32_t vaInc = t->auxInc; -        // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", -        //         t, vlInc/65536.0f, vl/65536.0f, t->volume[0], -        //         (vl + vlInc*frameCount)/65536.0f, frameCount); +            // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", +            //         t, vlInc/65536.0f, vl/65536.0f, t->volume[0], +            //         (vl + vlInc*frameCount)/65536.0f, frameCount); -        do { -            int32_t l = *in++; -            *out++ += (vl >> 16) * l; -            *out++ += (vr >> 16) * l; -            vl += vlInc; -            vr += vrInc; -        } while (--frameCount); -        -        t->prevVolume[0] = vl; -        t->prevVolume[1] = vr; -        t->adjustVolumeRamp(); -    } -    // constant gain -    else { -        const int16_t vl = t->volume[0]; -        const int16_t vr = t->volume[1]; -        do { -            int16_t l = *in++; -            out[0] = mulAdd(l, vl, out[0]); -            out[1] = mulAdd(l, vr, out[1]); -            out += 2; -        } while (--frameCount); +            do { +                int32_t l = *in++; +                *out++ += (vl >> 16) * l; +                *out++ += (vr >> 16) * l; +                *aux++ += (va >> 16) * l; +                vl += vlInc; +                vr += vrInc; +                va += vaInc; +            } while (--frameCount); + +            t->prevVolume[0] = vl; +            t->prevVolume[1] = vr; +            t->prevAuxLevel = va; +            t->adjustVolumeRamp(true); +        } +        // constant gain +        else { +            const int16_t vl = t->volume[0]; +            const int16_t vr = t->volume[1]; +            const int16_t va = (int16_t)t->auxLevel; +            do { +                int16_t l = *in++; +                out[0] = mulAdd(l, vl, out[0]); +                out[1] = mulAdd(l, vr, out[1]); +                out += 2; +                aux[0] = mulAdd(l, va, aux[0]); +                aux++; +            } while (--frameCount); +        } +    } else { +        // ramp gain +        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) { +            int32_t vl = t->prevVolume[0]; +            int32_t vr = t->prevVolume[1]; +            const int32_t vlInc = t->volumeInc[0]; +            const int32_t vrInc = t->volumeInc[1]; + +            // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", +            //         t, vlInc/65536.0f, vl/65536.0f, t->volume[0], +            //         (vl + vlInc*frameCount)/65536.0f, frameCount); + +            do { +                int32_t l = *in++; +                *out++ += (vl >> 16) * l; +                *out++ += (vr >> 16) * l; +                vl += vlInc; +                vr += vrInc; +            } while (--frameCount); + +            t->prevVolume[0] = vl; +            t->prevVolume[1] = vr; +            t->adjustVolumeRamp(false); +        } +        // constant gain +        else { +            const int16_t vl = t->volume[0]; +            const int16_t vr = t->volume[1]; +            do { +                int16_t l = *in++; +                out[0] = mulAdd(l, vl, out[0]); +                out[1] = mulAdd(l, vr, out[1]); +                out += 2; +            } while (--frameCount); +        }      }      t->in = in;  } @@ -624,37 +836,56 @@ void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)  }  // no-op case -void AudioMixer::process__nop(state_t* state, void* output) +void AudioMixer::process__nop(state_t* state)  { -    // this assumes output 16 bits stereo, no resampling -    memset(output, 0, state->frameCount*4); -    uint32_t en = state->enabledTracks; -    while (en) { -        const int i = 31 - __builtin_clz(en); -        en &= ~(1<<i); -        track_t& t = state->tracks[i]; -        size_t outFrames = state->frameCount; -        while (outFrames) { -            t.buffer.frameCount = outFrames; -            t.bufferProvider->getNextBuffer(&t.buffer); -            if (!t.buffer.raw) break; -            outFrames -= t.buffer.frameCount; -            t.bufferProvider->releaseBuffer(&t.buffer); +    uint32_t e0 = state->enabledTracks; +    size_t bufSize = state->frameCount * sizeof(int16_t) * MAX_NUM_CHANNELS; +    while (e0) { +        // process by group of tracks with same output buffer to +        // avoid multiple memset() on same buffer +        uint32_t e1 = e0, e2 = e0; +        int i = 31 - __builtin_clz(e1); +        track_t& t1 = state->tracks[i]; +        e2 &= ~(1<<i); +        while (e2) { +            i = 31 - __builtin_clz(e2); +            e2 &= ~(1<<i); +            track_t& t2 = state->tracks[i]; +            if UNLIKELY(t2.mainBuffer != t1.mainBuffer) { +                e1 &= ~(1<<i); +            } +        } +        e0 &= ~(e1); + +        memset(t1.mainBuffer, 0, bufSize); + +        while (e1) { +            i = 31 - __builtin_clz(e1); +            e1 &= ~(1<<i); +            t1 = state->tracks[i]; +            size_t outFrames = state->frameCount; +            while (outFrames) { +                t1.buffer.frameCount = outFrames; +                t1.bufferProvider->getNextBuffer(&t1.buffer); +                if (!t1.buffer.raw) break; +                outFrames -= t1.buffer.frameCount; +                t1.bufferProvider->releaseBuffer(&t1.buffer); +            }          }      }  }  // generic code without resampling -void AudioMixer::process__genericNoResampling(state_t* state, void* output) +void AudioMixer::process__genericNoResampling(state_t* state)  {      int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));      // acquire each track's buffer      uint32_t enabledTracks = state->enabledTracks; -    uint32_t en = enabledTracks; -    while (en) { -        const int i = 31 - __builtin_clz(en); -        en &= ~(1<<i); +    uint32_t e0 = enabledTracks; +    while (e0) { +        const int i = 31 - __builtin_clz(e0); +        e0 &= ~(1<<i);          track_t& t = state->tracks[i];          t.buffer.frameCount = state->frameCount;          t.bufferProvider->getNextBuffer(&t.buffer); @@ -666,110 +897,156 @@ void AudioMixer::process__genericNoResampling(state_t* state, void* output)              enabledTracks &= ~(1<<i);      } -    // this assumes output 16 bits stereo, no resampling -    int32_t* out = static_cast<int32_t*>(output); -    size_t numFrames = state->frameCount; -    do { -        memset(outTemp, 0, sizeof(outTemp)); - -        en = enabledTracks; -        while (en) { -            const int i = 31 - __builtin_clz(en); -            en &= ~(1<<i); -            track_t& t = state->tracks[i]; -            size_t outFrames = BLOCKSIZE; -            -            while (outFrames) { -                size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount; -                if (inFrames) { -                    (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp); -                    t.frameCount -= inFrames; -                    outFrames -= inFrames; +    e0 = enabledTracks; +    while (e0) { +        // process by group of tracks with same output buffer to +        // optimize cache use +        uint32_t e1 = e0, e2 = e0; +        int j = 31 - __builtin_clz(e1); +        track_t& t1 = state->tracks[j]; +        e2 &= ~(1<<j); +        while (e2) { +            j = 31 - __builtin_clz(e2); +            e2 &= ~(1<<j); +            track_t& t2 = state->tracks[j]; +            if UNLIKELY(t2.mainBuffer != t1.mainBuffer) { +                e1 &= ~(1<<j); +            } +        } +        e0 &= ~(e1); +        // this assumes output 16 bits stereo, no resampling +        int32_t *out = t1.mainBuffer; +        size_t numFrames = 0; +        do { +            memset(outTemp, 0, sizeof(outTemp)); +            e2 = e1; +            while (e2) { +                const int i = 31 - __builtin_clz(e2); +                e2 &= ~(1<<i); +                track_t& t = state->tracks[i]; +                size_t outFrames = BLOCKSIZE; +                int32_t *aux = NULL; +                if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) { +                    aux = t.auxBuffer + numFrames;                  } -                if (t.frameCount == 0 && outFrames) { -                    t.bufferProvider->releaseBuffer(&t.buffer); -                    t.buffer.frameCount = numFrames - (BLOCKSIZE - outFrames); -                    t.bufferProvider->getNextBuffer(&t.buffer); -                    t.in = t.buffer.raw; -                    if (t.in == NULL) { -                        enabledTracks &= ~(1<<i); -                        break; +                while (outFrames) { +                    size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount; +                    if (inFrames) { +                        (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, aux); +                        t.frameCount -= inFrames; +                        outFrames -= inFrames; +                        if UNLIKELY(aux != NULL) { +                            aux += inFrames; +                        }                      } -                    t.frameCount = t.buffer.frameCount; -                 } +                    if (t.frameCount == 0 && outFrames) { +                        t.bufferProvider->releaseBuffer(&t.buffer); +                        t.buffer.frameCount = (state->frameCount - numFrames) - (BLOCKSIZE - outFrames); +                        t.bufferProvider->getNextBuffer(&t.buffer); +                        t.in = t.buffer.raw; +                        if (t.in == NULL) { +                            enabledTracks &= ~(1<<i); +                            e1 &= ~(1<<i); +                            break; +                        } +                        t.frameCount = t.buffer.frameCount; +                    } +                }              } -        } - -        ditherAndClamp(out, outTemp, BLOCKSIZE); -        out += BLOCKSIZE; -        numFrames -= BLOCKSIZE; -    } while (numFrames); - +            ditherAndClamp(out, outTemp, BLOCKSIZE); +            out += BLOCKSIZE; +            numFrames += BLOCKSIZE; +        } while (numFrames < state->frameCount); +    }      // release each track's buffer -    en = enabledTracks; -    while (en) { -        const int i = 31 - __builtin_clz(en); -        en &= ~(1<<i); +    e0 = enabledTracks; +    while (e0) { +        const int i = 31 - __builtin_clz(e0); +        e0 &= ~(1<<i);          track_t& t = state->tracks[i];          t.bufferProvider->releaseBuffer(&t.buffer);      }  } -// generic code with resampling -void AudioMixer::process__genericResampling(state_t* state, void* output) + +  // generic code with resampling +void AudioMixer::process__genericResampling(state_t* state)  {      int32_t* const outTemp = state->outputTemp;      const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount;      memset(outTemp, 0, size); -    int32_t* out = static_cast<int32_t*>(output);      size_t numFrames = state->frameCount; -    uint32_t en = state->enabledTracks; -    while (en) { -        const int i = 31 - __builtin_clz(en); -        en &= ~(1<<i); -        track_t& t = state->tracks[i]; +    uint32_t e0 = state->enabledTracks; +    while (e0) { +        // process by group of tracks with same output buffer +        // to optimize cache use +        uint32_t e1 = e0, e2 = e0; +        int j = 31 - __builtin_clz(e1); +        track_t& t1 = state->tracks[j]; +        e2 &= ~(1<<j); +        while (e2) { +            j = 31 - __builtin_clz(e2); +            e2 &= ~(1<<j); +            track_t& t2 = state->tracks[j]; +            if UNLIKELY(t2.mainBuffer != t1.mainBuffer) { +                e1 &= ~(1<<j); +            } +        } +        e0 &= ~(e1); +        int32_t *out = t1.mainBuffer; +        while (e1) { +            const int i = 31 - __builtin_clz(e1); +            e1 &= ~(1<<i); +            track_t& t = state->tracks[i]; +            int32_t *aux = NULL; +            if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) { +                aux = t.auxBuffer; +            } -        // this is a little goofy, on the resampling case we don't -        // acquire/release the buffers because it's done by -        // the resampler. -        if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) { -            (t.hook)(&t, outTemp, numFrames, state->resampleTemp); -        } else { +            // this is a little goofy, on the resampling case we don't +            // acquire/release the buffers because it's done by +            // the resampler. +            if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) { +                (t.hook)(&t, outTemp, numFrames, state->resampleTemp, aux); +            } else { -            size_t outFrames = numFrames; -            -            while (outFrames) { -                t.buffer.frameCount = outFrames; -                t.bufferProvider->getNextBuffer(&t.buffer); -                t.in = t.buffer.raw; -                // t.in == NULL can happen if the track was flushed just after having -                // been enabled for mixing. -                if (t.in == NULL) break; - -                (t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp); -                outFrames -= t.buffer.frameCount; -                t.bufferProvider->releaseBuffer(&t.buffer); +                size_t outFrames = 0; + +                while (outFrames < numFrames) { +                    t.buffer.frameCount = numFrames - outFrames; +                    t.bufferProvider->getNextBuffer(&t.buffer); +                    t.in = t.buffer.raw; +                    // t.in == NULL can happen if the track was flushed just after having +                    // been enabled for mixing. +                    if (t.in == NULL) break; + +                    if UNLIKELY(aux != NULL) { +                        aux += outFrames; +                    } +                    (t.hook)(&t, outTemp + outFrames*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, aux); +                    outFrames += t.buffer.frameCount; +                    t.bufferProvider->releaseBuffer(&t.buffer); +                }              }          } +        ditherAndClamp(out, outTemp, numFrames);      } - -    ditherAndClamp(out, outTemp, numFrames);  }  // one track, 16 bits stereo without resampling is the most common case -void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void* output) +void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state)  {      const int i = 31 - __builtin_clz(state->enabledTracks);      const track_t& t = state->tracks[i];      AudioBufferProvider::Buffer& b(t.buffer); -    -    int32_t* out = static_cast<int32_t*>(output); + +    int32_t* out = t.mainBuffer;      size_t numFrames = state->frameCount; -   +      const int16_t vl = t.volume[0];      const int16_t vr = t.volume[1];      const uint32_t vrl = t.volumeRL; @@ -787,7 +1064,7 @@ void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void*              return;          }          size_t outFrames = b.frameCount; -        +          if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {              // volume is boosted, so we might need to clamp even though              // we process only one track. @@ -816,7 +1093,9 @@ void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void*  }  // 2 tracks is also a common case -void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output) +// NEVER used in current implementation of process__validate() +// only use if the 2 tracks have the same output buffer +void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state)  {      int i;      uint32_t en = state->enabledTracks; @@ -829,24 +1108,25 @@ void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void      i = 31 - __builtin_clz(en);      const track_t& t1 = state->tracks[i];      AudioBufferProvider::Buffer& b1(t1.buffer); -    +      int16_t const *in0;      const int16_t vl0 = t0.volume[0];      const int16_t vr0 = t0.volume[1];      size_t frameCount0 = 0; -   +      int16_t const *in1;      const int16_t vl1 = t1.volume[0];      const int16_t vr1 = t1.volume[1];      size_t frameCount1 = 0; -    -    int32_t* out = static_cast<int32_t*>(output); + +    //FIXME: only works if two tracks use same buffer +    int32_t* out = t0.mainBuffer;      size_t numFrames = state->frameCount;      int16_t const *buff = NULL; -   +      while (numFrames) { -    +          if (frameCount0 == 0) {              b0.frameCount = numFrames;              t0.bufferProvider->getNextBuffer(&b0); @@ -875,13 +1155,13 @@ void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void              }              frameCount1 = b1.frameCount;          } -        +          size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1;          numFrames -= outFrames;          frameCount0 -= outFrames;          frameCount1 -= outFrames; -        +          do {              int32_t l0 = *in0++;              int32_t r0 = *in0++; @@ -896,17 +1176,17 @@ void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void              r = clamp16(r);              *out++ = (r<<16) | (l & 0xFFFF);          } while (--outFrames); -        +          if (frameCount0 == 0) {              t0.bufferProvider->releaseBuffer(&b0);          }          if (frameCount1 == 0) {              t1.bufferProvider->releaseBuffer(&b1);          } -    }    -        +    } +      if (buff != NULL) { -        delete [] buff;        +        delete [] buff;      }  } diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h index 15766cddea..aee3e17af3 100644 --- a/libs/audioflinger/AudioMixer.h +++ b/libs/audioflinger/AudioMixer.h @@ -63,11 +63,14 @@ public:          // for target TRACK          CHANNEL_COUNT   = 0x4000,          FORMAT          = 0x4001, +        MAIN_BUFFER     = 0x4002, +        AUX_BUFFER      = 0x4003,          // for TARGET RESAMPLE          SAMPLE_RATE     = 0x4100,          // for TARGET VOLUME (8 channels max)          VOLUME0         = 0x4200,          VOLUME1         = 0x4201, +        AUXLEVEL        = 0x4210,      }; @@ -78,10 +81,10 @@ public:      status_t    disable(int name);      status_t    setActiveTrack(int track); -    status_t    setParameter(int target, int name, int value); +    status_t    setParameter(int target, int name, void *value);      status_t    setBufferProvider(AudioBufferProvider* bufferProvider); -    void        process(void* output); +    void        process();      uint32_t    trackNames() const { return mTrackNames; } @@ -94,6 +97,7 @@ private:          NEEDS_FORMAT__MASK          = 0x000000F0,          NEEDS_MUTE__MASK            = 0x00000100,          NEEDS_RESAMPLE__MASK        = 0x00001000, +        NEEDS_AUX__MASK             = 0x00010000,      };      enum { @@ -107,6 +111,9 @@ private:          NEEDS_RESAMPLE_DISABLED     = 0x00000000,          NEEDS_RESAMPLE_ENABLED      = 0x00001000, + +        NEEDS_AUX_DISABLED     = 0x00000000, +        NEEDS_AUX_ENABLED      = 0x00010000,      };      static inline int32_t applyVolume(int32_t in, int32_t v) { @@ -115,9 +122,10 @@ private:      struct state_t; +    struct track_t; -    typedef void (*mix_t)(state_t* state, void* output); - +    typedef void (*mix_t)(state_t* state); +    typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux);      static const int BLOCKSIZE = 16; // 4 cache lines      struct track_t { @@ -131,6 +139,9 @@ private:          int32_t     prevVolume[2];          int32_t     volumeInc[2]; +        int32_t     auxLevel; +        int32_t     auxInc; +        int32_t     prevAuxLevel;          uint16_t    frameCount; @@ -142,15 +153,17 @@ private:          AudioBufferProvider*                bufferProvider;          mutable AudioBufferProvider::Buffer buffer; -        void (*hook)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp); +        hook_t      hook;          void const* in;             // current location in buffer          AudioResampler*     resampler;          uint32_t            sampleRate; +        int32_t*           mainBuffer; +        int32_t*           auxBuffer;          bool        setResampler(uint32_t sampleRate, uint32_t devSampleRate);          bool        doesResample() const; -        void        adjustVolumeRamp(); +        void        adjustVolumeRamp(bool aux);      };      // pad to 32-bytes to fill cache line @@ -173,18 +186,19 @@ private:      void invalidateState(uint32_t mask); -    static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp); -    static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp); -    static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp); -    static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp); -    static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp); - -    static void process__validate(state_t* state, void* output); -    static void process__nop(state_t* state, void* output); -    static void process__genericNoResampling(state_t* state, void* output); -    static void process__genericResampling(state_t* state, void* output); -    static void process__OneTrack16BitsStereoNoResampling(state_t* state, void* output); -    static void process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output); +    static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux); +    static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux); +    static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux); +    static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux); +    static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux); +    static void volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux); + +    static void process__validate(state_t* state); +    static void process__nop(state_t* state); +    static void process__genericNoResampling(state_t* state); +    static void process__genericResampling(state_t* state); +    static void process__OneTrack16BitsStereoNoResampling(state_t* state); +    static void process__TwoTracks16BitsStereoNoResampling(state_t* state);  };  // ---------------------------------------------------------------------------- diff --git a/libs/audioflinger/AudioPolicyManagerBase.cpp b/libs/audioflinger/AudioPolicyManagerBase.cpp index c8b3f487a0..381a95803b 100644 --- a/libs/audioflinger/AudioPolicyManagerBase.cpp +++ b/libs/audioflinger/AudioPolicyManagerBase.cpp @@ -1249,6 +1249,17 @@ void AudioPolicyManagerBase::closeA2dpOutputs()      LOGV("setDeviceConnectionState() closing A2DP and duplicated output!");      if (mDuplicatedOutput != 0) { +        AudioOutputDescriptor *dupOutputDesc = mOutputs.valueFor(mDuplicatedOutput); +        AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput); +        // As all active tracks on duplicated output will be deleted, +        // and as they were also referenced on hardware output, the reference +        // count for their stream type must be adjusted accordingly on +        // hardware output. +        for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { +            int refCount = dupOutputDesc->mRefCount[i]; +            hwOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount); +        } +          mpClientInterface->closeOutput(mDuplicatedOutput);          delete mOutputs.valueFor(mDuplicatedOutput);          mOutputs.removeItem(mDuplicatedOutput); @@ -1288,11 +1299,6 @@ void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy, u          for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {              if (getStrategy((AudioSystem::stream_type)i) == strategy) {                  mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, mHardwareOutput); -                int refCount = a2dpOutputDesc->mRefCount[i]; -                // in the case of duplicated output, the ref count is first incremented -                // and then decremented on hardware output tus keeping its value -                hwOutputDesc->changeRefCount((AudioSystem::stream_type)i, refCount); -                a2dpOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount);              }          }          // do not change newDevice if it was already set before this call by a previous call to @@ -1318,11 +1324,6 @@ void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy, u          for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {              if (getStrategy((AudioSystem::stream_type)i) == strategy) {                  mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, a2dpOutput); -                int refCount = hwOutputDesc->mRefCount[i]; -                // in the case of duplicated output, the ref count is first incremented -                // and then decremented on hardware output tus keeping its value -                a2dpOutputDesc->changeRefCount((AudioSystem::stream_type)i, refCount); -                hwOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount);              }          }      } diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk index 86eb78d8dd..0879a66de4 100644 --- a/libs/surfaceflinger/Android.mk +++ b/libs/surfaceflinger/Android.mk @@ -13,7 +13,7 @@ LOCAL_SRC_FILES:= \      LayerDim.cpp \      MessageQueue.cpp \      SurfaceFlinger.cpp \ -    Tokenizer.cpp \ +    TextureManager.cpp \      Transform.cpp  LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\" diff --git a/libs/surfaceflinger/Barrier.h b/libs/surfaceflinger/Barrier.h index e2bcf6a049..6f8507e241 100644 --- a/libs/surfaceflinger/Barrier.h +++ b/libs/surfaceflinger/Barrier.h @@ -29,10 +29,6 @@ public:      inline Barrier() : state(CLOSED) { }      inline ~Barrier() { }      void open() { -        // gcc memory barrier, this makes sure all memory writes -        // have been issued by gcc. On an SMP system we'd need a real -        // h/w barrier. -        asm volatile ("":::"memory");          Mutex::Autolock _l(lock);          state = OPENED;          cv.broadcast(); diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp index ea68352828..51de1da723 100644 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -73,7 +73,7 @@ void checkEGLErrors(const char* token)  DisplayHardware::DisplayHardware(          const sp<SurfaceFlinger>& flinger,          uint32_t dpy) -    : DisplayHardwareBase(flinger, dpy) +    : DisplayHardwareBase(flinger, dpy), mFlags(0)  {      init(dpy);  } @@ -125,7 +125,6 @@ void DisplayHardware::init(uint32_t dpy)      EGLint numConfigs=0;      EGLSurface surface;      EGLContext context; -    mFlags = CACHED_BUFFERS;      // TODO: all the extensions below should be queried through      // eglGetProcAddress(). @@ -253,22 +252,10 @@ void DisplayHardware::init(uint32_t dpy)      LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);      LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims); -#if 0 -    // for drivers that don't have proper support for flushing cached buffers -    // on gralloc unlock, uncomment this block and test for the specific -    // renderer substring -    if (strstr(gl_renderer, "<some vendor string>")) { -        LOGD("Assuming uncached graphics buffers."); -        mFlags &= ~CACHED_BUFFERS; -    } -#endif      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; -    }  #ifdef EGL_ANDROID_image_native_buffer      if (strstr( gl_extensions, "GL_OES_EGL_image") &&          (strstr(egl_extensions, "EGL_KHR_image_base") ||  diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h index df046af95a..ebd7c4271c 100644 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h +++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h @@ -46,12 +46,10 @@ public:          DIRECT_TEXTURE          = 0x00000002,          COPY_BITS_EXTENSION     = 0x00000008,          NPOT_EXTENSION          = 0x00000100, -        DRAW_TEXTURE_EXTENSION  = 0x00000200,          BUFFER_PRESERVED        = 0x00010000,          PARTIAL_UPDATES         = 0x00020000,   // video driver feature          SLOW_CONFIG             = 0x00040000,   // software          SWAP_RECTANGLE          = 0x00080000, -        CACHED_BUFFERS          = 0x00100000      };      DisplayHardware( diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp index ce7e9aa3f9..e7247bd90a 100644 --- a/libs/surfaceflinger/Layer.cpp +++ b/libs/surfaceflinger/Layer.cpp @@ -47,47 +47,72 @@ template <typename T> inline T min(T a, T b) {  // --------------------------------------------------------------------------- -const uint32_t Layer::typeInfo = LayerBaseClient::typeInfo | 4; -const char* const Layer::typeID = "Layer"; - -// --------------------------------------------------------------------------- - -Layer::Layer(SurfaceFlinger* flinger, DisplayID display,  -        const sp<Client>& c, int32_t i) -    :   LayerBaseClient(flinger, display, c, i), -        mSecure(false), -        mNoEGLImageForSwBuffers(false), +Layer::Layer(SurfaceFlinger* flinger, +        DisplayID display, const sp<Client>& client) +    :   LayerBaseClient(flinger, display, client),          mNeedsBlending(true), -        mNeedsDithering(false) +        mNeedsDithering(false), +        mSecure(false), +        mTextureManager(mFlags), +        mBufferManager(mTextureManager), +        mWidth(0), mHeight(0), mFixedSize(false)  { -    // no OpenGL operation is possible here, since we might not be -    // in the OpenGL thread. -    mFrontBufferIndex = lcblk->getFrontBuffer();  }  Layer::~Layer()  { -    destroy(); -    // the actual buffers will be destroyed here +    // FIXME: must be called from the main UI thread +    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); +    mBufferManager.destroy(dpy); + +    // we can use getUserClientUnsafe here because we know we're +    // single-threaded at that point. +    sp<UserClient> ourClient(mUserClientRef.getUserClientUnsafe()); +    if (ourClient != 0) { +        ourClient->detachLayer(this); +    }  } -void Layer::destroy() +status_t Layer::setToken(const sp<UserClient>& userClient, +        SharedClient* sharedClient, int32_t token)  { -    for (size_t i=0 ; i<NUM_BUFFERS ; i++) { -        if (mTextures[i].name != -1U) { -            glDeleteTextures(1, &mTextures[i].name); -            mTextures[i].name = -1U; -        } -        if (mTextures[i].image != EGL_NO_IMAGE_KHR) { -            EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); -            eglDestroyImageKHR(dpy, mTextures[i].image); -            mTextures[i].image = EGL_NO_IMAGE_KHR; -        } -        Mutex::Autolock _l(mLock); -        mBuffers[i].clear(); -        mWidth = mHeight = 0; +    sp<SharedBufferServer> lcblk = new SharedBufferServer( +            sharedClient, token, mBufferManager.getDefaultBufferCount(), +            getIdentity()); + +    status_t err = mUserClientRef.setToken(userClient, lcblk, token); + +    LOGE_IF(err != NO_ERROR, +            "ClientRef::setToken(%p, %p, %u) failed", +            userClient.get(), lcblk.get(), token); + +    if (err == NO_ERROR) { +        // we need to free the buffers associated with this surface +    } + +    return err; +} + +int32_t Layer::getToken() const +{ +    return mUserClientRef.getToken(); +} + +sp<UserClient> Layer::getClient() const +{ +    return mUserClientRef.getClient(); +} + +// called with SurfaceFlinger::mStateLock as soon as the layer is entered +// in the purgatory list +void Layer::onRemoved() +{ +    ClientRef::Access sharedClient(mUserClientRef); +    SharedBufferServer* lcblk(sharedClient.get()); +    if (lcblk) { +        // wake up the condition +        lcblk->setStatus(NO_INIT);      } -    mSurface.clear();  }  sp<LayerBaseClient::Surface> Layer::createSurface() const @@ -97,9 +122,17 @@ sp<LayerBaseClient::Surface> Layer::createSurface() const  status_t Layer::ditch()  { +    // NOTE: Called from the main UI thread +      // the layer is not on screen anymore. free as much resources as possible      mFreezeLock.clear(); -    destroy(); + +    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); +    mBufferManager.destroy(dpy); +    mSurface.clear(); + +    Mutex::Autolock _l(mLock); +    mWidth = mHeight = 0;      return NO_ERROR;  } @@ -131,24 +164,19 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h,      mHeight = h;      mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;      mNeedsBlending = (info.h_alpha - info.l_alpha) > 0; -    mNoEGLImageForSwBuffers = !(hwFlags & DisplayHardware::CACHED_BUFFERS);      // we use the red index      int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED);      int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED);      mNeedsDithering = layerRedsize > displayRedSize; -    for (size_t i=0 ; i<NUM_BUFFERS ; i++) { -        mBuffers[i] = new GraphicBuffer(); -    } -    mSurface = new SurfaceLayer(mFlinger, clientIndex(), this); +    mSurface = new SurfaceLayer(mFlinger, this);      return NO_ERROR;  }  void Layer::reloadTexture(const Region& dirty)  { -    Mutex::Autolock _l(mLock); -    sp<GraphicBuffer> buffer(getFrontBufferLocked()); +    sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());      if (buffer == NULL) {          // this situation can happen if we ran out of memory for instance.          // not much we can do. continue to use whatever texture was bound @@ -156,118 +184,24 @@ void Layer::reloadTexture(const Region& dirty)          return;      } -    const int index = mFrontBufferIndex; - -    // create the new texture name if needed -    if (UNLIKELY(mTextures[index].name == -1U)) { -        mTextures[index].name = createTexture(); -        mTextures[index].width = 0; -        mTextures[index].height = 0; -    } -  #ifdef EGL_ANDROID_image_native_buffer      if (mFlags & DisplayHardware::DIRECT_TEXTURE) { -        if (buffer->usage & GraphicBuffer::USAGE_HW_TEXTURE) { -            if (mTextures[index].dirty) { -                if (initializeEglImage(buffer, &mTextures[index]) != NO_ERROR) { -                    // not sure what we can do here... -                    mFlags &= ~DisplayHardware::DIRECT_TEXTURE; -                    goto slowpath; -                } -            } -        } else { -            if (mHybridBuffer==0 || (mHybridBuffer->width != buffer->width || -                    mHybridBuffer->height != buffer->height)) { -                mHybridBuffer.clear(); -                mHybridBuffer = new GraphicBuffer( -                        buffer->width, buffer->height, buffer->format, -                        GraphicBuffer::USAGE_SW_WRITE_OFTEN | -                        GraphicBuffer::USAGE_HW_TEXTURE); -                if (initializeEglImage( -                        mHybridBuffer, &mTextures[0]) != NO_ERROR) { -                    // not sure what we can do here... -                    mFlags &= ~DisplayHardware::DIRECT_TEXTURE; -                    mHybridBuffer.clear(); -                    goto slowpath; -                } -            } - -            GGLSurface t; -            status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN); -            LOGE_IF(res, "error %d (%s) locking buffer %p", -                    res, strerror(res), buffer.get()); -            if (res == NO_ERROR) { -                Texture* const texture(&mTextures[0]); - -                glBindTexture(GL_TEXTURE_2D, texture->name); - -                sp<GraphicBuffer> buf(mHybridBuffer); -                void* vaddr; -                res = buf->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, &vaddr); -                if (res == NO_ERROR) { -                    int bpp = 0; -                    switch (t.format) { -                    case HAL_PIXEL_FORMAT_RGB_565: -                    case HAL_PIXEL_FORMAT_RGBA_4444: -                        bpp = 2; -                        break; -                    case HAL_PIXEL_FORMAT_RGBA_8888: -                    case HAL_PIXEL_FORMAT_RGBX_8888: -                        bpp = 4; -                        break; -                    default: -                        if (isSupportedYuvFormat(t.format)) { -                            // just show the Y plane of YUV buffers -                            bpp = 1; -                            break; -                        } -                        // oops, we don't handle this format! -                        LOGE("layer %p, texture=%d, using format %d, which is not " -                                "supported by the GL", this, texture->name, t.format); -                    } -                    if (bpp) { -                        const Rect bounds(dirty.getBounds()); -                        size_t src_stride = t.stride; -                        size_t dst_stride = buf->stride; -                        if (src_stride == dst_stride && -                            bounds.width() == t.width && -                            bounds.height() == t.height) -                        { -                            memcpy(vaddr, t.data, t.height * t.stride * bpp); -                        } else { -                            GLubyte const * src = t.data + -                                (bounds.left + bounds.top * src_stride) * bpp; -                            GLubyte * dst = (GLubyte *)vaddr + -                                (bounds.left + bounds.top * dst_stride) * bpp; -                            const size_t length = bounds.width() * bpp; -                            size_t h = bounds.height(); -                            src_stride *= bpp; -                            dst_stride *= bpp; -                            while (h--) { -                                memcpy(dst, src, length); -                                dst += dst_stride; -                                src += src_stride; -                            } -                        } -                    } -                    buf->unlock(); -                } -                buffer->unlock(); -            } +        EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); +        if (mBufferManager.initEglImage(dpy, buffer) != NO_ERROR) { +            // not sure what we can do here... +            mFlags &= ~DisplayHardware::DIRECT_TEXTURE; +            goto slowpath;          }      } else  #endif      {  slowpath: -        for (size_t i=0 ; i<NUM_BUFFERS ; i++) { -            mTextures[i].image = EGL_NO_IMAGE_KHR; -        }          GGLSurface t;          status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);          LOGE_IF(res, "error %d (%s) locking buffer %p",                  res, strerror(res), buffer.get());          if (res == NO_ERROR) { -            loadTexture(&mTextures[0], dirty, t); +            mBufferManager.loadTexture(dirty, t);              buffer->unlock();          }      } @@ -275,11 +209,8 @@ slowpath:  void Layer::onDraw(const Region& clip) const  { -    int index = mFrontBufferIndex; -    if (mTextures[index].image == EGL_NO_IMAGE_KHR) -        index = 0; -    GLuint textureName = mTextures[index].name; -    if (UNLIKELY(textureName == -1LU)) { +    Texture tex(mBufferManager.getActiveTexture()); +    if (tex.name == -1LU) {          // the texture has not been created yet, this Layer has          // in fact never been drawn into. This happens frequently with          // SurfaceView because the WindowManager can't know when the client @@ -305,17 +236,57 @@ void Layer::onDraw(const Region& clip) const          }          return;      } -    drawWithOpenGL(clip, mTextures[index]); +    drawWithOpenGL(clip, tex); +} + +bool Layer::needsFiltering() const +{ +    if (!(mFlags & DisplayHardware::SLOW_CONFIG)) { +        // NOTE: there is a race here, because mFixedSize is updated in a +        // binder transaction. however, it doesn't really matter since it is +        // evaluated each time we draw. To be perfectly correct, this flag +        // would have to be associated with a buffer. +        if (mFixedSize) +            return true; +    } +    return LayerBase::needsFiltering();  } -sp<GraphicBuffer> Layer::requestBuffer(int index, int usage) + +status_t Layer::setBufferCount(int bufferCount) +{ +    ClientRef::Access sharedClient(mUserClientRef); +    SharedBufferServer* lcblk(sharedClient.get()); +    if (!lcblk) { +        // oops, the client is already gone +        return DEAD_OBJECT; +    } + +    // NOTE: lcblk->resize() is protected by an internal lock +    status_t err = lcblk->resize(bufferCount); +    if (err == NO_ERROR) +        mBufferManager.resize(bufferCount); + +    return err; +} + +sp<GraphicBuffer> Layer::requestBuffer(int index, +        uint32_t reqWidth, uint32_t reqHeight, uint32_t reqFormat, +        uint32_t usage)  {      sp<GraphicBuffer> buffer; +    if (int32_t(reqWidth | reqHeight | reqFormat) < 0) +        return buffer; + +    if ((!reqWidth && reqHeight) || (reqWidth && !reqHeight)) +        return buffer; +      // this ensures our client doesn't go away while we're accessing      // the shared area. -    sp<Client> ourClient(client.promote()); -    if (ourClient == 0) { +    ClientRef::Access sharedClient(mUserClientRef); +    SharedBufferServer* lcblk(sharedClient.get()); +    if (!lcblk) {          // oops, the client is already gone          return buffer;      } @@ -324,7 +295,7 @@ sp<GraphicBuffer> Layer::requestBuffer(int index, int usage)       * This is called from the client's Surface::dequeue(). This can happen       * at any time, especially while we're in the middle of using the       * buffer 'index' as our front buffer. -     *  +     *       * Make sure the buffer we're resizing is not the front buffer and has been       * dequeued. Once this condition is asserted, we are guaranteed that this       * buffer cannot become the front buffer under our feet, since we're called @@ -337,31 +308,33 @@ sp<GraphicBuffer> Layer::requestBuffer(int index, int usage)          return buffer;      } -    uint32_t w, h; +    uint32_t w, h, f;      { // scope for the lock          Mutex::Autolock _l(mLock); -        w = mWidth; -        h = mHeight; -        buffer = mBuffers[index]; -         -        // destroy() could have been called before we get here, we log it -        // because it's uncommon, and the code below should handle it -        LOGW_IF(buffer==0,  -                "mBuffers[%d] is null (mWidth=%d, mHeight=%d)", -                index, w, h); -         -        mBuffers[index].clear(); +        const bool fixedSizeChanged = mFixedSize != (reqWidth && reqHeight); +        const bool formatChanged    = mReqFormat != reqFormat; +        mReqWidth  = reqWidth; +        mReqHeight = reqHeight; +        mReqFormat = reqFormat; +        mFixedSize = reqWidth && reqHeight; +        w = reqWidth  ? reqWidth  : mWidth; +        h = reqHeight ? reqHeight : mHeight; +        f = reqFormat ? reqFormat : mFormat; +        buffer = mBufferManager.detachBuffer(index); +        if (fixedSizeChanged || formatChanged) { +            lcblk->reallocateAllExcept(index); +        }      }      const uint32_t effectiveUsage = getEffectiveUsage(usage);      if (buffer!=0 && buffer->getStrongCount() == 1) { -        err = buffer->reallocate(w, h, mFormat, effectiveUsage); +        err = buffer->reallocate(w, h, f, effectiveUsage);      } else {          // here we have to reallocate a new buffer because we could have a          // client in our process with a reference to it (eg: status bar),          // and we can't release the handle under its feet.          buffer.clear(); -        buffer = new GraphicBuffer(w, h, mFormat, effectiveUsage); +        buffer = new GraphicBuffer(w, h, f, effectiveUsage);          err = buffer->initCheck();      } @@ -377,15 +350,7 @@ sp<GraphicBuffer> Layer::requestBuffer(int index, int usage)      if (err == NO_ERROR && buffer->handle != 0) {          Mutex::Autolock _l(mLock); -        if (mWidth && mHeight) { -            // and we have new buffer -            mBuffers[index] = buffer; -            // texture is now dirty... -            mTextures[index].dirty = true; -        } else { -            // oops we got killed while we were allocating the buffer -            buffer.clear(); -        } +        mBufferManager.attachBuffer(index, buffer);      }      return buffer;  } @@ -411,15 +376,8 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const      } else {          // it's allowed to modify the usage flags here, but generally          // the requested flags should be honored. -        if (mNoEGLImageForSwBuffers) { -            if (usage & GraphicBuffer::USAGE_HW_MASK) { -                // request EGLImage for h/w buffers only -                usage |= GraphicBuffer::USAGE_HW_TEXTURE; -            } -        } else { -            // request EGLImage for all buffers -            usage |= GraphicBuffer::USAGE_HW_TEXTURE; -        } +        // request EGLImage for all buffers +        usage |= GraphicBuffer::USAGE_HW_TEXTURE;      }      return usage;  } @@ -429,42 +387,50 @@ uint32_t Layer::doTransaction(uint32_t flags)      const Layer::State& front(drawingState());      const Layer::State& temp(currentState()); -    if ((front.requested_w != temp.requested_w) ||  -        (front.requested_h != temp.requested_h)) { +    const bool sizeChanged = (front.requested_w != temp.requested_w) || +            (front.requested_h != temp.requested_h); + +    if (sizeChanged) {          // the size changed, we need to ask our client to request a new buffer          LOGD_IF(DEBUG_RESIZE, -                    "resize (layer=%p), requested (%dx%d), " -                    "drawing (%d,%d), (%dx%d), (%dx%d)", -                    this,  -                    int(temp.requested_w), int(temp.requested_h), -                    int(front.requested_w), int(front.requested_h), -                    int(mBuffers[0]->getWidth()), int(mBuffers[0]->getHeight()), -                    int(mBuffers[1]->getWidth()), int(mBuffers[1]->getHeight())); - -        // we're being resized and there is a freeze display request, -        // acquire a freeze lock, so that the screen stays put -        // until we've redrawn at the new size; this is to avoid -        // glitches upon orientation changes. -        if (mFlinger->hasFreezeRequest()) { -            // if the surface is hidden, don't try to acquire the -            // freeze lock, since hidden surfaces may never redraw -            if (!(front.flags & ISurfaceComposer::eLayerHidden)) { -                mFreezeLock = mFlinger->getFreezeLock(); +                "resize (layer=%p), requested (%dx%d), drawing (%d,%d)", +                this, +                int(temp.requested_w), int(temp.requested_h), +                int(front.requested_w), int(front.requested_h)); + +        if (!isFixedSize()) { +            // we're being resized and there is a freeze display request, +            // acquire a freeze lock, so that the screen stays put +            // until we've redrawn at the new size; this is to avoid +            // glitches upon orientation changes. +            if (mFlinger->hasFreezeRequest()) { +                // if the surface is hidden, don't try to acquire the +                // freeze lock, since hidden surfaces may never redraw +                if (!(front.flags & ISurfaceComposer::eLayerHidden)) { +                    mFreezeLock = mFlinger->getFreezeLock(); +                }              } -        } - -        // this will make sure LayerBase::doTransaction doesn't update -        // the drawing state's size -        Layer::State& editDraw(mDrawingState); -        editDraw.requested_w = temp.requested_w; -        editDraw.requested_h = temp.requested_h; -        // record the new size, form this point on, when the client request a -        // buffer, it'll get the new size. -        setDrawingSize(temp.requested_w, temp.requested_h); - -        // all buffers need reallocation -        lcblk->reallocate(); +            // this will make sure LayerBase::doTransaction doesn't update +            // the drawing state's size +            Layer::State& editDraw(mDrawingState); +            editDraw.requested_w = temp.requested_w; +            editDraw.requested_h = temp.requested_h; + +            // record the new size, form this point on, when the client request +            // a buffer, it'll get the new size. +            setBufferSize(temp.requested_w, temp.requested_h); + +            ClientRef::Access sharedClient(mUserClientRef); +            SharedBufferServer* lcblk(sharedClient.get()); +            if (lcblk) { +                // all buffers need reallocation +                lcblk->reallocateAll(); +            } +        } else { +            // record the new size +            setBufferSize(temp.requested_w, temp.requested_h); +        }      }      if (temp.sequence != front.sequence) { @@ -478,35 +444,51 @@ uint32_t Layer::doTransaction(uint32_t flags)      return LayerBase::doTransaction(flags);  } -void Layer::setDrawingSize(uint32_t w, uint32_t h) { +void Layer::setBufferSize(uint32_t w, uint32_t h) {      Mutex::Autolock _l(mLock);      mWidth = w;      mHeight = h;  } +bool Layer::isFixedSize() const { +    Mutex::Autolock _l(mLock); +    return mFixedSize; +} +  // ----------------------------------------------------------------------------  // pageflip handling...  // ----------------------------------------------------------------------------  void Layer::lockPageFlip(bool& recomputeVisibleRegions)  { +    ClientRef::Access sharedClient(mUserClientRef); +    SharedBufferServer* lcblk(sharedClient.get()); +    if (!lcblk) { +        // client died +        recomputeVisibleRegions = true; +        return; +    } +      ssize_t buf = lcblk->retireAndLock(); -    if (buf < NO_ERROR) { -        //LOGW("nothing to retire (%s)", strerror(-buf)); -        // NOTE: here the buffer is locked because we will used  +    if (buf == NOT_ENOUGH_DATA) { +        // NOTE: This is not an error, it simply means there is nothing to +        // retire. The buffer is locked because we will use it          // for composition later in the loop          return;      } -    // ouch, this really should never happen -    if (uint32_t(buf)>=NUM_BUFFERS) { -        LOGE("retireAndLock() buffer index (%d) out of range", buf); +    if (buf < NO_ERROR) { +        LOGE("retireAndLock() buffer index (%d) out of range", int(buf));          mPostedDirtyRegion.clear();          return;      }      // we retired a buffer, which becomes the new front buffer -    mFrontBufferIndex = buf; +    if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) { +        LOGE("retireAndLock() buffer index (%d) out of range", int(buf)); +        mPostedDirtyRegion.clear(); +        return; +    }      // get the dirty region      sp<GraphicBuffer> newFrontBuffer(getBuffer(buf)); @@ -559,9 +541,15 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)          mFlinger->signalEvent();      } -    if (!mPostedDirtyRegion.isEmpty()) { -        reloadTexture( mPostedDirtyRegion ); -    } +    /* a buffer was posted, so we need to call reloadTexture(), which +     * will update our internal data structures (eg: EGLImageKHR or +     * texture names). we need to do this even if mPostedDirtyRegion is +     * empty -- it's orthogonal to the fact that a new buffer was posted, +     * for instance, a degenerate case could be that the user did an empty +     * update but repainted the buffer with appropriate content (after a +     * resize for instance). +     */ +    reloadTexture( mPostedDirtyRegion );  }  void Layer::unlockPageFlip( @@ -585,24 +573,260 @@ void Layer::unlockPageFlip(      }      if (visibleRegionScreen.isEmpty()) {          // an invisible layer should not hold a freeze-lock -        // (because it may never be updated and thereore never release it) +        // (because it may never be updated and therefore never release it)          mFreezeLock.clear();      }  }  void Layer::finishPageFlip()  { -    status_t err = lcblk->unlock( mFrontBufferIndex ); -    LOGE_IF(err!=NO_ERROR,  -            "layer %p, buffer=%d wasn't locked!", -            this, mFrontBufferIndex); +    ClientRef::Access sharedClient(mUserClientRef); +    SharedBufferServer* lcblk(sharedClient.get()); +    if (lcblk) { +        int buf = mBufferManager.getActiveBufferIndex(); +        if (buf >= 0) { +            status_t err = lcblk->unlock( buf ); +            LOGE_IF(err!=NO_ERROR, +                    "layer %p, buffer=%d wasn't locked!", +                    this, buf); +        } +    } +} + + +void Layer::dump(String8& result, char* buffer, size_t SIZE) const +{ +    LayerBaseClient::dump(result, buffer, SIZE); + +    ClientRef::Access sharedClient(mUserClientRef); +    SharedBufferServer* lcblk(sharedClient.get()); +    uint32_t totalTime = 0; +    if (lcblk) { +        SharedBufferStack::Statistics stats = lcblk->getStats(); +        totalTime= stats.totalTime; +        result.append( lcblk->dump("      ") ); +    } + +    sp<const GraphicBuffer> buf0(getBuffer(0)); +    sp<const GraphicBuffer> buf1(getBuffer(1)); +    uint32_t w0=0, h0=0, s0=0; +    uint32_t w1=0, h1=0, s1=0; +    if (buf0 != 0) { +        w0 = buf0->getWidth(); +        h0 = buf0->getHeight(); +        s0 = buf0->getStride(); +    } +    if (buf1 != 0) { +        w1 = buf1->getWidth(); +        h1 = buf1->getHeight(); +        s1 = buf1->getStride(); +    } +    snprintf(buffer, SIZE, +            "      " +            "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u]," +            " freezeLock=%p, dq-q-time=%u us\n", +            mFormat, w0, h0, s0, w1, h1, s1, +            getFreezeLock().get(), totalTime); + +    result.append(buffer); +} + +// --------------------------------------------------------------------------- + +Layer::ClientRef::ClientRef() +    : mControlBlock(0), mToken(-1) { +} + +Layer::ClientRef::~ClientRef() { +} + +int32_t Layer::ClientRef::getToken() const { +    Mutex::Autolock _l(mLock); +    return mToken; +} + +sp<UserClient> Layer::ClientRef::getClient() const { +    Mutex::Autolock _l(mLock); +    return mUserClient.promote(); +} + +status_t Layer::ClientRef::setToken(const sp<UserClient>& uc, +        const sp<SharedBufferServer>& sharedClient, int32_t token) { +    Mutex::Autolock _l(mLock); + +    { // scope for strong mUserClient reference +        sp<UserClient> userClient(mUserClient.promote()); +        if (mUserClient != 0 && mControlBlock != 0) { +            mControlBlock->setStatus(NO_INIT); +        } +    } + +    mUserClient = uc; +    mToken = token; +    mControlBlock = sharedClient; +    return NO_ERROR; +} + +sp<UserClient> Layer::ClientRef::getUserClientUnsafe() const { +    return mUserClient.promote(); +} + +// this class gives us access to SharedBufferServer safely +// it makes sure the UserClient (and its associated shared memory) +// won't go away while we're accessing it. +Layer::ClientRef::Access::Access(const ClientRef& ref) +    : mControlBlock(0) +{ +    Mutex::Autolock _l(ref.mLock); +    mUserClientStrongRef = ref.mUserClient.promote(); +    if (mUserClientStrongRef != 0) +        mControlBlock = ref.mControlBlock; +} + +Layer::ClientRef::Access::~Access() +{ +} + +// --------------------------------------------------------------------------- + +Layer::BufferManager::BufferManager(TextureManager& tm) +    : mNumBuffers(NUM_BUFFERS), mTextureManager(tm), +      mActiveBuffer(-1), mFailover(false) +{ +} + +Layer::BufferManager::~BufferManager() +{ +} + +status_t Layer::BufferManager::resize(size_t size) +{ +    Mutex::Autolock _l(mLock); +    mNumBuffers = size; +    return NO_ERROR; +} + +// only for debugging +sp<GraphicBuffer> Layer::BufferManager::getBuffer(size_t index) const { +    return mBufferData[index].buffer; +} + +status_t Layer::BufferManager::setActiveBufferIndex(size_t index) { +    mActiveBuffer = index; +    return NO_ERROR; +} + +size_t Layer::BufferManager::getActiveBufferIndex() const { +    return mActiveBuffer; +} + +Texture Layer::BufferManager::getActiveTexture() const { +    Texture res; +    if (mFailover || mActiveBuffer<0) { +        res = mFailoverTexture; +    } else { +        static_cast<Image&>(res) = mBufferData[mActiveBuffer].texture; +    } +    return res; +} + +sp<GraphicBuffer> Layer::BufferManager::getActiveBuffer() const { +    sp<GraphicBuffer> result; +    const ssize_t activeBuffer = mActiveBuffer; +    if (activeBuffer >= 0) { +        BufferData const * const buffers = mBufferData; +        Mutex::Autolock _l(mLock); +        result = buffers[activeBuffer].buffer; +    } +    return result; +} + +sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index) +{ +    BufferData* const buffers = mBufferData; +    sp<GraphicBuffer> buffer; +    Mutex::Autolock _l(mLock); +    buffer = buffers[index].buffer; +    buffers[index].buffer = 0; +    return buffer; +} + +status_t Layer::BufferManager::attachBuffer(size_t index, +        const sp<GraphicBuffer>& buffer) +{ +    BufferData* const buffers = mBufferData; +    Mutex::Autolock _l(mLock); +    buffers[index].buffer = buffer; +    buffers[index].texture.dirty = true; +    return NO_ERROR; +} + +status_t Layer::BufferManager::destroy(EGLDisplay dpy) +{ +    BufferData* const buffers = mBufferData; +    size_t num; +    { // scope for the lock +        Mutex::Autolock _l(mLock); +        num = mNumBuffers; +        for (size_t i=0 ; i<num ; i++) { +            buffers[i].buffer = 0; +        } +    } +    for (size_t i=0 ; i<num ; i++) { +        destroyTexture(&buffers[i].texture, dpy); +    } +    destroyTexture(&mFailoverTexture, dpy); +    return NO_ERROR; +} + +status_t Layer::BufferManager::initEglImage(EGLDisplay dpy, +        const sp<GraphicBuffer>& buffer) +{ +    status_t err = NO_INIT; +    ssize_t index = mActiveBuffer; +    if (index >= 0) { +        Image& texture(mBufferData[index].texture); +        err = mTextureManager.initEglImage(&texture, dpy, buffer); +        // if EGLImage fails, we switch to regular texture mode, and we +        // free all resources associated with using EGLImages. +        if (err == NO_ERROR) { +            mFailover = false; +            destroyTexture(&mFailoverTexture, dpy); +        } else { +            mFailover = true; +            const size_t num = mNumBuffers; +            for (size_t i=0 ; i<num ; i++) { +                destroyTexture(&mBufferData[i].texture, dpy); +            } +        } +    } +    return err; +} + +status_t Layer::BufferManager::loadTexture( +        const Region& dirty, const GGLSurface& t) +{ +    return mTextureManager.loadTexture(&mFailoverTexture, dirty, t); +} + +status_t Layer::BufferManager::destroyTexture(Image* tex, EGLDisplay dpy) +{ +    if (tex->name != -1U) { +        glDeleteTextures(1, &tex->name); +        tex->name = -1U; +    } +    if (tex->image != EGL_NO_IMAGE_KHR) { +        eglDestroyImageKHR(dpy, tex->image); +        tex->image = EGL_NO_IMAGE_KHR; +    } +    return NO_ERROR;  }  // ---------------------------------------------------------------------------  Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger, -        SurfaceID id, const sp<Layer>& owner) -    : Surface(flinger, id, owner->getIdentity(), owner) +        const sp<Layer>& owner) +    : Surface(flinger, owner->getIdentity(), owner)  {  } @@ -610,20 +834,37 @@ Layer::SurfaceLayer::~SurfaceLayer()  {  } -sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, int usage) +sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, +        uint32_t w, uint32_t h, uint32_t format, uint32_t usage)  {      sp<GraphicBuffer> buffer;      sp<Layer> owner(getOwner());      if (owner != 0) { -        LOGE_IF(uint32_t(index)>=NUM_BUFFERS, -                "getBuffer() index (%d) out of range", index); -        if (uint32_t(index) < NUM_BUFFERS) { -            buffer = owner->requestBuffer(index, usage); -        } +        /* +         * requestBuffer() cannot be called from the main thread +         * as it could cause a dead-lock, since it may have to wait +         * on conditions updated my the main thread. +         */ +        buffer = owner->requestBuffer(index, w, h, format, usage);      }      return buffer;  } +status_t Layer::SurfaceLayer::setBufferCount(int bufferCount) +{ +    status_t err = DEAD_OBJECT; +    sp<Layer> owner(getOwner()); +    if (owner != 0) { +        /* +         * setBufferCount() cannot be called from the main thread +         * as it could cause a dead-lock, since it may have to wait +         * on conditions updated my the main thread. +         */ +        err = owner->setBufferCount(bufferCount); +    } +    return err; +} +  // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h index 743afb4c47..dcb27a002b 100644 --- a/libs/surfaceflinger/Layer.h +++ b/libs/surfaceflinger/Layer.h @@ -31,36 +31,42 @@  #include "LayerBase.h"  #include "Transform.h" +#include "TextureManager.h"  namespace android {  // ---------------------------------------------------------------------------  class Client; +class UserClient;  class FreezeLock;  // --------------------------------------------------------------------------- -const size_t NUM_BUFFERS = 2; -  class Layer : public LayerBaseClient  { -public:     -    static const uint32_t typeInfo; -    static const char* const typeID; -    virtual char const* getTypeID() const { return typeID; } -    virtual uint32_t getTypeInfo() const { return typeInfo; } -     -                 Layer(SurfaceFlinger* flinger, DisplayID display, -                         const sp<Client>& client, int32_t i); +public: +            Layer(SurfaceFlinger* flinger, DisplayID display, +                    const sp<Client>& client); + +    virtual ~Layer(); -        virtual ~Layer(); +    virtual const char* getTypeId() const { return "Layer"; } +    // the this layer's size and format      status_t setBuffers(uint32_t w, uint32_t h,               PixelFormat format, uint32_t flags=0); -    void setDrawingSize(uint32_t w, uint32_t h); +    // associate a UserClient to this Layer +    status_t setToken(const sp<UserClient>& uc, SharedClient* sc, int32_t idx); +    int32_t getToken() const; +    sp<UserClient> getClient() const; + +    // Set this Layer's buffers size +    void setBufferSize(uint32_t w, uint32_t h); +    bool isFixedSize() const; +    // LayerBase interface      virtual void onDraw(const Region& clip) const;      virtual uint32_t doTransaction(uint32_t transactionFlags);      virtual void lockPageFlip(bool& recomputeVisibleRegions); @@ -68,63 +74,160 @@ public:      virtual void finishPageFlip();      virtual bool needsBlending() const      { return mNeedsBlending; }      virtual bool needsDithering() const     { return mNeedsDithering; } +    virtual bool needsFiltering() const;      virtual bool isSecure() const           { return mSecure; }      virtual sp<Surface> createSurface() const;      virtual status_t ditch(); -     -    // only for debugging -    inline sp<GraphicBuffer> getBuffer(int i) { return mBuffers[i]; } -    // only for debugging -    inline const sp<FreezeLock>&  getFreezeLock() const { return mFreezeLock; } +    virtual void onRemoved(); +      // only for debugging -    inline PixelFormat pixelFormat() const { return mFormat; } +    inline sp<GraphicBuffer> getBuffer(int i) const { +        return mBufferManager.getBuffer(i); }      // only for debugging -    inline int getFrontBufferIndex() const { return mFrontBufferIndex; } +    inline const sp<FreezeLock>&  getFreezeLock() const { +        return mFreezeLock; } + +protected: +    virtual void dump(String8& result, char* scratch, size_t size) const;  private: -    inline sp<GraphicBuffer> getFrontBufferLocked() { -        return mBuffers[mFrontBufferIndex]; -    } -       void reloadTexture(const Region& dirty); -      uint32_t getEffectiveUsage(uint32_t usage) const; +    sp<GraphicBuffer> requestBuffer(int bufferIdx, +            uint32_t w, uint32_t h, uint32_t format, uint32_t usage); +    status_t setBufferCount(int bufferCount); -    sp<GraphicBuffer> requestBuffer(int index, int usage); -    void destroy(); +    // -----------------------------------------------------------------------      class SurfaceLayer : public LayerBaseClient::Surface {      public: -        SurfaceLayer(const sp<SurfaceFlinger>& flinger, -                SurfaceID id, const sp<Layer>& owner); +        SurfaceLayer(const sp<SurfaceFlinger>& flinger, const sp<Layer>& owner);          ~SurfaceLayer();      private: -        virtual sp<GraphicBuffer> requestBuffer(int index, int usage); +        virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, +                uint32_t w, uint32_t h, uint32_t format, uint32_t usage); +        virtual status_t setBufferCount(int bufferCount);          sp<Layer> getOwner() const {              return static_cast<Layer*>(Surface::getOwner().get());          }      };      friend class SurfaceLayer; -     -    sp<Surface>             mSurface; - -            bool            mSecure; -            bool            mNoEGLImageForSwBuffers; -            int32_t         mFrontBufferIndex; -            bool            mNeedsBlending; -            bool            mNeedsDithering; -            Region          mPostedDirtyRegion; -            sp<FreezeLock>  mFreezeLock; -            PixelFormat     mFormat; -             -            // protected by mLock -            sp<GraphicBuffer> mBuffers[NUM_BUFFERS]; -            Texture         mTextures[NUM_BUFFERS]; -            sp<GraphicBuffer> mHybridBuffer; -            uint32_t        mWidth; -            uint32_t        mHeight; -             -   mutable Mutex mLock; + +    // ----------------------------------------------------------------------- + +    class ClientRef { +        ClientRef(const ClientRef& rhs); +        ClientRef& operator = (const ClientRef& rhs); +        mutable Mutex mLock; +        // binder thread, page-flip thread +        sp<SharedBufferServer> mControlBlock; +        wp<UserClient> mUserClient; +        int32_t mToken; +    public: +        ClientRef(); +        ~ClientRef(); +        int32_t getToken() const; +        sp<UserClient> getClient() const; +        status_t setToken(const sp<UserClient>& uc, +                const sp<SharedBufferServer>& sharedClient, int32_t token); +        sp<UserClient> getUserClientUnsafe() const; +        class Access { +            Access(const Access& rhs); +            Access& operator = (const Access& rhs); +            sp<UserClient> mUserClientStrongRef; +            sp<SharedBufferServer> mControlBlock; +        public: +            Access(const ClientRef& ref); +            ~Access(); +            inline SharedBufferServer* get() const { return mControlBlock.get(); } +        }; +        friend class Access; +    }; + +    // ----------------------------------------------------------------------- + +    class BufferManager { +        static const size_t NUM_BUFFERS = 2; +        struct BufferData { +            sp<GraphicBuffer>   buffer; +            Image               texture; +        }; +        // this lock protect mBufferData[].buffer but since there +        // is very little contention, we have only one like for +        // the whole array, we also use it to protect mNumBuffers. +        mutable Mutex mLock; +        BufferData          mBufferData[SharedBufferStack::NUM_BUFFER_MAX]; +        size_t              mNumBuffers; +        Texture             mFailoverTexture; +        TextureManager&     mTextureManager; +        ssize_t             mActiveBuffer; +        bool                mFailover; +        static status_t destroyTexture(Image* tex, EGLDisplay dpy); + +    public: +        static size_t getDefaultBufferCount() { return NUM_BUFFERS; } +        BufferManager(TextureManager& tm); +        ~BufferManager(); + +        // detach/attach buffer from/to given index +        sp<GraphicBuffer> detachBuffer(size_t index); +        status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer); +        // resize the number of active buffers +        status_t resize(size_t size); + +        // ---------------------------------------------- +        // must be called from GL thread + +        // set/get active buffer index +        status_t setActiveBufferIndex(size_t index); +        size_t getActiveBufferIndex() const; +        // return the active buffer +        sp<GraphicBuffer> getActiveBuffer() const; +        // return the active texture (or fail-over) +        Texture getActiveTexture() const; +        // frees resources associated with all buffers +        status_t destroy(EGLDisplay dpy); +        // load bitmap data into the active buffer +        status_t loadTexture(const Region& dirty, const GGLSurface& t); +        // make active buffer an EGLImage if needed +        status_t initEglImage(EGLDisplay dpy, +                const sp<GraphicBuffer>& buffer); + +        // ---------------------------------------------- +        // only for debugging +        sp<GraphicBuffer> getBuffer(size_t index) const; +    }; + +    // ----------------------------------------------------------------------- + +    // thread-safe +    ClientRef mUserClientRef; + +    // constants +    sp<Surface> mSurface; +    PixelFormat mFormat; +    bool mNeedsBlending; +    bool mNeedsDithering; + +    // page-flip thread (currently main thread) +    bool mSecure; +    Region mPostedDirtyRegion; + +    // page-flip thread and transaction thread (currently main thread) +    sp<FreezeLock>  mFreezeLock; + +    // see threading usage in declaration +    TextureManager mTextureManager; +    BufferManager mBufferManager; + +    // binder thread, transaction thread +    mutable Mutex mLock; +    uint32_t mWidth; +    uint32_t mHeight; +    uint32_t mReqWidth; +    uint32_t mReqHeight; +    uint32_t mReqFormat; +    bool mFixedSize;  };  // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp index a8b735ef6a..1f66fd0296 100644 --- a/libs/surfaceflinger/LayerBase.cpp +++ b/libs/surfaceflinger/LayerBase.cpp @@ -32,29 +32,21 @@  #include "LayerBase.h"  #include "SurfaceFlinger.h"  #include "DisplayHardware/DisplayHardware.h" +#include "TextureManager.h"  namespace android {  // --------------------------------------------------------------------------- -const uint32_t LayerBase::typeInfo = 1; -const char* const LayerBase::typeID = "LayerBase"; - -const uint32_t LayerBaseClient::typeInfo = LayerBase::typeInfo | 2; -const char* const LayerBaseClient::typeID = "LayerBaseClient"; - -// --------------------------------------------------------------------------- -  LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)      : dpy(display), contentDirty(false),        mFlinger(flinger), -      mTransformed(false), -      mUseLinearFiltering(false), +      mNeedsFiltering(false),        mOrientation(0),        mLeft(0), mTop(0),        mTransactionFlags(0), -      mPremultipliedAlpha(true), mDebug(false), +      mPremultipliedAlpha(true), mName("unnamed"), mDebug(false),        mInvalidate(0)  {      const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware()); @@ -159,7 +151,6 @@ bool LayerBase::setAlpha(uint8_t alpha) {      return true;  }  bool LayerBase::setMatrix(const layer_state_t::matrix22_t& matrix) { -    // TODO: check the matrix has changed      mCurrentState.sequence++;      mCurrentState.transform.set(              matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy); @@ -167,7 +158,6 @@ bool LayerBase::setMatrix(const layer_state_t::matrix22_t& matrix) {      return true;  }  bool LayerBase::setTransparentRegionHint(const Region& transparent) { -    // TODO: check the region has changed      mCurrentState.sequence++;      mCurrentState.transparentRegion = transparent;      requestTransaction(); @@ -221,13 +211,12 @@ uint32_t LayerBase::doTransaction(uint32_t flags)          flags |= eVisibleRegion;          this->contentDirty = true; -        const bool linearFiltering = mUseLinearFiltering; -        mUseLinearFiltering = false; +        mNeedsFiltering = false;          if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {              // we may use linear filtering, if the matrix scales us              const uint8_t type = temp.transform.getType();              if (!temp.transform.preserveRects() || (type >= Transform::SCALE)) { -                mUseLinearFiltering = true; +                mNeedsFiltering = true;              }          }      } @@ -267,7 +256,6 @@ void LayerBase::validateVisibility(const Transform& planeTransform)      // cache a few things...      mOrientation = tr.getOrientation();      mTransformedBounds = tr.makeBounds(w, h); -    mTransformed = transformed;      mLeft = tr.tx();      mTop  = tr.ty();  } @@ -348,25 +336,13 @@ void LayerBase::draw(const Region& inClip) const      */  } -GLuint LayerBase::createTexture() const -{ -    GLuint textureName = -1; -    glGenTextures(1, &textureName); -    glBindTexture(GL_TEXTURE_2D, textureName); -    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); -    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -    return textureName; -} - -void LayerBase::clearWithOpenGL(const Region& clip, GLclampx red, -                                GLclampx green, GLclampx blue, -                                GLclampx alpha) const +void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red, +                                GLclampf green, GLclampf blue, +                                GLclampf alpha) const  {      const DisplayHardware& hw(graphicPlane(0).displayHardware());      const uint32_t fbHeight = hw.getHeight(); -    glColor4x(red,green,blue,alpha); +    glColor4f(red,green,blue,alpha);      glDisable(GL_TEXTURE_2D);      glDisable(GL_BLEND);      glDisable(GL_DITHER); @@ -374,7 +350,7 @@ void LayerBase::clearWithOpenGL(const Region& clip, GLclampx red,      Region::const_iterator it = clip.begin();      Region::const_iterator const end = clip.end();      glEnable(GL_SCISSOR_TEST); -    glVertexPointer(2, GL_FIXED, 0, mVertices); +    glVertexPointer(2, GL_FLOAT, 0, mVertices);      while (it != end) {          const Rect& r = *it++;          const GLint sy = fbHeight - (r.top + r.height()); @@ -401,33 +377,21 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const      glEnable(GL_TEXTURE_2D); +    GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;      if (UNLIKELY(s.alpha < 0xFF)) { -        // We have an alpha-modulation. We need to modulate all -        // texture components by alpha because we're always using  -        // premultiplied alpha. -         -        // If the texture doesn't have an alpha channel we can -        // use REPLACE and switch to non premultiplied alpha -        // blending (SRCA/ONE_MINUS_SRCA). -         -        GLenum env, src; -        if (needsBlending()) { -            env = GL_MODULATE; -            src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; +        const GLfloat alpha = s.alpha * (1.0f/255.0f); +        if (mPremultipliedAlpha) { +            glColor4f(alpha, alpha, alpha, alpha);          } else { -            env = GL_REPLACE; -            src = GL_SRC_ALPHA; +            glColor4f(1, 1, 1, alpha);          } -        const GGLfixed alpha = (s.alpha << 16)/255; -        glColor4x(alpha, alpha, alpha, alpha);          glEnable(GL_BLEND);          glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA); -        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env); +        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);      } else { +        glColor4f(1, 1, 1, 1);          glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); -        glColor4x(0x10000, 0x10000, 0x10000, 0x10000);          if (needsBlending()) { -            GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;              glEnable(GL_BLEND);              glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);          } else { @@ -437,13 +401,11 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const      Region::const_iterator it = clip.begin();      Region::const_iterator const end = clip.end(); - -    //StopWatch watch("GL transformed"); -    const GLfixed texCoords[4][2] = { -            { 0,        0 }, -            { 0,        0x10000 }, -            { 0x10000,  0x10000 }, -            { 0x10000,  0 } +    const GLfloat texCoords[4][2] = { +            { 0,  0 }, +            { 0,  1 }, +            { 1,  1 }, +            { 1,  0 }      };      glMatrixMode(GL_TEXTURE); @@ -470,8 +432,8 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const      }      glEnableClientState(GL_TEXTURE_COORD_ARRAY); -    glVertexPointer(2, GL_FIXED, 0, mVertices); -    glTexCoordPointer(2, GL_FIXED, 0, texCoords); +    glVertexPointer(2, GL_FLOAT, 0, mVertices); +    glTexCoordPointer(2, GL_FLOAT, 0, texCoords);      while (it != end) {          const Rect& r = *it++; @@ -487,7 +449,7 @@ void LayerBase::validateTexture(GLint textureName) const      glBindTexture(GL_TEXTURE_2D, textureName);      // TODO: reload the texture if needed      // this is currently done in loadTexture() below -    if (mUseLinearFiltering) { +    if (needsFiltering()) {          glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);          glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);      } else { @@ -502,226 +464,40 @@ void LayerBase::validateTexture(GLint textureName) const      }  } -bool LayerBase::isSupportedYuvFormat(int format) const -{ -    switch (format) { -        case HAL_PIXEL_FORMAT_YCbCr_422_SP: -        case HAL_PIXEL_FORMAT_YCbCr_420_SP: -        case HAL_PIXEL_FORMAT_YCbCr_422_P: -        case HAL_PIXEL_FORMAT_YCbCr_420_P: -        case HAL_PIXEL_FORMAT_YCbCr_422_I: -        case HAL_PIXEL_FORMAT_YCbCr_420_I: -        case HAL_PIXEL_FORMAT_YCrCb_420_SP: -            return true; -    } -    return false; -} - -void LayerBase::loadTexture(Texture* texture,  -        const Region& dirty, const GGLSurface& t) const -{ -    if (texture->name == -1U) { -        // uh? -        return; -    } - -    glBindTexture(GL_TEXTURE_2D, texture->name); - -    /* -     * In OpenGL ES we can't specify a stride with glTexImage2D (however, -     * GL_UNPACK_ALIGNMENT is a limited form of stride). -     * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we -     * need to do something reasonable (here creating a bigger texture). -     *  -     * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT); -     *  -     * This situation doesn't happen often, but some h/w have a limitation -     * for their framebuffer (eg: must be multiple of 8 pixels), and -     * we need to take that into account when using these buffers as -     * textures. -     * -     * This should never be a problem with POT textures -     */ -     -    int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format)); -    unpack = 1 << ((unpack > 3) ? 3 : unpack); -    glPixelStorei(GL_UNPACK_ALIGNMENT, unpack); -     -    /* -     * round to POT if needed  -     */ -    if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) { -        texture->NPOTAdjust = true; -    } -     -    if (texture->NPOTAdjust) { -        // find the smallest power-of-two that will accommodate our surface -        texture->potWidth  = 1 << (31 - clz(t.width)); -        texture->potHeight = 1 << (31 - clz(t.height)); -        if (texture->potWidth  < t.width)  texture->potWidth  <<= 1; -        if (texture->potHeight < t.height) texture->potHeight <<= 1; -        texture->wScale = float(t.width)  / texture->potWidth; -        texture->hScale = float(t.height) / texture->potHeight; -    } else { -        texture->potWidth  = t.width; -        texture->potHeight = t.height; -    } - -    Rect bounds(dirty.bounds()); -    GLvoid* data = 0; -    if (texture->width != t.width || texture->height != t.height) { -        texture->width  = t.width; -        texture->height = t.height; - -        // texture size changed, we need to create a new one -        bounds.set(Rect(t.width, t.height)); -        if (t.width  == texture->potWidth && -            t.height == texture->potHeight) { -            // we can do it one pass -            data = t.data; -        } - -        if (t.format == HAL_PIXEL_FORMAT_RGB_565) { -            glTexImage2D(GL_TEXTURE_2D, 0, -                    GL_RGB, texture->potWidth, texture->potHeight, 0, -                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); -        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { -            glTexImage2D(GL_TEXTURE_2D, 0, -                    GL_RGBA, texture->potWidth, texture->potHeight, 0, -                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); -        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || -                   t.format == HAL_PIXEL_FORMAT_RGBX_8888) { -            glTexImage2D(GL_TEXTURE_2D, 0, -                    GL_RGBA, texture->potWidth, texture->potHeight, 0, -                    GL_RGBA, GL_UNSIGNED_BYTE, data); -        } else if (isSupportedYuvFormat(t.format)) { -            // just show the Y plane of YUV buffers -            glTexImage2D(GL_TEXTURE_2D, 0, -                    GL_LUMINANCE, texture->potWidth, texture->potHeight, 0, -                    GL_LUMINANCE, GL_UNSIGNED_BYTE, data); -        } else { -            // oops, we don't handle this format! -            LOGE("layer %p, texture=%d, using format %d, which is not " -                 "supported by the GL", this, texture->name, t.format); -        } -    } -    if (!data) { -        if (t.format == HAL_PIXEL_FORMAT_RGB_565) { -            glTexSubImage2D(GL_TEXTURE_2D, 0, -                    0, bounds.top, t.width, bounds.height(), -                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5, -                    t.data + bounds.top*t.stride*2); -        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { -            glTexSubImage2D(GL_TEXTURE_2D, 0, -                    0, bounds.top, t.width, bounds.height(), -                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, -                    t.data + bounds.top*t.stride*2); -        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || -                   t.format == HAL_PIXEL_FORMAT_RGBX_8888) { -            glTexSubImage2D(GL_TEXTURE_2D, 0, -                    0, bounds.top, t.width, bounds.height(), -                    GL_RGBA, GL_UNSIGNED_BYTE, -                    t.data + bounds.top*t.stride*4); -        } else if (isSupportedYuvFormat(t.format)) { -            // just show the Y plane of YUV buffers -            glTexSubImage2D(GL_TEXTURE_2D, 0, -                    0, bounds.top, t.width, bounds.height(), -                    GL_LUMINANCE, GL_UNSIGNED_BYTE, -                    t.data + bounds.top*t.stride); -        } -    } -} - -status_t LayerBase::initializeEglImage( -        const sp<GraphicBuffer>& buffer, Texture* texture) +void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const  { -    status_t err = NO_ERROR; - -    // we need to recreate the texture -    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); - -    // free the previous image -    if (texture->image != EGL_NO_IMAGE_KHR) { -        eglDestroyImageKHR(dpy, texture->image); -        texture->image = EGL_NO_IMAGE_KHR; -    } - -    // construct an EGL_NATIVE_BUFFER_ANDROID -    android_native_buffer_t* clientBuf = buffer->getNativeBuffer(); - -    // create the new EGLImageKHR -    const EGLint attrs[] = { -            EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE, -            EGL_NONE,                   EGL_NONE -    }; -    texture->image = eglCreateImageKHR( -            dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, -            (EGLClientBuffer)clientBuf, attrs); - -    if (texture->image != EGL_NO_IMAGE_KHR) { -        glBindTexture(GL_TEXTURE_2D, texture->name); -        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, -                (GLeglImageOES)texture->image); -        GLint error = glGetError(); -        if (UNLIKELY(error != GL_NO_ERROR)) { -            LOGE("layer=%p, glEGLImageTargetTexture2DOES(%p) " -                 "failed err=0x%04x", -                 this, texture->image, error); -            err = INVALID_OPERATION; -        } else { -            // Everything went okay! -            texture->NPOTAdjust = false; -            texture->dirty  = false; -            texture->width  = clientBuf->width; -            texture->height = clientBuf->height; -        } -    } else { -        LOGE("layer=%p, eglCreateImageKHR() failed. err=0x%4x", -                this, eglGetError()); -        err = INVALID_OPERATION; -    } -    return err; +    const Layer::State& s(drawingState()); +    snprintf(buffer, SIZE, +            "+ %s %p\n" +            "      " +            "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), " +            "needsBlending=%1d, needsDithering=%1d, invalidate=%1d, " +            "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n", +            getTypeId(), this, s.z, tx(), ty(), s.w, s.h, +            needsBlending(), needsDithering(), contentDirty, +            s.alpha, s.flags, +            s.transform[0][0], s.transform[0][1], +            s.transform[1][0], s.transform[1][1]); +    result.append(buffer);  } -  // --------------------------------------------------------------------------- -int32_t LayerBaseClient::sIdentity = 0; +int32_t LayerBaseClient::sIdentity = 1;  LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, -        const sp<Client>& client, int32_t i) -    : LayerBase(flinger, display), lcblk(NULL), client(client), mIndex(i), +        const sp<Client>& client) +    : LayerBase(flinger, display), mClientRef(client),        mIdentity(uint32_t(android_atomic_inc(&sIdentity)))  { -    lcblk = new SharedBufferServer( -            client->ctrlblk, i, NUM_BUFFERS, -            mIdentity); -} - -void LayerBaseClient::onFirstRef() -{     -    sp<Client> client(this->client.promote()); -    if (client != 0) { -        client->bindLayer(this, mIndex); -    }  }  LayerBaseClient::~LayerBaseClient()  { -    sp<Client> client(this->client.promote()); -    if (client != 0) { -        client->free(mIndex); +    sp<Client> c(mClientRef.promote()); +    if (c != 0) { +        c->detachLayer(this);      } -    delete lcblk; -} - -int32_t LayerBaseClient::serverIndex() const  -{ -    sp<Client> client(this->client.promote()); -    if (client != 0) { -        return (client->cid<<16)|mIndex; -    } -    return 0xFFFF0000 | mIndex;  }  sp<LayerBaseClient::Surface> LayerBaseClient::getSurface() @@ -738,25 +514,31 @@ sp<LayerBaseClient::Surface> LayerBaseClient::getSurface()  sp<LayerBaseClient::Surface> LayerBaseClient::createSurface() const  { -    return new Surface(mFlinger, clientIndex(), mIdentity, +    return new Surface(mFlinger, mIdentity,              const_cast<LayerBaseClient *>(this));  } -// called with SurfaceFlinger::mStateLock as soon as the layer is entered -// in the purgatory list -void LayerBaseClient::onRemoved() +void LayerBaseClient::dump(String8& result, char* buffer, size_t SIZE) const  { -    // wake up the condition -    lcblk->setStatus(NO_INIT); +    LayerBase::dump(result, buffer, SIZE); + +    sp<Client> client(mClientRef.promote()); +    snprintf(buffer, SIZE, +            "      name=%s\n" +            "      client=%p, identity=%u\n", +            getName().string(), +            client.get(), getIdentity()); + +    result.append(buffer);  }  // ---------------------------------------------------------------------------  LayerBaseClient::Surface::Surface(          const sp<SurfaceFlinger>& flinger, -        SurfaceID id, int identity,  +        int identity,          const sp<LayerBaseClient>& owner)  -    : mFlinger(flinger), mToken(id), mIdentity(identity), mOwner(owner) +    : mFlinger(flinger), mIdentity(identity), mOwner(owner)  {  } @@ -799,11 +581,17 @@ status_t LayerBaseClient::Surface::onTransact(      return BnSurface::onTransact(code, data, reply, flags);  } -sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int index, int usage)  +sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int bufferIdx, +        uint32_t w, uint32_t h, uint32_t format, uint32_t usage)  {      return NULL;   } +status_t LayerBaseClient::Surface::setBufferCount(int bufferCount) +{ +    return INVALID_OPERATION; +} +  status_t LayerBaseClient::Surface::registerBuffers(          const ISurface::BufferHeap& buffers)   {  diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h index 62ec8399ad..1a07f32cb5 100644 --- a/libs/surfaceflinger/LayerBase.h +++ b/libs/surfaceflinger/LayerBase.h @@ -29,7 +29,7 @@  #include <ui/Region.h>  #include <ui/Overlay.h> -#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurfaceComposerClient.h>  #include <private/surfaceflinger/SharedBufferStack.h>  #include <private/surfaceflinger/LayerState.h> @@ -45,41 +45,17 @@ class DisplayHardware;  class Client;  class GraphicBuffer;  class GraphicPlane; +class LayerBaseClient;  class SurfaceFlinger; +class Texture;  // ---------------------------------------------------------------------------  class LayerBase : public RefBase  { -    // poor man's dynamic_cast below -    template<typename T> -    struct getTypeInfoOfAnyType { -        static uint32_t get() { return T::typeInfo; } -    }; - -    template<typename T> -    struct getTypeInfoOfAnyType<T*> { -        static uint32_t get() { return getTypeInfoOfAnyType<T>::get(); } -    }; -  public: -    static const uint32_t typeInfo; -    static const char* const typeID; -    virtual char const* getTypeID() const { return typeID; } -    virtual uint32_t getTypeInfo() const { return typeInfo; } -     -    template<typename T> -    static T dynamicCast(LayerBase* base) { -        uint32_t mostDerivedInfo = base->getTypeInfo(); -        uint32_t castToInfo = getTypeInfoOfAnyType<T>::get(); -        if ((mostDerivedInfo & castToInfo) == castToInfo) -            return static_cast<T>(base); -        return 0; -    } +            LayerBase(SurfaceFlinger* flinger, DisplayID display); -     -    LayerBase(SurfaceFlinger* flinger, DisplayID display); -          DisplayID           dpy;      mutable bool        contentDirty;              Region      visibleRegionScreen; @@ -125,6 +101,10 @@ public:              void invalidate(); +    virtual sp<LayerBaseClient> getLayerBaseClient() const { return 0; } + +    virtual const char* getTypeId() const { return "LayerBase"; } +      /**       * draw - performs some global clipping optimizations       * and calls onDraw(). @@ -199,9 +179,9 @@ public:      virtual bool needsDithering() const { return false; }      /** -     * transformed -- true is this surface needs a to be transformed +     * needsLinearFiltering - true if this surface needs filtering       */ -    virtual bool transformed() const    { return mTransformed; } +    virtual bool needsFiltering() const { return mNeedsFiltering; }      /**       * isSecure - true if this surface is secure, that is if it prevents @@ -217,7 +197,10 @@ public:       *  current list */      virtual void onRemoved() { }; -     +    /** always call base class first */ +    virtual void dump(String8& result, char* scratch, size_t size) const; + +      enum { // flags for doTransaction()          eVisibleRegion      = 0x00000002,      }; @@ -241,44 +224,18 @@ protected:      const GraphicPlane& graphicPlane(int dpy) const;            GraphicPlane& graphicPlane(int dpy); -          GLuint createTexture() const; -     -          struct Texture { -              Texture() : name(-1U), width(0), height(0), -                  image(EGL_NO_IMAGE_KHR), transform(0),  -                  NPOTAdjust(false), dirty(true) { } -              GLuint        name; -              GLuint        width; -              GLuint        height; -              GLuint        potWidth; -              GLuint        potHeight; -              GLfloat       wScale; -              GLfloat       hScale; -              EGLImageKHR   image; -              uint32_t      transform; -              bool          NPOTAdjust; -              bool          dirty; -          }; - -          void clearWithOpenGL(const Region& clip, GLclampx r, GLclampx g, -                               GLclampx b, GLclampx alpha) const; +          void clearWithOpenGL(const Region& clip, GLclampf r, GLclampf g, +                               GLclampf b, GLclampf alpha) const;            void clearWithOpenGL(const Region& clip) const;            void drawWithOpenGL(const Region& clip, const Texture& texture) const; -          void loadTexture(Texture* texture,  -                  const Region& dirty, const GGLSurface& t) const; -          status_t initializeEglImage( -                  const sp<GraphicBuffer>& buffer, Texture* texture); - -          bool isSupportedYuvFormat(int format) const;                  sp<SurfaceFlinger> mFlinger;                  uint32_t        mFlags;                  // cached during validateVisibility() -                bool            mTransformed; -                bool            mUseLinearFiltering; +                bool            mNeedsFiltering;                  int32_t         mOrientation; -                GLfixed         mVertices[4][2]; +                GLfloat         mVertices[4][2];                  Rect            mTransformedBounds;                  int             mLeft;                  int             mTop; @@ -313,42 +270,25 @@ class LayerBaseClient : public LayerBase  {  public:      class Surface; -   static const uint32_t typeInfo; -    static const char* const typeID; -    virtual char const* getTypeID() const { return typeID; } -    virtual uint32_t getTypeInfo() const { return typeInfo; } - -    // lcblk is (almost) only accessed from the main SF thread, in the places -    // where it's not, a reference to Client must be held -    SharedBufferServer*     lcblk; -    LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,  -            const sp<Client>& client, int32_t i); +            LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, +                        const sp<Client>& client);      virtual ~LayerBaseClient(); -    virtual void onFirstRef(); - -    const wp<Client>    client; -    inline  uint32_t    getIdentity() const { return mIdentity; } -    inline  int32_t     clientIndex() const { return mIndex; } -            int32_t     serverIndex() const; - -                 sp<Surface> getSurface();      virtual sp<Surface> createSurface() const; -     -    virtual void onRemoved(); +    virtual sp<LayerBaseClient> getLayerBaseClient() const { +        return const_cast<LayerBaseClient*>(this); } +    virtual const char* getTypeId() const { return "LayerBaseClient"; } +    uint32_t getIdentity() const { return mIdentity; } -    class Surface : public BnSurface  -    { +    class Surface : public BnSurface  {      public: -        int32_t getToken() const { return mToken; }          int32_t getIdentity() const { return mIdentity; }      protected: -        Surface(const sp<SurfaceFlinger>& flinger,  -                SurfaceID id, int identity,  +        Surface(const sp<SurfaceFlinger>& flinger, int identity,                  const sp<LayerBaseClient>& owner);          virtual ~Surface();          virtual status_t onTransact(uint32_t code, const Parcel& data, @@ -356,7 +296,10 @@ public:          sp<LayerBaseClient> getOwner() const;      private: -        virtual sp<GraphicBuffer> requestBuffer(int index, int usage); +        virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, +                uint32_t w, uint32_t h, uint32_t format, uint32_t usage); +        virtual status_t setBufferCount(int bufferCount); +          virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);           virtual void postBuffer(ssize_t offset);          virtual void unregisterBuffers(); @@ -366,20 +309,22 @@ public:      protected:          friend class LayerBaseClient;          sp<SurfaceFlinger>  mFlinger; -        int32_t             mToken;          int32_t             mIdentity;          wp<LayerBaseClient> mOwner;      };      friend class Surface; +protected: +    virtual void dump(String8& result, char* scratch, size_t size) const; +  private: -                int32_t         mIndex; -    mutable     Mutex           mLock; -    mutable     wp<Surface>     mClientSurface; +    mutable Mutex mLock; +    mutable wp<Surface> mClientSurface; +    const wp<Client> mClientRef;      // only read -    const       uint32_t        mIdentity; -    static      int32_t         sIdentity; +    const uint32_t mIdentity; +    static int32_t sIdentity;  };  // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp index 5fd7904be6..4c8bae8f67 100644 --- a/libs/surfaceflinger/LayerBlur.cpp +++ b/libs/surfaceflinger/LayerBlur.cpp @@ -33,14 +33,9 @@  namespace android {  // --------------------------------------------------------------------------- -const uint32_t LayerBlur::typeInfo = LayerBaseClient::typeInfo | 8; -const char* const LayerBlur::typeID = "LayerBlur"; - -// --------------------------------------------------------------------------- -  LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display, -        const sp<Client>& client, int32_t i) -    : LayerBaseClient(flinger, display, client, i), mCacheDirty(true), +        const sp<Client>& client) +    : LayerBaseClient(flinger, display, client), mCacheDirty(true),            mRefreshCache(true), mCacheAge(0), mTextureName(-1U),            mWidthScale(1.0f), mHeightScale(1.0f),            mBlurFormat(GGL_PIXEL_FORMAT_RGB_565) @@ -100,7 +95,9 @@ void LayerBlur::unlockPageFlip(const Transform& planeTransform, Region& outDirty                      mCacheDirty = false;                  } else {                      if (!mAutoRefreshPending) { -                        mFlinger->signalDelayedEvent(ms2ns(500)); +                        mFlinger->postMessageAsync( +                                new MessageBase(MessageQueue::INVALIDATE), +                                ms2ns(500));                          mAutoRefreshPending = true;                      }                  } @@ -206,8 +203,8 @@ void LayerBlur::onDraw(const Region& clip) const          const State& s = drawingState();          if (UNLIKELY(s.alpha < 0xFF)) { -            const GGLfixed alpha = (s.alpha << 16)/255; -            glColor4x(0, 0, 0, alpha); +            const GLfloat alpha = s.alpha * (1.0f/255.0f); +            glColor4f(0, 0, 0, alpha);              glEnable(GL_BLEND);              glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);              glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); @@ -225,38 +222,20 @@ void LayerBlur::onDraw(const Region& clip) const          glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);          glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -        if (UNLIKELY(transformed() -                || !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) )) { -            // This is a very rare scenario. -            glMatrixMode(GL_TEXTURE); -            glLoadIdentity(); -            glScalef(mWidthScale, mHeightScale, 1); -            glTranslatef(-x, mYOffset - y, 0); -            glEnableClientState(GL_TEXTURE_COORD_ARRAY); -            glVertexPointer(2, GL_FIXED, 0, mVertices); -            glTexCoordPointer(2, GL_FIXED, 0, mVertices); -            while (it != end) { -                const Rect& r = *it++; -                const GLint sy = fbHeight - (r.top + r.height()); -                glScissor(r.left, sy, r.width(), r.height()); -                glDrawArrays(GL_TRIANGLE_FAN, 0, 4);  -            }        -            glDisableClientState(GL_TEXTURE_COORD_ARRAY); -        } else { -            // NOTE: this is marginally faster with the software gl, because -            // glReadPixels() reads the fb bottom-to-top, however we'll -            // skip all the jaccobian computations. -            Rect r; -            GLint crop[4] = { 0, 0, w, h }; -            glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); -            y = fbHeight - (y + h); -            while (it != end) { -                const Rect& r = *it++; -                const GLint sy = fbHeight - (r.top + r.height()); -                glScissor(r.left, sy, r.width(), r.height()); -                glDrawTexiOES(x, y, 0, w, h); -            } +        glMatrixMode(GL_TEXTURE); +        glLoadIdentity(); +        glScalef(mWidthScale, mHeightScale, 1); +        glTranslatef(-x, mYOffset - y, 0); +        glEnableClientState(GL_TEXTURE_COORD_ARRAY); +        glVertexPointer(2, GL_FLOAT, 0, mVertices); +        glTexCoordPointer(2, GL_FLOAT, 0, mVertices); +        while (it != end) { +            const Rect& r = *it++; +            const GLint sy = fbHeight - (r.top + r.height()); +            glScissor(r.left, sy, r.width(), r.height()); +            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);          } +        glDisableClientState(GL_TEXTURE_COORD_ARRAY);      }  } diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h index 5b63dec290..4c9ec647a0 100644 --- a/libs/surfaceflinger/LayerBlur.h +++ b/libs/surfaceflinger/LayerBlur.h @@ -31,18 +31,14 @@ namespace android {  class LayerBlur : public LayerBaseClient  {  public:     -    static const uint32_t typeInfo; -    static const char* const typeID; -    virtual char const* getTypeID() const { return typeID; } -    virtual uint32_t getTypeInfo() const { return typeInfo; } -                      LayerBlur(SurfaceFlinger* flinger, DisplayID display, -                        const sp<Client>& client, int32_t i); +                        const sp<Client>& client);          virtual ~LayerBlur();      virtual void onDraw(const Region& clip) const;      virtual bool needsBlending() const  { return true; }      virtual bool isSecure() const       { return false; } +    virtual const char* getTypeId() const { return "LayerBlur"; }      virtual uint32_t doTransaction(uint32_t flags);      virtual void setVisibleRegion(const Region& visibleRegion); diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp index 5c21593db2..732a4ec1dc 100644 --- a/libs/surfaceflinger/LayerBuffer.cpp +++ b/libs/surfaceflinger/LayerBuffer.cpp @@ -39,15 +39,13 @@ namespace android {  // --------------------------------------------------------------------------- -const uint32_t LayerBuffer::typeInfo = LayerBaseClient::typeInfo | 0x20; -const char* const LayerBuffer::typeID = "LayerBuffer";  gralloc_module_t const* LayerBuffer::sGrallocModule = 0;  // ---------------------------------------------------------------------------  LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display, -        const sp<Client>& client, int32_t i) -    : LayerBaseClient(flinger, display, client, i), +        const sp<Client>& client) +    : LayerBaseClient(flinger, display, client),        mNeedsBlending(false), mBlitEngine(0)  {  } @@ -62,8 +60,7 @@ LayerBuffer::~LayerBuffer()  void LayerBuffer::onFirstRef()  {      LayerBaseClient::onFirstRef(); -    mSurface = new SurfaceLayerBuffer(mFlinger, clientIndex(), -            const_cast<LayerBuffer *>(this)); +    mSurface = new SurfaceLayerBuffer(mFlinger, this);      hw_module_t const* module = (hw_module_t const*)sGrallocModule;      if (!module) { @@ -120,7 +117,7 @@ uint32_t LayerBuffer::doTransaction(uint32_t flags)          source->onTransaction(flags);      uint32_t res = LayerBase::doTransaction(flags);      // we always want filtering for these surfaces -    mUseLinearFiltering = !(mFlags & DisplayHardware::SLOW_CONFIG); +    mNeedsFiltering = !(mFlags & DisplayHardware::SLOW_CONFIG);      return res;  } @@ -145,14 +142,6 @@ void LayerBuffer::onDraw(const Region& clip) const      }  } -bool LayerBuffer::transformed() const -{ -    sp<Source> source(getSource()); -    if (LIKELY(source != 0)) -        return source->transformed(); -    return false; -} -  void LayerBuffer::serverDestroy()  {      sp<Source> source(clearSource()); @@ -214,9 +203,9 @@ sp<LayerBuffer::Source> LayerBuffer::clearSource() {  // LayerBuffer::SurfaceLayerBuffer  // ============================================================================ -LayerBuffer::SurfaceLayerBuffer::SurfaceLayerBuffer(const sp<SurfaceFlinger>& flinger, -        SurfaceID id, const sp<LayerBuffer>& owner) -    : LayerBaseClient::Surface(flinger, id, owner->getIdentity(), owner) +LayerBuffer::SurfaceLayerBuffer::SurfaceLayerBuffer( +        const sp<SurfaceFlinger>& flinger, const sp<LayerBuffer>& owner) +    : LayerBaseClient::Surface(flinger, owner->getIdentity(), owner)  {  } @@ -321,16 +310,13 @@ void LayerBuffer::Source::postBuffer(ssize_t offset) {  }  void LayerBuffer::Source::unregisterBuffers() {  } -bool LayerBuffer::Source::transformed() const { -    return mLayer.mTransformed;  -}  // ---------------------------------------------------------------------------  LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,          const ISurface::BufferHeap& buffers)      : Source(layer), mStatus(NO_ERROR), mBufferSize(0), -      mUseEGLImageDirectly(true) +      mTextureManager(layer.mFlags)  {      if (buffers.heap == NULL) {          // this is allowed, but in this case, it is illegal to receive @@ -444,11 +430,6 @@ void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer)      mBuffer = buffer;  } -bool LayerBuffer::BufferSource::transformed() const -{ -    return mBufferHeap.transform ? true : Source::transformed();  -} -  void LayerBuffer::BufferSource::onDraw(const Region& clip) const   {      sp<Buffer> ourBuffer(getBuffer()); @@ -462,35 +443,10 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const      NativeBuffer src(ourBuffer->getBuffer());      const Rect transformedBounds(mLayer.getTransformedBounds()); -    if (UNLIKELY(mTexture.name == -1LU)) { -        mTexture.name = mLayer.createTexture(); -    } -  #if defined(EGL_ANDROID_image_native_buffer)      if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) {          err = INVALID_OPERATION;          if (ourBuffer->supportsCopybit()) { - -            // there are constraints on buffers used by the GPU and these may not -            // be honored here. We need to change the API so the buffers -            // are allocated with gralloc. For now disable this code-path -#if 0 -            // First, try to use the buffer as an EGLImage directly -            if (mUseEGLImageDirectly) { -                // NOTE: Assume the buffer is allocated with the proper USAGE flags - -                sp<GraphicBuffer> buffer = new  GraphicBuffer( -                        src.img.w, src.img.h, src.img.format, -                        GraphicBuffer::USAGE_HW_TEXTURE, -                        src.img.w, src.img.handle, false); - -                err = mLayer.initializeEglImage(buffer, &mTexture); -                if (err != NO_ERROR) { -                    mUseEGLImageDirectly = false; -                } -            } -#endif -              copybit_device_t* copybit = mLayer.mBlitEngine;              if (copybit && err != NO_ERROR) {                  // create our EGLImageKHR the first time @@ -527,7 +483,7 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const          t.format = src.img.format;          t.data = (GGLubyte*)src.img.base;          const Region dirty(Rect(t.width, t.height)); -        mLayer.loadTexture(&mTexture, dirty, t); +        mTextureManager.loadTexture(&mTexture, dirty, t);      }      mTexture.transform = mBufferHeap.transform; @@ -569,7 +525,7 @@ status_t LayerBuffer::BufferSource::initTempBuffer() const      // figure out if we need linear filtering      if (buffers.w * h == buffers.h * w) {          // same pixel area, don't use filtering -        mLayer.mUseLinearFiltering = false; +        mLayer.mNeedsFiltering = false;      }      // Allocate a temporary buffer and create the corresponding EGLImageKHR @@ -593,7 +549,8 @@ status_t LayerBuffer::BufferSource::initTempBuffer() const          dst.crop.r = w;          dst.crop.b = h; -        err = mLayer.initializeEglImage(buffer, &mTexture); +        EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay()); +        err = mTextureManager.initEglImage(&mTexture, dpy, buffer);      }      return err; @@ -609,7 +566,6 @@ void LayerBuffer::BufferSource::clearTempBufferImage() const      glDeleteTextures(1, &mTexture.name);      Texture defaultTexture;      mTexture = defaultTexture; -    mTexture.name = mLayer.createTexture();  }  // --------------------------------------------------------------------------- @@ -665,9 +621,9 @@ LayerBuffer::OverlaySource::~OverlaySource()  void LayerBuffer::OverlaySource::onDraw(const Region& clip) const  {      // this would be where the color-key would be set, should we need it. -    GLclampx red = 0; -    GLclampx green = 0; -    GLclampx blue = 0; +    GLclampf red = 0; +    GLclampf green = 0; +    GLclampf blue = 0;      mLayer.clearWithOpenGL(clip, red, green, blue, 0);  } diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h index b1766238cd..413b8a45bc 100644 --- a/libs/surfaceflinger/LayerBuffer.h +++ b/libs/surfaceflinger/LayerBuffer.h @@ -21,6 +21,7 @@  #include <sys/types.h>  #include "LayerBase.h" +#include "TextureManager.h"  struct copybit_device_t; @@ -45,31 +46,25 @@ class LayerBuffer : public LayerBaseClient          virtual void onVisibilityResolved(const Transform& planeTransform);          virtual void postBuffer(ssize_t offset);          virtual void unregisterBuffers(); -        virtual bool transformed() const;          virtual void destroy() { }      protected:          LayerBuffer& mLayer;      };  public: -    static const uint32_t typeInfo; -    static const char* const typeID; -    virtual char const* getTypeID() const { return typeID; } -    virtual uint32_t getTypeInfo() const { return typeInfo; } -              LayerBuffer(SurfaceFlinger* flinger, DisplayID display, -                    const sp<Client>& client, int32_t i); +                    const sp<Client>& client);          virtual ~LayerBuffer();      virtual void onFirstRef();      virtual bool needsBlending() const; +    virtual const char* getTypeId() const { return "LayerBuffer"; }      virtual sp<LayerBaseClient::Surface> createSurface() const;      virtual status_t ditch();      virtual void onDraw(const Region& clip) const;      virtual uint32_t doTransaction(uint32_t flags);      virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); -    virtual bool transformed() const;      status_t registerBuffers(const ISurface::BufferHeap& buffers);      void postBuffer(ssize_t offset); @@ -133,7 +128,6 @@ private:          virtual void onDraw(const Region& clip) const;          virtual void postBuffer(ssize_t offset);          virtual void unregisterBuffers(); -        virtual bool transformed() const;          virtual void destroy() { }      private:          status_t initTempBuffer() const; @@ -143,9 +137,9 @@ private:          status_t                        mStatus;          ISurface::BufferHeap            mBufferHeap;          size_t                          mBufferSize; -        mutable LayerBase::Texture      mTexture; +        mutable Texture                 mTexture;          mutable NativeBuffer            mTempBuffer; -        mutable bool                    mUseEGLImageDirectly; +        mutable TextureManager          mTextureManager;      };      class OverlaySource : public Source { @@ -195,7 +189,7 @@ private:      {      public:          SurfaceLayerBuffer(const sp<SurfaceFlinger>& flinger, -                        SurfaceID id, const sp<LayerBuffer>& owner); +                        const sp<LayerBuffer>& owner);          virtual ~SurfaceLayerBuffer();          virtual status_t registerBuffers(const ISurface::BufferHeap& buffers); diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp index fd61e30d8f..d528d2ff77 100644 --- a/libs/surfaceflinger/LayerDim.cpp +++ b/libs/surfaceflinger/LayerDim.cpp @@ -30,9 +30,6 @@  namespace android {  // --------------------------------------------------------------------------- -const uint32_t LayerDim::typeInfo = LayerBaseClient::typeInfo | 0x10; -const char* const LayerDim::typeID = "LayerDim"; -  bool LayerDim::sUseTexture;  GLuint LayerDim::sTexId;  EGLImageKHR LayerDim::sImage; @@ -42,8 +39,8 @@ int32_t LayerDim::sHeight;  // ---------------------------------------------------------------------------  LayerDim::LayerDim(SurfaceFlinger* flinger, DisplayID display, -        const sp<Client>& client, int32_t i) -    : LayerBaseClient(flinger, display, client, i) +        const sp<Client>& client) +    : LayerBaseClient(flinger, display, client)  {  } diff --git a/libs/surfaceflinger/LayerDim.h b/libs/surfaceflinger/LayerDim.h index d4672a1c44..f0323149ac 100644 --- a/libs/surfaceflinger/LayerDim.h +++ b/libs/surfaceflinger/LayerDim.h @@ -37,18 +37,14 @@ class LayerDim : public LayerBaseClient      static int32_t sWidth;      static int32_t sHeight;  public:     -    static const uint32_t typeInfo; -    static const char* const typeID; -    virtual char const* getTypeID() const { return typeID; } -    virtual uint32_t getTypeInfo() const { return typeInfo; } -                      LayerDim(SurfaceFlinger* flinger, DisplayID display, -                        const sp<Client>& client, int32_t i); +                        const sp<Client>& client);          virtual ~LayerDim();      virtual void onDraw(const Region& clip) const;      virtual bool needsBlending() const  { return true; }      virtual bool isSecure() const       { return false; } +    virtual const char* getTypeId() const { return "LayerDim"; }      static void initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h);  }; diff --git a/libs/surfaceflinger/MessageQueue.cpp b/libs/surfaceflinger/MessageQueue.cpp index b43d80173a..d668e88d47 100644 --- a/libs/surfaceflinger/MessageQueue.cpp +++ b/libs/surfaceflinger/MessageQueue.cpp @@ -60,9 +60,9 @@ MessageQueue::~MessageQueue()  {  } -MessageList::value_type MessageQueue::waitMessage(nsecs_t timeout) +sp<MessageBase> MessageQueue::waitMessage(nsecs_t timeout)  { -    MessageList::value_type result; +    sp<MessageBase> result;      bool again;      do { @@ -132,6 +132,7 @@ MessageList::value_type MessageQueue::waitMessage(nsecs_t timeout)          if (again) {              // the message has been processed. release our reference to it              // without holding the lock. +            result->notify();              result = 0;          } @@ -141,7 +142,7 @@ MessageList::value_type MessageQueue::waitMessage(nsecs_t timeout)  }  status_t MessageQueue::postMessage( -        const MessageList::value_type& message, nsecs_t relTime, uint32_t flags) +        const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags)  {      return queueMessage(message, relTime, flags);  } @@ -154,7 +155,7 @@ status_t MessageQueue::invalidate() {  }  status_t MessageQueue::queueMessage( -        const MessageList::value_type& message, nsecs_t relTime, uint32_t flags) +        const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags)  {      Mutex::Autolock _l(mLock);      message->when = systemTime() + relTime; @@ -167,13 +168,13 @@ status_t MessageQueue::queueMessage(      return NO_ERROR;  } -void MessageQueue::dump(const MessageList::value_type& message) +void MessageQueue::dump(const sp<MessageBase>& message)  {      Mutex::Autolock _l(mLock);      dumpLocked(message);  } -void MessageQueue::dumpLocked(const MessageList::value_type& message) +void MessageQueue::dumpLocked(const sp<MessageBase>& message)  {      LIST::const_iterator cur(mMessages.begin());      LIST::const_iterator end(mMessages.end()); diff --git a/libs/surfaceflinger/MessageQueue.h b/libs/surfaceflinger/MessageQueue.h index dc8138d166..890f809a3b 100644 --- a/libs/surfaceflinger/MessageQueue.h +++ b/libs/surfaceflinger/MessageQueue.h @@ -25,6 +25,7 @@  #include <utils/Timers.h>  #include <utils/List.h> +#include "Barrier.h"  namespace android { @@ -37,7 +38,6 @@ class MessageList      List< sp<MessageBase> > mList;      typedef List< sp<MessageBase> > LIST;  public: -    typedef sp<MessageBase> value_type;      inline LIST::iterator begin()                { return mList.begin(); }      inline LIST::const_iterator begin() const    { return mList.begin(); }      inline LIST::iterator end()                  { return mList.end(); } @@ -63,11 +63,19 @@ public:      // return true if message has a handler      virtual bool handler() { return false; } + +    // waits for the handler to be processed +    void wait() const { barrier.wait(); } +    // releases all waiters. this is done automatically if +    // handler returns true +    void notify() const { barrier.open(); } +  protected:      virtual ~MessageBase() { }  private: +    mutable Barrier barrier;      friend class LightRefBase<MessageBase>;  }; @@ -82,42 +90,33 @@ class MessageQueue      typedef List< sp<MessageBase> > LIST;  public: -    // this is a work-around the multichar constant warning. A macro would -    // work too, but would pollute the namespace. -    template <int a, int b, int c, int d> -    struct WHAT { -        static const uint32_t Value =  -            (uint32_t(a&0xff)<<24)|(uint32_t(b&0xff)<<16)| -            (uint32_t(c&0xff)<<8)|uint32_t(d&0xff); -    }; -          MessageQueue();      ~MessageQueue();      // pre-defined messages      enum { -        INVALIDATE = WHAT<'_','p','d','t'>::Value +        INVALIDATE = '_upd'      }; -    MessageList::value_type waitMessage(nsecs_t timeout = -1); +    sp<MessageBase> waitMessage(nsecs_t timeout = -1); -    status_t postMessage(const MessageList::value_type& message,  +    status_t postMessage(const sp<MessageBase>& message,              nsecs_t reltime=0, uint32_t flags = 0); -         +      status_t invalidate(); -    void dump(const MessageList::value_type& message); +    void dump(const sp<MessageBase>& message);  private: -    status_t queueMessage(const MessageList::value_type& message, +    status_t queueMessage(const sp<MessageBase>& message,              nsecs_t reltime, uint32_t flags); -    void dumpLocked(const MessageList::value_type& message); +    void dumpLocked(const sp<MessageBase>& message);      Mutex           mLock;      Condition       mCondition;      MessageList     mMessages;      bool            mInvalidate; -    MessageList::value_type mInvalidateMessage; +    sp<MessageBase> mInvalidateMessage;  };  // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp index 0722fda55e..4dea62f410 100644 --- a/libs/surfaceflinger/SurfaceFlinger.cpp +++ b/libs/surfaceflinger/SurfaceFlinger.cpp @@ -206,8 +206,8 @@ void SurfaceFlinger::init()      property_get("debug.sf.showbackground", value, "0");      mDebugBackground = atoi(value); -    LOGI_IF(mDebugRegion,           "showupdates enabled"); -    LOGI_IF(mDebugBackground,       "showbackground enabled"); +    LOGI_IF(mDebugRegion,       "showupdates enabled"); +    LOGI_IF(mDebugBackground,   "showbackground enabled");  }  SurfaceFlinger::~SurfaceFlinger() @@ -225,56 +225,29 @@ sp<IMemoryHeap> SurfaceFlinger::getCblk() const      return mServerHeap;  } -sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection() +sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()  { -    Mutex::Autolock _l(mStateLock); -    uint32_t token = mTokens.acquire(); - -    sp<Client> client = new Client(token, this); -    if (client->ctrlblk == 0) { -        mTokens.release(token); -        return 0; -    } -    status_t err = mClientsMap.add(token, client); -    if (err < 0) { -        mTokens.release(token); -        return 0; +    sp<ISurfaceComposerClient> bclient; +    sp<Client> client(new Client(this)); +    status_t err = client->initCheck(); +    if (err == NO_ERROR) { +        bclient = client;      } -    sp<BClient> bclient = -        new BClient(this, token, client->getControlBlockMemory());      return bclient;  } -void SurfaceFlinger::destroyConnection(ClientID cid) +sp<ISurfaceComposerClient> SurfaceFlinger::createClientConnection()  { -    Mutex::Autolock _l(mStateLock); -    sp<Client> client = mClientsMap.valueFor(cid); -    if (client != 0) { -        // free all the layers this client owns -        Vector< wp<LayerBaseClient> > layers(client->getLayers()); -        const size_t count = layers.size(); -        for (size_t i=0 ; i<count ; i++) { -            sp<LayerBaseClient> layer(layers[i].promote()); -            if (layer != 0) { -                purgatorizeLayer_l(layer); -            } -        } - -        // the resources associated with this client will be freed -        // during the next transaction, after these surfaces have been -        // properly removed from the screen - -        // remove this client from our ClientID->Client mapping. -        mClientsMap.removeItem(cid); - -        // and add it to the list of disconnected clients -        mDisconnectedClients.add(client); - -        // request a transaction -        setTransactionFlags(eTransactionNeeded); +    sp<ISurfaceComposerClient> bclient; +    sp<UserClient> client(new UserClient(this)); +    status_t err = client->initCheck(); +    if (err == NO_ERROR) { +        bclient = client;      } +    return bclient;  } +  const GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) const  {      LOGE_IF(uint32_t(dpy) >= DISPLAY_COUNT, "Invalid DisplayID %d", dpy); @@ -357,7 +330,6 @@ status_t SurfaceFlinger::readyToRun()      dcblk->ydpi         = hw.getDpiY();      dcblk->fps          = hw.getRefreshRate();      dcblk->density      = hw.getDensity(); -    asm volatile ("":::"memory");      // Initialize OpenGL|ES      glActiveTexture(GL_TEXTURE0); @@ -427,7 +399,7 @@ void SurfaceFlinger::waitForEvent()              timeout = waitTime>0 ? waitTime : 0;          } -        MessageList::value_type msg = mEventQueue.waitMessage(timeout); +        sp<MessageBase> msg = mEventQueue.waitMessage(timeout);          // see if we timed out          if (isFrozen()) { @@ -462,9 +434,20 @@ void SurfaceFlinger::signal() const {      const_cast<SurfaceFlinger*>(this)->signalEvent();  } -void SurfaceFlinger::signalDelayedEvent(nsecs_t delay) +status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg, +        nsecs_t reltime, uint32_t flags)  { -    mEventQueue.postMessage( new MessageBase(MessageQueue::INVALIDATE), delay); +    return mEventQueue.postMessage(msg, reltime, flags); +} + +status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg, +        nsecs_t reltime, uint32_t flags) +{ +    status_t res = mEventQueue.postMessage(msg, reltime, flags); +    if (res == NO_ERROR) { +        msg->wait(); +    } +    return res;  }  // ---------------------------------------------------------------------------- @@ -655,10 +638,6 @@ void SurfaceFlinger::handleTransactionLocked(                  }              }          } - -        // get rid of all resources we don't need anymore -        // (layers and clients) -        free_resources_l();      }      commitTransaction(); @@ -805,7 +784,8 @@ void SurfaceFlinger::commitTransaction()  void SurfaceFlinger::handlePageFlip()  {      bool visibleRegions = mVisibleRegionsDirty; -    LayerVector& currentLayers = const_cast<LayerVector&>(mDrawingState.layersSortedByZ); +    LayerVector& currentLayers = const_cast<LayerVector&>( +            mDrawingState.layersSortedByZ);      visibleRegions |= lockPageFlip(currentLayers);          const DisplayHardware& hw = graphicPlane(0).displayHardware(); @@ -827,7 +807,7 @@ bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers)      size_t count = currentLayers.size();      sp<LayerBase> const* layers = currentLayers.array();      for (size_t i=0 ; i<count ; i++) { -        const sp<LayerBase>& layer = layers[i]; +        const sp<LayerBase>& layer(layers[i]);          layer->lockPageFlip(recomputeVisibleRegions);      }      return recomputeVisibleRegions; @@ -840,7 +820,7 @@ void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers)      size_t count = currentLayers.size();      sp<LayerBase> const* layers = currentLayers.array();      for (size_t i=0 ; i<count ; i++) { -        const sp<LayerBase>& layer = layers[i]; +        const sp<LayerBase>& layer(layers[i]);          layer->unlockPageFlip(planeTransform, mDirtyRegion);      }  } @@ -872,7 +852,7 @@ void SurfaceFlinger::handleRepaint()          // takes a rectangle, we must make sure to update that whole          // rectangle in that case          if (flags & DisplayHardware::SWAP_RECTANGLE) { -            // FIXME: we really should be able to pass a region to +            // TODO: we really should be able to pass a region to              // SWAP_RECTANGLE so that we don't have to redraw all this.              mDirtyRegion.set(mInvalidRegion.bounds());          } else { @@ -1061,6 +1041,27 @@ status_t SurfaceFlinger::addLayer(const sp<LayerBase>& layer)      return NO_ERROR;  } +status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer) +{ +    ssize_t i = mCurrentState.layersSortedByZ.add( +                layer, &LayerBase::compareCurrentStateZ); +    return (i < 0) ? status_t(i) : status_t(NO_ERROR); +} + +ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client, +        const sp<LayerBaseClient>& lbc) +{ +    Mutex::Autolock _l(mStateLock); + +    // attach this layer to the client +    ssize_t name = client->attachLayer(lbc); + +    // add this layer to the current state list +    addLayer_l(lbc); + +    return name; +} +  status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer)  {      Mutex::Autolock _l(mStateLock); @@ -1070,36 +1071,15 @@ status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer)      return err;  } -status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer) -{ -    layer->forceVisibilityTransaction(); -    setTransactionFlags(eTraversalNeeded); -    return NO_ERROR; -} - -status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer) +status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase)  { -    if (layer == 0) -        return BAD_VALUE; -    ssize_t i = mCurrentState.layersSortedByZ.add( -                layer, &LayerBase::compareCurrentStateZ); -    sp<LayerBaseClient> lbc = LayerBase::dynamicCast< LayerBaseClient* >(layer.get()); +    sp<LayerBaseClient> lbc(layerBase->getLayerBaseClient());      if (lbc != 0) { -        mLayerMap.add(lbc->serverIndex(), lbc); +        mLayerMap.removeItem( lbc->getSurface()->asBinder() );      } -    return NO_ERROR; -} - -status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase) -{      ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase);      if (index >= 0) {          mLayersRemoved = true; -        sp<LayerBaseClient> layer = -            LayerBase::dynamicCast< LayerBaseClient* >(layerBase.get()); -        if (layer != 0) { -            mLayerMap.removeItem(layer->serverIndex()); -        }          return NO_ERROR;      }      return status_t(index); @@ -1114,22 +1094,16 @@ status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase)      // it's possible that we don't find a layer, because it might      // have been destroyed already -- this is not technically an error -    // from the user because there is a race between BClient::destroySurface(), -    // ~BClient() and ~ISurface(). +    // from the user because there is a race between Client::destroySurface(), +    // ~Client() and ~ISurface().      return (err == NAME_NOT_FOUND) ? status_t(NO_ERROR) : err;  } - -void SurfaceFlinger::free_resources_l() +status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer)  { -    // free resources associated with disconnected clients -    Vector< sp<Client> >& disconnectedClients(mDisconnectedClients); -    const size_t count = disconnectedClients.size(); -    for (size_t i=0 ; i<count ; i++) { -        sp<Client> client = disconnectedClients[i]; -        mTokens.release(client->cid); -    } -    disconnectedClients.clear(); +    layer->forceVisibilityTransaction(); +    setTransactionFlags(eTraversalNeeded); +    return NO_ERROR;  }  uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) @@ -1137,15 +1111,11 @@ uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)      return android_atomic_and(~flags, &mTransactionFlags) & flags;  } -uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, nsecs_t delay) +uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags)  {      uint32_t old = android_atomic_or(flags, &mTransactionFlags);      if ((old & flags)==0) { // wake the server up -        if (delay > 0) { -            signalDelayedEvent(delay); -        } else { -            signalEvent(); -        } +        signalEvent();      }      return old;  } @@ -1224,8 +1194,8 @@ int SurfaceFlinger::setOrientation(DisplayID dpy,      return orientation;  } -sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid, -        const String8& name, ISurfaceFlingerClient::surface_data_t* params, +sp<ISurface> SurfaceFlinger::createSurface(const sp<Client>& client, int pid, +        const String8& name, ISurfaceComposerClient::surface_data_t* params,          DisplayID d, uint32_t w, uint32_t h, PixelFormat format,          uint32_t flags)  { @@ -1238,57 +1208,52 @@ sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,          return surfaceHandle;      } -    Mutex::Autolock _l(mStateLock); -    sp<Client> client = mClientsMap.valueFor(clientId); -    if (UNLIKELY(client == 0)) { -        LOGE("createSurface() failed, client not found (id=%d)", clientId); -        return surfaceHandle; -    } -      //LOGD("createSurface for pid %d (%d x %d)", pid, w, h); -    int32_t id = client->generateId(pid); -    if (uint32_t(id) >= NUM_LAYERS_MAX) { -        LOGE("createSurface() failed, generateId = %d", id); -        return surfaceHandle; -    } - +    sp<Layer> normalLayer;      switch (flags & eFXSurfaceMask) {          case eFXSurfaceNormal:              if (UNLIKELY(flags & ePushBuffers)) { -                layer = createPushBuffersSurfaceLocked(client, d, id, -                        w, h, flags); +                layer = createPushBuffersSurface(client, d, w, h, flags);              } else { -                layer = createNormalSurfaceLocked(client, d, id, -                        w, h, flags, format); +                normalLayer = createNormalSurface(client, d, w, h, flags, format); +                layer = normalLayer;              }              break;          case eFXSurfaceBlur: -            layer = createBlurSurfaceLocked(client, d, id, w, h, flags); +            layer = createBlurSurface(client, d, w, h, flags);              break;          case eFXSurfaceDim: -            layer = createDimSurfaceLocked(client, d, id, w, h, flags); +            layer = createDimSurface(client, d, w, h, flags);              break;      }      if (layer != 0) { +        layer->initStates(w, h, flags);          layer->setName(name); -        setTransactionFlags(eTransactionNeeded); +        ssize_t token = addClientLayer(client, layer); +          surfaceHandle = layer->getSurface();          if (surfaceHandle != 0) {  -            params->token = surfaceHandle->getToken(); +            params->token = token;              params->identity = surfaceHandle->getIdentity();              params->width = w;              params->height = h;              params->format = format; +            if (normalLayer != 0) { +                Mutex::Autolock _l(mStateLock); +                mLayerMap.add(surfaceHandle->asBinder(), normalLayer); +            }          } + +        setTransactionFlags(eTransactionNeeded);      }      return surfaceHandle;  } -sp<LayerBaseClient> SurfaceFlinger::createNormalSurfaceLocked( +sp<Layer> SurfaceFlinger::createNormalSurface(          const sp<Client>& client, DisplayID display, -        int32_t id, uint32_t w, uint32_t h, uint32_t flags, +        uint32_t w, uint32_t h, uint32_t flags,          PixelFormat& format)  {      // initialize the surfaces @@ -1298,53 +1263,47 @@ sp<LayerBaseClient> SurfaceFlinger::createNormalSurfaceLocked(          format = PIXEL_FORMAT_RGBA_8888;          break;      case PIXEL_FORMAT_OPAQUE: -        format = PIXEL_FORMAT_RGB_565; +        format = PIXEL_FORMAT_RGBX_8888;          break;      } -    sp<Layer> layer = new Layer(this, display, client, id); +    sp<Layer> layer = new Layer(this, display, client);      status_t err = layer->setBuffers(w, h, format, flags); -    if (LIKELY(err == NO_ERROR)) { -        layer->initStates(w, h, flags); -        addLayer_l(layer); -    } else { +    if (LIKELY(err != NO_ERROR)) {          LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err));          layer.clear();      }      return layer;  } -sp<LayerBaseClient> SurfaceFlinger::createBlurSurfaceLocked( +sp<LayerBlur> SurfaceFlinger::createBlurSurface(          const sp<Client>& client, DisplayID display, -        int32_t id, uint32_t w, uint32_t h, uint32_t flags) +        uint32_t w, uint32_t h, uint32_t flags)  { -    sp<LayerBlur> layer = new LayerBlur(this, display, client, id); +    sp<LayerBlur> layer = new LayerBlur(this, display, client);      layer->initStates(w, h, flags); -    addLayer_l(layer);      return layer;  } -sp<LayerBaseClient> SurfaceFlinger::createDimSurfaceLocked( +sp<LayerDim> SurfaceFlinger::createDimSurface(          const sp<Client>& client, DisplayID display, -        int32_t id, uint32_t w, uint32_t h, uint32_t flags) +        uint32_t w, uint32_t h, uint32_t flags)  { -    sp<LayerDim> layer = new LayerDim(this, display, client, id); +    sp<LayerDim> layer = new LayerDim(this, display, client);      layer->initStates(w, h, flags); -    addLayer_l(layer);      return layer;  } -sp<LayerBaseClient> SurfaceFlinger::createPushBuffersSurfaceLocked( +sp<LayerBuffer> SurfaceFlinger::createPushBuffersSurface(          const sp<Client>& client, DisplayID display, -        int32_t id, uint32_t w, uint32_t h, uint32_t flags) +        uint32_t w, uint32_t h, uint32_t flags)  { -    sp<LayerBuffer> layer = new LayerBuffer(this, display, client, id); +    sp<LayerBuffer> layer = new LayerBuffer(this, display, client);      layer->initStates(w, h, flags); -    addLayer_l(layer);      return layer;  } -status_t SurfaceFlinger::removeSurface(SurfaceID index) +status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid)  {      /*       * called by the window manager, when a surface should be marked for @@ -1357,7 +1316,7 @@ status_t SurfaceFlinger::removeSurface(SurfaceID index)      status_t err = NAME_NOT_FOUND;      Mutex::Autolock _l(mStateLock); -    sp<LayerBaseClient> layer = getLayerUser_l(index); +    sp<LayerBaseClient> layer = client->getLayerUser(sid);      if (layer != 0) {          err = purgatorizeLayer_l(layer);          if (err == NO_ERROR) { @@ -1397,21 +1356,20 @@ status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer)          }      }; -    mEventQueue.postMessage( new MessageDestroySurface(this, layer) ); +    postMessageAsync( new MessageDestroySurface(this, layer) );      return NO_ERROR;  }  status_t SurfaceFlinger::setClientState( -        ClientID cid, +        const sp<Client>& client,          int32_t count,          const layer_state_t* states)  {      Mutex::Autolock _l(mStateLock);      uint32_t flags = 0; -    cid <<= 16;      for (int i=0 ; i<count ; i++) { -        const layer_state_t& s = states[i]; -        sp<LayerBaseClient> layer(getLayerUser_l(s.surface | cid)); +        const layer_state_t& s(states[i]); +        sp<LayerBaseClient> layer(client->getLayerUser(s.surface));          if (layer != 0) {              const uint32_t what = s.what;              if (what & ePositionChanged) { @@ -1457,12 +1415,6 @@ status_t SurfaceFlinger::setClientState(      return NO_ERROR;  } -sp<LayerBaseClient> SurfaceFlinger::getLayerUser_l(SurfaceID s) const -{ -    sp<LayerBaseClient> layer = mLayerMap.valueFor(s); -    return layer; -} -  void SurfaceFlinger::screenReleased(int dpy)  {      // this may be called by a signal handler, we can't do too much in here @@ -1512,83 +1464,17 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)              result.append(buffer);          } -        size_t s = mClientsMap.size(); -        char name[64]; -        for (size_t i=0 ; i<s ; i++) { -            sp<Client> client = mClientsMap.valueAt(i); -            sprintf(name, "  Client (id=0x%08x)", client->cid); -            client->dump(name); -        }          const LayerVector& currentLayers = mCurrentState.layersSortedByZ;          const size_t count = currentLayers.size();          for (size_t i=0 ; i<count ; i++) { -            /*** LayerBase ***/ -            const sp<LayerBase>& layer = currentLayers[i]; -            const Layer::State& s = layer->drawingState(); -            snprintf(buffer, SIZE, -                    "+ %s %p\n" -                    "      " -                    "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), " -                    "needsBlending=%1d, needsDithering=%1d, invalidate=%1d, " -                    "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n", -                    layer->getTypeID(), layer.get(), -                    s.z, layer->tx(), layer->ty(), s.w, s.h, -                    layer->needsBlending(), layer->needsDithering(), -                    layer->contentDirty, -                    s.alpha, s.flags, -                    s.transform[0][0], s.transform[0][1], -                    s.transform[1][0], s.transform[1][1]); -            result.append(buffer); -            buffer[0] = 0; -            /*** LayerBaseClient ***/ -            sp<LayerBaseClient> lbc = -                LayerBase::dynamicCast< LayerBaseClient* >(layer.get()); -            if (lbc != 0) { -                sp<Client> client(lbc->client.promote()); -                snprintf(buffer, SIZE, -                        "      name=%s\n", lbc->getName().string()); -                result.append(buffer); -                snprintf(buffer, SIZE, -                        "      id=0x%08x, client=0x%08x, identity=%u\n", -                        lbc->clientIndex(), client.get() ? client->cid : 0, -                        lbc->getIdentity()); - -                result.append(buffer); -                buffer[0] = 0; -            } -            /*** Layer ***/ -            sp<Layer> l = LayerBase::dynamicCast< Layer* >(layer.get()); -            if (l != 0) { -                SharedBufferStack::Statistics stats = l->lcblk->getStats(); -                result.append( l->lcblk->dump("      ") ); -                sp<const GraphicBuffer> buf0(l->getBuffer(0)); -                sp<const GraphicBuffer> buf1(l->getBuffer(1)); -                uint32_t w0=0, h0=0, s0=0; -                uint32_t w1=0, h1=0, s1=0; -                if (buf0 != 0) { -                    w0 = buf0->getWidth(); -                    h0 = buf0->getHeight(); -                    s0 = buf0->getStride(); -                } -                if (buf1 != 0) { -                    w1 = buf1->getWidth(); -                    h1 = buf1->getHeight(); -                    s1 = buf1->getStride(); -                } -                snprintf(buffer, SIZE, -                        "      " -                        "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u]," -                        " freezeLock=%p, dq-q-time=%u us\n", -                        l->pixelFormat(), -                        w0, h0, s0, w1, h1, s1, -                        l->getFreezeLock().get(), stats.totalTime); -                result.append(buffer); -                buffer[0] = 0; -            } +            const sp<LayerBase>& layer(currentLayers[i]); +            layer->dump(result, buffer, SIZE); +            const Layer::State& s(layer->drawingState());              s.transparentRegion.dump(result, "transparentRegion");              layer->transparentRegionScreen.dump(result, "transparentRegionScreen");              layer->visibleRegionScreen.dump(result, "visibleRegionScreen");          } +          mWormholeRegion.dump(result, "WormholeRegion");          const DisplayHardware& hw(graphicPlane(0).displayHardware());          snprintf(buffer, SIZE, @@ -1601,18 +1487,19 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)                  "  last transaction time     : %f us\n",                  mLastSwapBufferTime/1000.0, mLastTransactionTime/1000.0);          result.append(buffer); +          if (inSwapBuffersDuration || !locked) {              snprintf(buffer, SIZE, "  eglSwapBuffers time: %f us\n",                      inSwapBuffersDuration/1000.0);              result.append(buffer);          } +          if (inTransactionDuration || !locked) {              snprintf(buffer, SIZE, "  transaction time: %f us\n",                      inTransactionDuration/1000.0);              result.append(buffer);          } -        snprintf(buffer, SIZE, "  client count: %d\n", mClientsMap.size()); -        result.append(buffer); +          const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());          alloc.dump(result); @@ -1705,116 +1592,189 @@ status_t SurfaceFlinger::onTransact(  }  // --------------------------------------------------------------------------- -#if 0 -#pragma mark - -#endif -Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger) -    : ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger) +sp<Layer> SurfaceFlinger::getLayer(const sp<ISurface>& sur) const  { -    const int pgsize = getpagesize(); -    const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1)); +    sp<Layer> result; +    Mutex::Autolock _l(mStateLock); +    result = mLayerMap.valueFor( sur->asBinder() ).promote(); +    return result; +} -    mCblkHeap = new MemoryHeapBase(cblksize, 0, -            "SurfaceFlinger Client control-block"); +// --------------------------------------------------------------------------- -    ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase()); -    if (ctrlblk) { // construct the shared structure in-place. -        new(ctrlblk) SharedClient; -    } +Client::Client(const sp<SurfaceFlinger>& flinger) +    : mFlinger(flinger), mNameGenerator(1) +{  } -Client::~Client() { -    if (ctrlblk) { -        ctrlblk->~SharedClient();  // destroy our shared-structure. +Client::~Client() +{ +    const size_t count = mLayers.size(); +    for (size_t i=0 ; i<count ; i++) { +        sp<LayerBaseClient> layer(mLayers.valueAt(i).promote()); +        if (layer != 0) { +            mFlinger->removeLayer(layer); +        }      }  } -int32_t Client::generateId(int pid) -{ -    const uint32_t i = clz( ~mBitmap ); -    if (i >= NUM_LAYERS_MAX) { -        return NO_MEMORY; -    } -    mPid = pid; -    mInUse.add(uint8_t(i)); -    mBitmap |= 1<<(31-i); -    return i; +status_t Client::initCheck() const { +    return NO_ERROR;  } -status_t Client::bindLayer(const sp<LayerBaseClient>& layer, int32_t id) +ssize_t Client::attachLayer(const sp<LayerBaseClient>& layer)  { -    ssize_t idx = mInUse.indexOf(id); -    if (idx < 0) -        return NAME_NOT_FOUND; -    return mLayers.insertAt(layer, idx); +    int32_t name = android_atomic_inc(&mNameGenerator); +    mLayers.add(name, layer); +    return name;  } -void Client::free(int32_t id) +void Client::detachLayer(const LayerBaseClient* layer)  { -    ssize_t idx = mInUse.remove(uint8_t(id)); -    if (idx >= 0) { -        mBitmap &= ~(1<<(31-id)); -        mLayers.removeItemsAt(idx); +    // we do a linear search here, because this doesn't happen often +    const size_t count = mLayers.size(); +    for (size_t i=0 ; i<count ; i++) { +        if (mLayers.valueAt(i) == layer) { +            mLayers.removeItemsAt(i, 1); +            break; +        }      }  } - -bool Client::isValid(int32_t i) const { -    return (uint32_t(i)<NUM_LAYERS_MAX) && (mBitmap & (1<<(31-i))); -} -  sp<LayerBaseClient> Client::getLayerUser(int32_t i) const {      sp<LayerBaseClient> lbc; -    ssize_t idx = mInUse.indexOf(uint8_t(i)); -    if (idx >= 0) { -        lbc = mLayers[idx].promote(); -        LOGE_IF(lbc==0, "getLayerUser(i=%d), idx=%d is dead", int(i), int(idx)); +    const wp<LayerBaseClient>& layer(mLayers.valueFor(i)); +    if (layer != 0) { +        lbc = layer.promote(); +        LOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i));      }      return lbc;  } -void Client::dump(const char* what) +sp<IMemoryHeap> Client::getControlBlock() const { +    return 0; +} +ssize_t Client::getTokenForSurface(const sp<ISurface>& sur) const { +    return -1; +} +sp<ISurface> Client::createSurface( +        ISurfaceComposerClient::surface_data_t* params, int pid, +        const String8& name, +        DisplayID display, uint32_t w, uint32_t h, PixelFormat format, +        uint32_t flags)  { +    return mFlinger->createSurface(this, pid, name, params, +            display, w, h, format, flags); +} +status_t Client::destroySurface(SurfaceID sid) { +    return mFlinger->removeSurface(this, sid); +} +status_t Client::setState(int32_t count, const layer_state_t* states) { +    return mFlinger->setClientState(this, count, states);  }  // --------------------------------------------------------------------------- -#if 0 -#pragma mark - -#endif -BClient::BClient(SurfaceFlinger *flinger, ClientID cid, const sp<IMemoryHeap>& cblk) -    : mId(cid), mFlinger(flinger), mCblk(cblk) +UserClient::UserClient(const sp<SurfaceFlinger>& flinger) +    : ctrlblk(0), mBitmap(0), mFlinger(flinger)  { +    const int pgsize = getpagesize(); +    const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1)); + +    mCblkHeap = new MemoryHeapBase(cblksize, 0, +            "SurfaceFlinger Client control-block"); + +    ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase()); +    if (ctrlblk) { // construct the shared structure in-place. +        new(ctrlblk) SharedClient; +    }  } -BClient::~BClient() { -    // destroy all resources attached to this client -    mFlinger->destroyConnection(mId); +UserClient::~UserClient() +{ +    if (ctrlblk) { +        ctrlblk->~SharedClient();  // destroy our shared-structure. +    } + +    /* +     * When a UserClient dies, it's unclear what to do exactly. +     * We could go ahead and destroy all surfaces linked to that client +     * however, it wouldn't be fair to the main Client +     * (usually the the window-manager), which might want to re-target +     * the layer to another UserClient. +     * I think the best is to do nothing, or not much; in most cases the +     * WM itself will go ahead and clean things up when it detects a client of +     * his has died. +     * The remaining question is what to display? currently we keep +     * just keep the current buffer. +     */  } -sp<IMemoryHeap> BClient::getControlBlock() const { -    return mCblk; +status_t UserClient::initCheck() const { +    return ctrlblk == 0 ? NO_INIT : NO_ERROR;  } -sp<ISurface> BClient::createSurface( -        ISurfaceFlingerClient::surface_data_t* params, int pid, -        const String8& name, -        DisplayID display, uint32_t w, uint32_t h, PixelFormat format, -        uint32_t flags) +void UserClient::detachLayer(const Layer* layer)  { -    return mFlinger->createSurface(mId, pid, name, params, display, w, h, -            format, flags); +    int32_t name = layer->getToken(); +    if (name >= 0) { +        int32_t mask = 1LU<<name; +        if ((android_atomic_and(~mask, &mBitmap) & mask) == 0) { +            LOGW("token %d wasn't marked as used %08x", name, int(mBitmap)); +        } +    }  } -status_t BClient::destroySurface(SurfaceID sid) -{ -    sid |= (mId << 16); // add the client-part to id -    return mFlinger->removeSurface(sid); +sp<IMemoryHeap> UserClient::getControlBlock() const { +    return mCblkHeap;  } -status_t BClient::setState(int32_t count, const layer_state_t* states) +ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const  { -    return mFlinger->setClientState(mId, count, states); +    int32_t name = NAME_NOT_FOUND; +    sp<Layer> layer(mFlinger->getLayer(sur)); +    if (layer == 0) return name; + +    // if this layer already has a token, just return it +    name = layer->getToken(); +    if ((name >= 0) && (layer->getClient() == this)) +        return name; + +    name = 0; +    do { +        int32_t mask = 1LU<<name; +        if ((android_atomic_or(mask, &mBitmap) & mask) == 0) { +            // we found and locked that name +            status_t err = layer->setToken( +                    const_cast<UserClient*>(this), ctrlblk, name); +            if (err != NO_ERROR) { +                // free the name +                android_atomic_and(~mask, &mBitmap); +                name = err; +            } +            break; +        } +        if (++name > 31) +            name = NO_MEMORY; +    } while(name >= 0); + +    //LOGD("getTokenForSurface(%p) => %d (client=%p, bitmap=%08lx)", +    //        sur->asBinder().get(), name, this, mBitmap); +    return name; +} + +sp<ISurface> UserClient::createSurface( +        ISurfaceComposerClient::surface_data_t* params, int pid, +        const String8& name, +        DisplayID display, uint32_t w, uint32_t h, PixelFormat format, +        uint32_t flags) { +    return 0; +} +status_t UserClient::destroySurface(SurfaceID sid) { +    return INVALID_OPERATION; +} +status_t UserClient::setState(int32_t count, const layer_state_t* states) { +    return INVALID_OPERATION;  }  // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h index d75dc15f18..0bfc1709e8 100644 --- a/libs/surfaceflinger/SurfaceFlinger.h +++ b/libs/surfaceflinger/SurfaceFlinger.h @@ -32,11 +32,10 @@  #include <ui/PixelFormat.h>  #include <surfaceflinger/ISurfaceComposer.h> -#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurfaceComposerClient.h>  #include "Barrier.h"  #include "Layer.h" -#include "Tokenizer.h"  #include "MessageQueue.h" @@ -48,55 +47,80 @@ namespace android {  // ---------------------------------------------------------------------------  class Client; -class BClient;  class DisplayHardware;  class FreezeLock;  class Layer; +class LayerBlur; +class LayerDim;  class LayerBuffer; -typedef int32_t ClientID; -  #define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))  #define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))  // --------------------------------------------------------------------------- -class Client : public RefBase +class Client : public BnSurfaceComposerClient +{ +public: +        Client(const sp<SurfaceFlinger>& flinger); +        ~Client(); + +    status_t initCheck() const; + +    // protected by SurfaceFlinger::mStateLock +    ssize_t attachLayer(const sp<LayerBaseClient>& layer); +    void detachLayer(const LayerBaseClient* layer); +    sp<LayerBaseClient> getLayerUser(int32_t i) const; + +private: + +    // ISurfaceComposerClient interface +    virtual sp<IMemoryHeap> getControlBlock() const; +    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const; +    virtual sp<ISurface> createSurface( +            surface_data_t* params, int pid, const String8& name, +            DisplayID display, uint32_t w, uint32_t h,PixelFormat format, +            uint32_t flags); +    virtual status_t destroySurface(SurfaceID surfaceId); +    virtual status_t setState(int32_t count, const layer_state_t* states); + +    DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers; +    sp<SurfaceFlinger> mFlinger; +    int32_t mNameGenerator; +}; + +class UserClient : public BnSurfaceComposerClient  {  public: -            Client(ClientID cid, const sp<SurfaceFlinger>& flinger); -            ~Client(); - -            int32_t                 generateId(int pid); -            void                    free(int32_t id); -            status_t                bindLayer(const sp<LayerBaseClient>& layer, int32_t id); - -    inline  bool                    isValid(int32_t i) const; -    sp<LayerBaseClient>             getLayerUser(int32_t i) const; -    void                            dump(const char* what); -     -    const Vector< wp<LayerBaseClient> >& getLayers() const {  -        return mLayers;  -    } -     -    const sp<IMemoryHeap>& getControlBlockMemory() const { -        return mCblkHeap;  -    } -          // pointer to this client's control block -    SharedClient*           ctrlblk; -    ClientID                cid; +    SharedClient* ctrlblk; + +public: +        UserClient(const sp<SurfaceFlinger>& flinger); +        ~UserClient(); + +    status_t initCheck() const; + +    // protected by SurfaceFlinger::mStateLock +    void detachLayer(const Layer* layer); -      private: -    int getClientPid() const { return mPid; } -         -    int                             mPid; -    uint32_t                        mBitmap; -    SortedVector<uint8_t>           mInUse; -    Vector< wp<LayerBaseClient> >   mLayers; -    sp<IMemoryHeap>                 mCblkHeap; -    sp<SurfaceFlinger>              mFlinger; + +    // ISurfaceComposerClient interface +    virtual sp<IMemoryHeap> getControlBlock() const; +    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const; +    virtual sp<ISurface> createSurface( +            surface_data_t* params, int pid, const String8& name, +            DisplayID display, uint32_t w, uint32_t h,PixelFormat format, +            uint32_t flags); +    virtual status_t destroySurface(SurfaceID surfaceId); +    virtual status_t setState(int32_t count, const layer_state_t* states); + +    // atomic-ops +    mutable volatile int32_t mBitmap; + +    sp<IMemoryHeap> mCblkHeap; +    sp<SurfaceFlinger> mFlinger;  };  // --------------------------------------------------------------------------- @@ -159,7 +183,8 @@ public:      virtual status_t dump(int fd, const Vector<String16>& args);      // ISurfaceComposer interface -    virtual sp<ISurfaceFlingerClient>   createConnection(); +    virtual sp<ISurfaceComposerClient>  createConnection(); +    virtual sp<ISurfaceComposerClient>  createClientConnection();      virtual sp<IMemoryHeap>             getCblk() const;      virtual void                        bootFinished();      virtual void                        openGlobalTransaction(); @@ -174,13 +199,14 @@ public:              overlay_control_device_t* getOverlayEngine() const; -                  status_t removeLayer(const sp<LayerBase>& layer);      status_t addLayer(const sp<LayerBase>& layer);      status_t invalidateLayerVisibility(const sp<LayerBase>& layer); -     + +    sp<Layer> getLayer(const sp<ISurface>& sur) const; +  private: -    friend class BClient; +    friend class Client;      friend class LayerBase;      friend class LayerBuffer;      friend class LayerBaseClient; @@ -189,31 +215,33 @@ private:      friend class LayerBlur;      friend class LayerDim; -    sp<ISurface> createSurface(ClientID client, int pid, const String8& name, -            ISurfaceFlingerClient::surface_data_t* params, +    sp<ISurface> createSurface(const sp<Client>& client, +            int pid, const String8& name, +            ISurfaceComposerClient::surface_data_t* params,              DisplayID display, uint32_t w, uint32_t h, PixelFormat format,              uint32_t flags); -    sp<LayerBaseClient> createNormalSurfaceLocked( +    sp<Layer> createNormalSurface(              const sp<Client>& client, DisplayID display, -            int32_t id, uint32_t w, uint32_t h, uint32_t flags, +            uint32_t w, uint32_t h, uint32_t flags,              PixelFormat& format); -    sp<LayerBaseClient> createBlurSurfaceLocked( +    sp<LayerBlur> createBlurSurface(              const sp<Client>& client, DisplayID display, -            int32_t id, uint32_t w, uint32_t h, uint32_t flags); +            uint32_t w, uint32_t h, uint32_t flags); -    sp<LayerBaseClient> createDimSurfaceLocked( +    sp<LayerDim> createDimSurface(              const sp<Client>& client, DisplayID display, -            int32_t id, uint32_t w, uint32_t h, uint32_t flags); +            uint32_t w, uint32_t h, uint32_t flags); -    sp<LayerBaseClient> createPushBuffersSurfaceLocked( +    sp<LayerBuffer> createPushBuffersSurface(              const sp<Client>& client, DisplayID display, -            int32_t id, uint32_t w, uint32_t h, uint32_t flags); +            uint32_t w, uint32_t h, uint32_t flags); -    status_t removeSurface(SurfaceID surface_id); +    status_t removeSurface(const sp<Client>& client, SurfaceID sid);      status_t destroySurface(const sp<LayerBaseClient>& layer); -    status_t setClientState(ClientID cid, int32_t count, const layer_state_t* states); +    status_t setClientState(const sp<Client>& client, +            int32_t count, const layer_state_t* states);      class LayerVector { @@ -256,8 +284,6 @@ private:  public:     // hack to work around gcc 4.0.3 bug              void        signalEvent();  private: -            void        signalDelayedEvent(nsecs_t delay); -              void        handleConsoleEvents();              void        handleTransaction(uint32_t transactionFlags);              void        handleTransactionLocked( @@ -278,15 +304,14 @@ private:              void        unlockClients(); -            void        destroyConnection(ClientID cid); -            sp<LayerBaseClient> getLayerUser_l(SurfaceID index) const; +            ssize_t     addClientLayer(const sp<Client>& client, +                    const sp<LayerBaseClient>& lbc);              status_t    addLayer_l(const sp<LayerBase>& layer);              status_t    removeLayer_l(const sp<LayerBase>& layer);              status_t    purgatorizeLayer_l(const sp<LayerBase>& layer); -            void        free_resources_l();              uint32_t    getTransactionFlags(uint32_t flags); -            uint32_t    setTransactionFlags(uint32_t flags, nsecs_t delay = 0); +            uint32_t    setTransactionFlags(uint32_t flags);              void        commitTransaction(); @@ -310,9 +335,13 @@ private:      mutable     MessageQueue    mEventQueue; -     -                 -                 + +    status_t postMessageAsync(const sp<MessageBase>& msg, +            nsecs_t reltime=0, uint32_t flags = 0); + +    status_t postMessageSync(const sp<MessageBase>& msg, +            nsecs_t reltime=0, uint32_t flags = 0); +                  // access must be protected by mStateLock      mutable     Mutex                   mStateLock;                  State                   mCurrentState; @@ -321,14 +350,11 @@ private:      volatile    int32_t                 mTransactionCount;                  Condition               mTransactionCV;                  bool                    mResizeTransationPending; -                 +                  // protected by mStateLock (but we could use another lock) -                Tokenizer                               mTokens; -                DefaultKeyedVector<ClientID, sp<Client> >   mClientsMap; -                DefaultKeyedVector<SurfaceID, sp<LayerBaseClient> >   mLayerMap; -                GraphicPlane                            mGraphicPlanes[1]; -                bool                                    mLayersRemoved; -                Vector< sp<Client> >                    mDisconnectedClients; +                GraphicPlane                mGraphicPlanes[1]; +                bool                        mLayersRemoved; +                DefaultKeyedVector< wp<IBinder>, wp<Layer> > mLayerMap;                  // constant members (no synchronization needed for access)                  sp<IMemoryHeap>             mServerHeap; @@ -389,32 +415,6 @@ public:  };  // --------------------------------------------------------------------------- - -class BClient : public BnSurfaceFlingerClient -{ -public: -    BClient(SurfaceFlinger *flinger, ClientID cid, -            const sp<IMemoryHeap>& cblk); -    ~BClient(); - -    // ISurfaceFlingerClient interface -    virtual sp<IMemoryHeap> getControlBlock() const; - -    virtual sp<ISurface> createSurface( -            surface_data_t* params, int pid, const String8& name, -            DisplayID display, uint32_t w, uint32_t h,PixelFormat format, -            uint32_t flags); - -    virtual status_t destroySurface(SurfaceID surfaceId); -    virtual status_t setState(int32_t count, const layer_state_t* states); - -private: -    ClientID            mId; -    SurfaceFlinger*     mFlinger; -    sp<IMemoryHeap>     mCblk; -}; - -// ---------------------------------------------------------------------------  }; // namespace android  #endif // ANDROID_SURFACE_FLINGER_H diff --git a/libs/surfaceflinger/TextureManager.cpp b/libs/surfaceflinger/TextureManager.cpp new file mode 100644 index 0000000000..ee2159b3ff --- /dev/null +++ b/libs/surfaceflinger/TextureManager.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/Log.h> + +#include <ui/GraphicBuffer.h> + +#include <GLES/gl.h> +#include <GLES/glext.h> + +#include <hardware/hardware.h> + +#include "clz.h" +#include "DisplayHardware/DisplayHardware.h" +#include "TextureManager.h" + +namespace android { + +// --------------------------------------------------------------------------- + +TextureManager::TextureManager(uint32_t flags) +    : mFlags(flags) +{ +} + +GLuint TextureManager::createTexture() +{ +    GLuint textureName = -1; +    glGenTextures(1, &textureName); +    glBindTexture(GL_TEXTURE_2D, textureName); +    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); +    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +    return textureName; +} + +bool TextureManager::isSupportedYuvFormat(int format) +{ +    switch (format) { +        case HAL_PIXEL_FORMAT_YCbCr_422_SP: +        case HAL_PIXEL_FORMAT_YCbCr_420_SP: +        case HAL_PIXEL_FORMAT_YCbCr_422_P: +        case HAL_PIXEL_FORMAT_YCbCr_420_P: +        case HAL_PIXEL_FORMAT_YCbCr_422_I: +        case HAL_PIXEL_FORMAT_YCbCr_420_I: +        case HAL_PIXEL_FORMAT_YCrCb_420_SP: +            return true; +    } +    return false; +} + +status_t TextureManager::initEglImage(Image* texture, +        EGLDisplay dpy, const sp<GraphicBuffer>& buffer) +{ +    status_t err = NO_ERROR; +    if (!texture->dirty) return err; + +    // free the previous image +    if (texture->image != EGL_NO_IMAGE_KHR) { +        eglDestroyImageKHR(dpy, texture->image); +        texture->image = EGL_NO_IMAGE_KHR; +    } + +    // construct an EGL_NATIVE_BUFFER_ANDROID +    android_native_buffer_t* clientBuf = buffer->getNativeBuffer(); + +    // create the new EGLImageKHR +    const EGLint attrs[] = { +            EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE, +            EGL_NONE,                   EGL_NONE +    }; +    texture->image = eglCreateImageKHR( +            dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, +            (EGLClientBuffer)clientBuf, attrs); + +    if (texture->image != EGL_NO_IMAGE_KHR) { +        if (texture->name == -1UL) { +            texture->name = createTexture(); +            texture->width = 0; +            texture->height = 0; +        } +        glBindTexture(GL_TEXTURE_2D, texture->name); +        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, +                (GLeglImageOES)texture->image); +        GLint error = glGetError(); +        if (error != GL_NO_ERROR) { +            LOGE("glEGLImageTargetTexture2DOES(%p) failed err=0x%04x", +                    texture->image, error); +            err = INVALID_OPERATION; +        } else { +            // Everything went okay! +            texture->dirty  = false; +            texture->width  = clientBuf->width; +            texture->height = clientBuf->height; +        } +    } else { +        LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError()); +        err = INVALID_OPERATION; +    } +    return err; +} + +status_t TextureManager::loadTexture(Texture* texture, +        const Region& dirty, const GGLSurface& t) +{ +    if (texture->name == -1UL) { +        texture->name = createTexture(); +        texture->width = 0; +        texture->height = 0; +    } + +    glBindTexture(GL_TEXTURE_2D, texture->name); + +    /* +     * In OpenGL ES we can't specify a stride with glTexImage2D (however, +     * GL_UNPACK_ALIGNMENT is a limited form of stride). +     * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we +     * need to do something reasonable (here creating a bigger texture). +     * +     * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT); +     * +     * This situation doesn't happen often, but some h/w have a limitation +     * for their framebuffer (eg: must be multiple of 8 pixels), and +     * we need to take that into account when using these buffers as +     * textures. +     * +     * This should never be a problem with POT textures +     */ + +    int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format)); +    unpack = 1 << ((unpack > 3) ? 3 : unpack); +    glPixelStorei(GL_UNPACK_ALIGNMENT, unpack); + +    /* +     * round to POT if needed +     */ +    if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) { +        texture->NPOTAdjust = true; +    } + +    if (texture->NPOTAdjust) { +        // find the smallest power-of-two that will accommodate our surface +        texture->potWidth  = 1 << (31 - clz(t.width)); +        texture->potHeight = 1 << (31 - clz(t.height)); +        if (texture->potWidth  < t.width)  texture->potWidth  <<= 1; +        if (texture->potHeight < t.height) texture->potHeight <<= 1; +        texture->wScale = float(t.width)  / texture->potWidth; +        texture->hScale = float(t.height) / texture->potHeight; +    } else { +        texture->potWidth  = t.width; +        texture->potHeight = t.height; +    } + +    Rect bounds(dirty.bounds()); +    GLvoid* data = 0; +    if (texture->width != t.width || texture->height != t.height) { +        texture->width  = t.width; +        texture->height = t.height; + +        // texture size changed, we need to create a new one +        bounds.set(Rect(t.width, t.height)); +        if (t.width  == texture->potWidth && +            t.height == texture->potHeight) { +            // we can do it one pass +            data = t.data; +        } + +        if (t.format == HAL_PIXEL_FORMAT_RGB_565) { +            glTexImage2D(GL_TEXTURE_2D, 0, +                    GL_RGB, texture->potWidth, texture->potHeight, 0, +                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); +        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { +            glTexImage2D(GL_TEXTURE_2D, 0, +                    GL_RGBA, texture->potWidth, texture->potHeight, 0, +                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); +        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || +                   t.format == HAL_PIXEL_FORMAT_RGBX_8888) { +            glTexImage2D(GL_TEXTURE_2D, 0, +                    GL_RGBA, texture->potWidth, texture->potHeight, 0, +                    GL_RGBA, GL_UNSIGNED_BYTE, data); +        } else if (isSupportedYuvFormat(t.format)) { +            // just show the Y plane of YUV buffers +            glTexImage2D(GL_TEXTURE_2D, 0, +                    GL_LUMINANCE, texture->potWidth, texture->potHeight, 0, +                    GL_LUMINANCE, GL_UNSIGNED_BYTE, data); +        } else { +            // oops, we don't handle this format! +            LOGE("texture=%d, using format %d, which is not " +                 "supported by the GL", texture->name, t.format); +        } +    } +    if (!data) { +        if (t.format == HAL_PIXEL_FORMAT_RGB_565) { +            glTexSubImage2D(GL_TEXTURE_2D, 0, +                    0, bounds.top, t.width, bounds.height(), +                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5, +                    t.data + bounds.top*t.stride*2); +        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { +            glTexSubImage2D(GL_TEXTURE_2D, 0, +                    0, bounds.top, t.width, bounds.height(), +                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, +                    t.data + bounds.top*t.stride*2); +        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || +                   t.format == HAL_PIXEL_FORMAT_RGBX_8888) { +            glTexSubImage2D(GL_TEXTURE_2D, 0, +                    0, bounds.top, t.width, bounds.height(), +                    GL_RGBA, GL_UNSIGNED_BYTE, +                    t.data + bounds.top*t.stride*4); +        } else if (isSupportedYuvFormat(t.format)) { +            // just show the Y plane of YUV buffers +            glTexSubImage2D(GL_TEXTURE_2D, 0, +                    0, bounds.top, t.width, bounds.height(), +                    GL_LUMINANCE, GL_UNSIGNED_BYTE, +                    t.data + bounds.top*t.stride); +        } +    } +    return NO_ERROR; +} + +// --------------------------------------------------------------------------- + +}; // namespace android diff --git a/libs/surfaceflinger/TextureManager.h b/libs/surfaceflinger/TextureManager.h new file mode 100644 index 0000000000..d0acfe90ac --- /dev/null +++ b/libs/surfaceflinger/TextureManager.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_TEXTURE_MANAGER_H +#define ANDROID_TEXTURE_MANAGER_H + +#include <stdint.h> +#include <sys/types.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES/gl.h> + +#include <ui/Region.h> + +#include <pixelflinger/pixelflinger.h> + +namespace android { + +// --------------------------------------------------------------------------- + +class GraphicBuffer; + +// --------------------------------------------------------------------------- + +struct Image { +    Image() : name(-1U), image(EGL_NO_IMAGE_KHR), width(0), height(0), +        transform(0), dirty(true) { } +    GLuint        name; +    EGLImageKHR   image; +    GLuint        width; +    GLuint        height; +    uint32_t      transform; +    bool          dirty; +}; + +struct Texture : public Image { +    Texture() : Image(), NPOTAdjust(false)  { } +    GLuint        potWidth; +    GLuint        potHeight; +    GLfloat       wScale; +    GLfloat       hScale; +    bool          NPOTAdjust; +}; + +// --------------------------------------------------------------------------- + +class TextureManager { +    uint32_t mFlags; +    GLuint createTexture(); +    static bool isSupportedYuvFormat(int format); +public: + +    TextureManager(uint32_t flags); + +    // load bitmap data into the active buffer +    status_t loadTexture(Texture* texture, +            const Region& dirty, const GGLSurface& t); + +    // make active buffer an EGLImage if needed +    status_t initEglImage(Image* texture, +            EGLDisplay dpy, const sp<GraphicBuffer>& buffer); +}; + +// --------------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_TEXTURE_MANAGER_H diff --git a/libs/surfaceflinger/Tokenizer.cpp b/libs/surfaceflinger/Tokenizer.cpp deleted file mode 100644 index be3a239836..0000000000 --- a/libs/surfaceflinger/Tokenizer.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdio.h> - -#include "Tokenizer.h" - -// ---------------------------------------------------------------------------- - -namespace android { - -ANDROID_BASIC_TYPES_TRAITS(Tokenizer::run_t) - -Tokenizer::Tokenizer() -{ -} - -Tokenizer::Tokenizer(const Tokenizer& other) -    : mRanges(other.mRanges) -{ -} - -Tokenizer::~Tokenizer() -{ -} - -uint32_t Tokenizer::acquire() -{ -    if (!mRanges.size() || mRanges[0].first) { -        _insertTokenAt(0,0); -        return 0; -    } -     -    // just extend the first run -    const run_t& run = mRanges[0]; -    uint32_t token = run.first + run.length; -    _insertTokenAt(token, 1); -    return token; -} - -bool Tokenizer::isAcquired(uint32_t token) const -{ -    return (_indexOrderOf(token) >= 0); -} - -status_t Tokenizer::reserve(uint32_t token) -{ -    size_t o; -    const ssize_t i = _indexOrderOf(token, &o); -    if (i >= 0) { -        return BAD_VALUE; // this token is already taken -    } -    ssize_t err = _insertTokenAt(token, o); -    return (err<0) ? err : status_t(NO_ERROR); -} - -status_t Tokenizer::release(uint32_t token) -{ -    const ssize_t i = _indexOrderOf(token); -    if (i >= 0) { -        const run_t& run = mRanges[i]; -        if ((token >= run.first) && (token < run.first+run.length)) { -            // token in this range, we need to split -            run_t& run = mRanges.editItemAt(i); -            if ((token == run.first) || (token == run.first+run.length-1)) { -                if (token == run.first) { -                    run.first += 1; -                } -                run.length -= 1; -                if (run.length == 0) { -                    // XXX: should we systematically remove a run that's empty? -                    mRanges.removeItemsAt(i); -                } -            } else { -                // split the run -                run_t new_run; -                new_run.first = token+1; -                new_run.length = run.first+run.length - new_run.first; -                run.length = token - run.first; -                mRanges.insertAt(new_run, i+1); -            } -            return NO_ERROR; -        } -    } -    return NAME_NOT_FOUND; -} - -ssize_t Tokenizer::_indexOrderOf(uint32_t token, size_t* order) const -{ -    // binary search -    ssize_t err = NAME_NOT_FOUND; -    ssize_t l = 0; -    ssize_t h = mRanges.size()-1; -    ssize_t mid; -    const run_t* a = mRanges.array(); -    while (l <= h) { -        mid = l + (h - l)/2; -        const run_t* const curr = a + mid; -        int c = 0; -        if (token < curr->first)                        c = 1; -        else if (token >= curr->first+curr->length)     c = -1; -        if (c == 0) { -            err = l = mid; -            break; -        } else if (c < 0) { -            l = mid + 1; -        } else { -            h = mid - 1; -        } -    } -    if (order) *order = l; -    return err; -} - -ssize_t Tokenizer::_insertTokenAt(uint32_t token, size_t index) -{ -    const size_t c = mRanges.size(); - -    if (index >= 1) { -        // do we need to merge with the previous run? -        run_t& p = mRanges.editItemAt(index-1); -        if (p.first+p.length == token) { -            p.length += 1; -            if (index < c) { -                const run_t& n = mRanges[index]; -                if (token+1 == n.first) { -                    p.length += n.length; -                    mRanges.removeItemsAt(index); -                } -            } -            return index; -        } -    } -     -    if (index < c) { -        // do we need to merge with the next run? -        run_t& n = mRanges.editItemAt(index); -        if (token+1 == n.first) { -            n.first -= 1; -            n.length += 1; -            return index; -        } -    } - -    return mRanges.insertAt(run_t(token,1), index); -} - -void Tokenizer::dump() const -{ -    const run_t* ranges = mRanges.array(); -    const size_t c = mRanges.size(); -    printf("Tokenizer (%p, size = %d)\n", this, int(c)); -    for (size_t i=0 ; i<c ; i++) { -        printf("%u: (%u, %u)\n", i, -                uint32_t(ranges[i].first), uint32_t(ranges[i].length)); -    } -} - -}; // namespace android - diff --git a/libs/surfaceflinger/Tokenizer.h b/libs/surfaceflinger/Tokenizer.h deleted file mode 100644 index 6b3057d240..0000000000 --- a/libs/surfaceflinger/Tokenizer.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_TOKENIZER_H -#define ANDROID_TOKENIZER_H - -#include <utils/Vector.h> -#include <utils/Errors.h> - -// ---------------------------------------------------------------------------- - -namespace android { - -class Tokenizer -{ -public: -                Tokenizer(); -                Tokenizer(const Tokenizer& other); -                ~Tokenizer(); - -    uint32_t    acquire(); -    status_t    reserve(uint32_t token); -    status_t    release(uint32_t token); -    bool        isAcquired(uint32_t token) const; - -    void dump() const; - -    struct run_t { -        run_t() {}; -        run_t(uint32_t f, uint32_t l) : first(f), length(l) {} -        uint32_t    first; -        uint32_t    length; -    }; -private: -    ssize_t _indexOrderOf(uint32_t token, size_t* order=0) const; -    ssize_t _insertTokenAt(uint32_t token, size_t index); -    Vector<run_t>   mRanges; -}; - -}; // namespace android - -// ---------------------------------------------------------------------------- - -#endif // ANDROID_TOKENIZER_H diff --git a/libs/surfaceflinger/Transform.cpp b/libs/surfaceflinger/Transform.cpp index 175f989ef0..5e27cc9bd9 100644 --- a/libs/surfaceflinger/Transform.cpp +++ b/libs/surfaceflinger/Transform.cpp @@ -229,14 +229,13 @@ Transform::vec3 Transform::transform(const vec3& v) const {      return r;  } -void Transform::transform(fixed1616* point, int x, int y) const +void Transform::transform(float* point, int x, int y) const  { -    const float toFixed = 65536.0f;      const mat33& M(mMatrix);      vec2 v(x, y);      v = transform(v); -    point[0] = v[0] * toFixed; -    point[1] = v[1] * toFixed; +    point[0] = v[0]; +    point[1] = v[1];  }  Rect Transform::makeBounds(int w, int h) const diff --git a/libs/surfaceflinger/Transform.h b/libs/surfaceflinger/Transform.h index 2e5b893ece..20fa11a46a 100644 --- a/libs/surfaceflinger/Transform.h +++ b/libs/surfaceflinger/Transform.h @@ -37,8 +37,6 @@ public:             explicit Transform(uint32_t orientation);                      ~Transform(); -            typedef int32_t fixed1616; -              // FIXME: must match OVERLAY_TRANSFORM_*, pull from hardware.h              enum orientation_flags {                  ROT_0   = 0x00000000, @@ -76,7 +74,7 @@ public:              // transform data              Rect    makeBounds(int w, int h) const; -            void    transform(fixed1616* point, int x, int y) const; +            void    transform(float* point, int x, int y) const;              Region  transform(const Region& reg) const;              Transform operator * (const Transform& rhs) const; diff --git a/libs/surfaceflinger_client/Android.mk b/libs/surfaceflinger_client/Android.mk index fe85b34986..ce3c71a7d9 100644 --- a/libs/surfaceflinger_client/Android.mk +++ b/libs/surfaceflinger_client/Android.mk @@ -4,7 +4,7 @@ include $(CLEAR_VARS)  LOCAL_SRC_FILES:= \  	ISurfaceComposer.cpp \  	ISurface.cpp \ -	ISurfaceFlingerClient.cpp \ +	ISurfaceComposerClient.cpp \  	LayerState.cpp \  	SharedBufferStack.cpp \  	Surface.cpp \ diff --git a/libs/surfaceflinger_client/ISurface.cpp b/libs/surfaceflinger_client/ISurface.cpp index bb86199876..7049d9e42d 100644 --- a/libs/surfaceflinger_client/ISurface.cpp +++ b/libs/surfaceflinger_client/ISurface.cpp @@ -71,11 +71,15 @@ public:      {      } -    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) +    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, +            uint32_t w, uint32_t h, uint32_t format, uint32_t usage)      {          Parcel data, reply;          data.writeInterfaceToken(ISurface::getInterfaceDescriptor());          data.writeInt32(bufferIdx); +        data.writeInt32(w); +        data.writeInt32(h); +        data.writeInt32(format);          data.writeInt32(usage);          remote()->transact(REQUEST_BUFFER, data, &reply);          sp<GraphicBuffer> buffer = new GraphicBuffer(); @@ -83,6 +87,16 @@ public:          return buffer;      } +    virtual status_t setBufferCount(int bufferCount) +    { +        Parcel data, reply; +        data.writeInterfaceToken(ISurface::getInterfaceDescriptor()); +        data.writeInt32(bufferCount); +        remote()->transact(SET_BUFFER_COUNT, data, &reply); +        status_t err = reply.readInt32(); +        return err; +    } +      virtual status_t registerBuffers(const BufferHeap& buffers)      {          Parcel data, reply; @@ -140,12 +154,22 @@ status_t BnSurface::onTransact(          case REQUEST_BUFFER: {              CHECK_INTERFACE(ISurface, data, reply);              int bufferIdx = data.readInt32(); -            int usage = data.readInt32(); -            sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage)); +            uint32_t w = data.readInt32(); +            uint32_t h = data.readInt32(); +            uint32_t format = data.readInt32(); +            uint32_t usage = data.readInt32(); +            sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format, usage));              if (buffer == NULL)                  return BAD_VALUE;              return reply->write(*buffer);          } +        case SET_BUFFER_COUNT: { +            CHECK_INTERFACE(ISurface, data, reply); +            int bufferCount = data.readInt32(); +            status_t err = setBufferCount(bufferCount); +            reply->writeInt32(err); +            return NO_ERROR; +        }          case REGISTER_BUFFERS: {              CHECK_INTERFACE(ISurface, data, reply);              BufferHeap buffer; diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp index b6f4e24a2a..5c111f64c7 100644 --- a/libs/surfaceflinger_client/ISurfaceComposer.cpp +++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp @@ -46,13 +46,22 @@ public:      {      } -    virtual sp<ISurfaceFlingerClient> createConnection() +    virtual sp<ISurfaceComposerClient> createConnection()      {          uint32_t n;          Parcel data, reply;          data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());          remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply); -        return interface_cast<ISurfaceFlingerClient>(reply.readStrongBinder()); +        return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder()); +    } + +    virtual sp<ISurfaceComposerClient> createClientConnection() +    { +        uint32_t n; +        Parcel data, reply; +        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); +        remote()->transact(BnSurfaceComposer::CREATE_CLIENT_CONNECTION, data, &reply); +        return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());      }      virtual sp<IMemoryHeap> getCblk() const @@ -136,6 +145,11 @@ status_t BnSurfaceComposer::onTransact(              sp<IBinder> b = createConnection()->asBinder();              reply->writeStrongBinder(b);          } break; +        case CREATE_CLIENT_CONNECTION: { +            CHECK_INTERFACE(ISurfaceComposer, data, reply); +            sp<IBinder> b = createClientConnection()->asBinder(); +            reply->writeStrongBinder(b); +        } break;          case OPEN_GLOBAL_TRANSACTION: {              CHECK_INTERFACE(ISurfaceComposer, data, reply);              openGlobalTransaction(); diff --git a/libs/surfaceflinger_client/ISurfaceFlingerClient.cpp b/libs/surfaceflinger_client/ISurfaceComposerClient.cpp index def96d70ff..2cc1f8e343 100644 --- a/libs/surfaceflinger_client/ISurfaceFlingerClient.cpp +++ b/libs/surfaceflinger_client/ISurfaceComposerClient.cpp @@ -30,7 +30,7 @@  #include <ui/Rect.h>  #include <surfaceflinger/ISurface.h> -#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurfaceComposerClient.h>  #include <private/surfaceflinger/LayerState.h>  // --------------------------------------------------------------------------- @@ -51,27 +51,37 @@ namespace android {  enum {      GET_CBLK = IBinder::FIRST_CALL_TRANSACTION, +    GET_TOKEN,      CREATE_SURFACE,      DESTROY_SURFACE,      SET_STATE  }; -class BpSurfaceFlingerClient : public BpInterface<ISurfaceFlingerClient> +class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient>  {  public: -    BpSurfaceFlingerClient(const sp<IBinder>& impl) -        : BpInterface<ISurfaceFlingerClient>(impl) +    BpSurfaceComposerClient(const sp<IBinder>& impl) +        : BpInterface<ISurfaceComposerClient>(impl)      {      }      virtual sp<IMemoryHeap> getControlBlock() const      {          Parcel data, reply; -        data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); +        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());          remote()->transact(GET_CBLK, data, &reply);          return interface_cast<IMemoryHeap>(reply.readStrongBinder());      } +    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const +    { +        Parcel data, reply; +        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); +        data.writeStrongBinder(sur->asBinder()); +        remote()->transact(GET_TOKEN, data, &reply); +        return reply.readInt32(); +    } +      virtual sp<ISurface> createSurface( surface_data_t* params,                                          int pid,                                          const String8& name, @@ -82,7 +92,7 @@ public:                                          uint32_t flags)      {          Parcel data, reply; -        data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); +        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());          data.writeInt32(pid);          data.writeString8(name);          data.writeInt32(display); @@ -94,11 +104,11 @@ public:          params->readFromParcel(reply);          return interface_cast<ISurface>(reply.readStrongBinder());      } -                                     +      virtual status_t destroySurface(SurfaceID sid)      {          Parcel data, reply; -        data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); +        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());          data.writeInt32(sid);          remote()->transact(DESTROY_SURFACE, data, &reply);          return reply.readInt32(); @@ -107,7 +117,7 @@ public:      virtual status_t setState(int32_t count, const layer_state_t* states)      {          Parcel data, reply; -        data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); +        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());          data.writeInt32(count);          for (int i=0 ; i<count ; i++)              states[i].write(data); @@ -116,26 +126,33 @@ public:      }  }; -IMPLEMENT_META_INTERFACE(SurfaceFlingerClient, "android.ui.ISurfaceFlingerClient"); +IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient");  // ---------------------------------------------------------------------- -status_t BnSurfaceFlingerClient::onTransact( +status_t BnSurfaceComposerClient::onTransact(      uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  {      // codes that don't require permission check      switch(code) {          case GET_CBLK: { -            CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); +            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);              sp<IMemoryHeap> ctl(getControlBlock());              reply->writeStrongBinder(ctl->asBinder());              return NO_ERROR;          } break; +        case GET_TOKEN: { +            CHECK_INTERFACE(ISurfaceComposerClient, data, reply); +            sp<ISurface> sur = interface_cast<ISurface>(data.readStrongBinder()); +            ssize_t token = getTokenForSurface(sur); +            reply->writeInt32(token); +            return NO_ERROR; +        } break;      }      // these must be checked -      +       IPCThreadState* ipc = IPCThreadState::self();       const int pid = ipc->getCallingPid();       const int uid = ipc->getCallingUid(); @@ -150,10 +167,10 @@ status_t BnSurfaceFlingerClient::onTransact(               return PERMISSION_DENIED;           }       } -    +       switch(code) {          case CREATE_SURFACE: { -            CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); +            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);              surface_data_t params;              int32_t pid = data.readInt32();              String8 name = data.readString8(); @@ -169,12 +186,12 @@ status_t BnSurfaceFlingerClient::onTransact(              return NO_ERROR;          } break;          case DESTROY_SURFACE: { -            CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); +            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);              reply->writeInt32( destroySurface( data.readInt32() ) );              return NO_ERROR;          } break;          case SET_STATE: { -            CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); +            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);              int32_t count = data.readInt32();              layer_state_t* states = new layer_state_t[count];              for (int i=0 ; i<count ; i++) @@ -191,7 +208,7 @@ status_t BnSurfaceFlingerClient::onTransact(  // ---------------------------------------------------------------------- -status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& parcel) +status_t ISurfaceComposerClient::surface_data_t::readFromParcel(const Parcel& parcel)  {      token    = parcel.readInt32();      identity = parcel.readInt32(); @@ -201,7 +218,7 @@ status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& par      return NO_ERROR;  } -status_t ISurfaceFlingerClient::surface_data_t::writeToParcel(Parcel* parcel) const +status_t ISurfaceComposerClient::surface_data_t::writeToParcel(Parcel* parcel) const  {      parcel->writeInt32(token);      parcel->writeInt32(identity); diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp index a17e8acc57..d67a589ac9 100644 --- a/libs/surfaceflinger_client/SharedBufferStack.cpp +++ b/libs/surfaceflinger_client/SharedBufferStack.cpp @@ -44,15 +44,11 @@ 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)) +    if (uint32_t(i) >= uint32_t(SharedBufferStack::NUM_LAYERS_MAX))          return BAD_INDEX;      return surfaces[i].status;  } -uint32_t SharedClient::getIdentity(size_t token) const { -    return uint32_t(surfaces[token].identity); -} -  // ---------------------------------------------------------------------------- @@ -62,24 +58,52 @@ SharedBufferStack::SharedBufferStack()  void SharedBufferStack::init(int32_t i)  { -    inUse = -1; +    inUse = -2;      status = NO_ERROR;      identity = i;  } +status_t SharedBufferStack::setCrop(int buffer, const Rect& crop) +{ +    if (uint32_t(buffer) >= NUM_BUFFER_MAX) +        return BAD_INDEX; + +    buffers[buffer].crop.l = uint16_t(crop.left); +    buffers[buffer].crop.t = uint16_t(crop.top); +    buffers[buffer].crop.r = uint16_t(crop.right); +    buffers[buffer].crop.b = uint16_t(crop.bottom); +    return NO_ERROR; +} +  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); +    FlatRegion& reg(buffers[buffer].dirtyRegion); +    if (dirty.isEmpty()) { +        reg.count = 0; +        return NO_ERROR; +    } + +    size_t count; +    Rect const* r = dirty.getArray(&count); +    if (count > FlatRegion::NUM_RECT_MAX) { +        const Rect bounds(dirty.getBounds()); +        reg.count = 1; +        reg.rects[0].l = uint16_t(bounds.left); +        reg.rects[0].t = uint16_t(bounds.top); +        reg.rects[0].r = uint16_t(bounds.right); +        reg.rects[0].b = uint16_t(bounds.bottom); +    } else { +        reg.count = count; +        for (size_t i=0 ; i<count ; i++) { +            reg.rects[i].l = uint16_t(r[i].left); +            reg.rects[i].t = uint16_t(r[i].top); +            reg.rects[i].r = uint16_t(r[i].right); +            reg.rects[i].b = uint16_t(r[i].bottom); +        } +    }      return NO_ERROR;  } @@ -89,18 +113,37 @@ Region SharedBufferStack::getDirtyRegion(int buffer) const      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])); +    const FlatRegion& reg(buffers[buffer].dirtyRegion); +    if (reg.count > FlatRegion::NUM_RECT_MAX) +        return res; + +    if (reg.count == 1) { +        const Rect r( +                reg.rects[0].l, +                reg.rects[0].t, +                reg.rects[0].r, +                reg.rects[0].b); +        res.set(r); +    } else { +        for (size_t i=0 ; i<reg.count ; i++) { +            const Rect r( +                    reg.rects[i].l, +                    reg.rects[i].t, +                    reg.rects[i].r, +                    reg.rects[i].b); +            res.orSelf(r); +        } +    }      return res;  }  // ----------------------------------------------------------------------------  SharedBufferBase::SharedBufferBase(SharedClient* sharedClient, -        int surface, int num, int32_t identity) +        int surface, int32_t identity)      : mSharedClient(sharedClient),         mSharedStack(sharedClient->surfaces + surface), -      mNumBuffers(num), mIdentity(identity) +      mIdentity(identity)  {  } @@ -108,16 +151,16 @@ SharedBufferBase::~SharedBufferBase()  {  } -uint32_t SharedBufferBase::getIdentity() +status_t SharedBufferBase::getStatus() const  {      SharedBufferStack& stack( *mSharedStack ); -    return stack.identity; +    return stack.status;  } -status_t SharedBufferBase::getStatus() const +int32_t SharedBufferBase::getIdentity() const  {      SharedBufferStack& stack( *mSharedStack ); -    return stack.status; +    return stack.identity;  }  size_t SharedBufferBase::getFrontBuffer() const @@ -132,16 +175,52 @@ String8 SharedBufferBase::dump(char const* prefix) const      char buffer[SIZE];      String8 result;      SharedBufferStack& stack( *mSharedStack ); -    int tail = (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers;      snprintf(buffer, SIZE,  -            "%s[ head=%2d, available=%2d, queued=%2d, tail=%2d ] " -            "reallocMask=%08x, inUse=%2d, identity=%d, status=%d\n", -            prefix, stack.head, stack.available, stack.queued, tail, +            "%s[ head=%2d, available=%2d, queued=%2d ] " +            "reallocMask=%08x, inUse=%2d, identity=%d, status=%d", +            prefix, stack.head, stack.available, stack.queued,              stack.reallocMask, stack.inUse, stack.identity, stack.status);      result.append(buffer); +    result.append("\n");      return result;  } +status_t SharedBufferBase::waitForCondition(const ConditionBase& condition) +{ +    const SharedBufferStack& stack( *mSharedStack ); +    SharedClient& client( *mSharedClient ); +    const nsecs_t TIMEOUT = s2ns(1); +    const int identity = mIdentity; + +    Mutex::Autolock _l(client.lock); +    while ((condition()==false) && +            (stack.identity == identity) && +            (stack.status == NO_ERROR)) +    { +        status_t err = client.cv.waitRelative(client.lock, TIMEOUT); +        // handle errors and timeouts +        if (CC_UNLIKELY(err != NO_ERROR)) { +            if (err == TIMED_OUT) { +                if (condition()) { +                    LOGE("waitForCondition(%s) timed out (identity=%d), " +                        "but condition is true! We recovered but it " +                        "shouldn't happen." , condition.name(), stack.identity); +                    break; +                } else { +                    LOGW("waitForCondition(%s) timed out " +                        "(identity=%d, status=%d). " +                        "CPU may be pegged. trying again.", condition.name(), +                        stack.identity, stack.status); +                } +            } else { +                LOGE("waitForCondition(%s) error (%s) ", +                        condition.name(), strerror(-err)); +                return err; +            } +        } +    } +    return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status; +}  // ============================================================================  // conditions and updates  // ============================================================================ @@ -149,24 +228,34 @@ String8 SharedBufferBase::dump(char const* prefix) const  SharedBufferClient::DequeueCondition::DequeueCondition(          SharedBufferClient* sbc) : ConditionBase(sbc)  {   } -bool SharedBufferClient::DequeueCondition::operator()() { +bool SharedBufferClient::DequeueCondition::operator()() const {      return stack.available > 0;  }  SharedBufferClient::LockCondition::LockCondition(          SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) {   } -bool SharedBufferClient::LockCondition::operator()() { -    return (buf != stack.head ||  +bool SharedBufferClient::LockCondition::operator()() const { +    // NOTE: if stack.head is messed up, we could crash the client +    // or cause some drawing artifacts. This is okay, as long as it is +    // limited to the client. +    return (buf != stack.index[stack.head] ||              (stack.queued > 0 && stack.inUse != buf));  }  SharedBufferServer::ReallocateCondition::ReallocateCondition(          SharedBufferBase* sbb, int buf) : ConditionBase(sbb), buf(buf) {   } -bool SharedBufferServer::ReallocateCondition::operator()() { +bool SharedBufferServer::ReallocateCondition::operator()() const { +    int32_t head = stack.head; +    if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX) { +        // if stack.head is messed up, we cannot allow the server to +        // crash (since stack.head is mapped on the client side) +        stack.status = BAD_VALUE; +        return false; +    }      // TODO: we should also check that buf has been dequeued -    return (buf != stack.head); +    return (buf != stack.index[head]);  }  // ---------------------------------------------------------------------------- @@ -193,8 +282,10 @@ SharedBufferServer::UnlockUpdate::UnlockUpdate(  }  ssize_t SharedBufferServer::UnlockUpdate::operator()() {      if (stack.inUse != lockedBuffer) { -        LOGE("unlocking %d, but currently locked buffer is %d", -                lockedBuffer, stack.inUse); +        LOGE("unlocking %d, but currently locked buffer is %d " +             "(identity=%d, token=%d)", +                lockedBuffer, stack.inUse, +                stack.identity, stack.token);          return BAD_VALUE;      }      android_atomic_write(-1, &stack.inUse); @@ -206,11 +297,12 @@ SharedBufferServer::RetireUpdate::RetireUpdate(      : 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; +    if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX) +        return BAD_VALUE;      // Preventively lock the current buffer before updating queued. -    android_atomic_write(head, &stack.inUse); +    android_atomic_write(stack.index[head], &stack.inUse);      // Decrement the number of queued buffers       int32_t queued; @@ -221,16 +313,15 @@ ssize_t SharedBufferServer::RetireUpdate::operator()() {          }      } 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 +    head = (head + 1) % numBuffers; +    android_atomic_write(stack.index[head], &stack.inUse); + +    // head is only modified here, so we don't need to use cmpxchg      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; @@ -250,41 +341,31 @@ ssize_t SharedBufferServer::StatusUpdate::operator()() {  SharedBufferClient::SharedBufferClient(SharedClient* sharedClient,          int surface, int num, int32_t identity) -    : SharedBufferBase(sharedClient, surface, num, identity), tail(0) +    : SharedBufferBase(sharedClient, surface, identity), +      mNumBuffers(num), tail(0), undoDequeueTail(0)  { +    SharedBufferStack& stack( *mSharedStack );      tail = computeTail(); +    queued_head = stack.head;  }  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; -    } else if (newTail >= mNumBuffers) { -        newTail -= mNumBuffers; -    } -    return newTail; +    return (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers;  }  ssize_t SharedBufferClient::dequeue()  {      SharedBufferStack& stack( *mSharedStack ); -    if (stack.head == tail && stack.available == 2) { +    if (stack.head == tail && stack.available == mNumBuffers) {          LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",                  tail, stack.head, stack.available, stack.queued);      } -         + +    RWLock::AutoRLock _rd(mLock); +      const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);      //LOGD("[%d] about to dequeue a buffer", @@ -301,9 +382,10 @@ ssize_t SharedBufferClient::dequeue()          LOGW("dequeue probably called from multiple threads!");      } -    int dequeued = tail; +    undoDequeueTail = tail; +    int dequeued = stack.index[tail];      tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1); -    LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail=%d, %s", +    LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail++=%d, %s",              dequeued, tail, dump("").string());      mDequeueTime[dequeued] = dequeueTime;  @@ -313,16 +395,23 @@ ssize_t SharedBufferClient::dequeue()  status_t SharedBufferClient::undoDequeue(int buf)  { +    RWLock::AutoRLock _rd(mLock); + +    // TODO: we can only undo the previous dequeue, we should +    // enforce that in the api      UndoDequeueUpdate update(this);      status_t err = updateCondition( update );      if (err == NO_ERROR) { -        tail = computeTail(); +        tail = undoDequeueTail;      }      return err;  }  status_t SharedBufferClient::lock(int buf)  { +    RWLock::AutoRLock _rd(mLock); + +    SharedBufferStack& stack( *mSharedStack );      LockCondition condition(this, buf);      status_t err = waitForCondition(condition);      return err; @@ -330,53 +419,105 @@ status_t SharedBufferClient::lock(int buf)  status_t SharedBufferClient::queue(int buf)  { +    RWLock::AutoRLock _rd(mLock); + +    SharedBufferStack& stack( *mSharedStack ); + +    queued_head = (queued_head + 1) % mNumBuffers; +    stack.index[queued_head] = 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 +bool SharedBufferClient::needNewBuffer(int buf) const  {      SharedBufferStack& stack( *mSharedStack ); -    const uint32_t mask = 1<<buffer; +    const uint32_t mask = 1<<(31-buf);      return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0;  } -status_t SharedBufferClient::setDirtyRegion(int buffer, const Region& reg) +status_t SharedBufferClient::setCrop(int buf, const Rect& crop)  {      SharedBufferStack& stack( *mSharedStack ); -    return stack.setDirtyRegion(buffer, reg); +    return stack.setCrop(buf, crop); +} + +status_t SharedBufferClient::setDirtyRegion(int buf, const Region& reg) +{ +    SharedBufferStack& stack( *mSharedStack ); +    return stack.setDirtyRegion(buf, reg); +} + +status_t SharedBufferClient::setBufferCount( +        int bufferCount, const SetBufferCountCallback& ipc) +{ +    SharedBufferStack& stack( *mSharedStack ); +    if (uint32_t(bufferCount) >= SharedBufferStack::NUM_BUFFER_MAX) +        return BAD_VALUE; + +    if (uint32_t(bufferCount) < SharedBufferStack::NUM_BUFFER_MIN) +        return BAD_VALUE; + +    RWLock::AutoWLock _wr(mLock); + +    status_t err = ipc(bufferCount); +    if (err == NO_ERROR) { +        mNumBuffers = bufferCount; +        queued_head = (stack.head + stack.queued) % mNumBuffers; +    } +    return err;  }  // ----------------------------------------------------------------------------  SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,          int surface, int num, int32_t identity) -    : SharedBufferBase(sharedClient, surface, num, identity) +    : SharedBufferBase(sharedClient, surface, identity), +      mNumBuffers(num)  {      mSharedStack->init(identity); +    mSharedStack->token = surface;      mSharedStack->head = num-1;      mSharedStack->available = num;      mSharedStack->queued = 0;      mSharedStack->reallocMask = 0; -    memset(mSharedStack->dirtyRegion, 0, sizeof(mSharedStack->dirtyRegion)); +    memset(mSharedStack->buffers, 0, sizeof(mSharedStack->buffers)); +    for (int i=0 ; i<num ; i++) { +        mBufferList.add(i); +        mSharedStack->index[i] = i; +    } +} + +SharedBufferServer::~SharedBufferServer() +{  }  ssize_t SharedBufferServer::retireAndLock()  { +    RWLock::AutoRLock _l(mLock); +      RetireUpdate update(this, mNumBuffers);      ssize_t buf = updateCondition( update ); -    LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s", int(buf), dump("").string()); +    if (buf >= 0) { +        if (uint32_t(buf) >= SharedBufferStack::NUM_BUFFER_MAX) +            return BAD_VALUE; +        SharedBufferStack& stack( *mSharedStack ); +        buf = stack.index[buf]; +        LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s", +                int(buf), dump("").string()); +    }      return buf;  } -status_t SharedBufferServer::unlock(int buffer) +status_t SharedBufferServer::unlock(int buf)  { -    UnlockUpdate update(this, buffer); +    UnlockUpdate update(this, buf);      status_t err = updateCondition( update );      return err;  } @@ -389,11 +530,25 @@ void SharedBufferServer::setStatus(status_t status)      }  } -status_t SharedBufferServer::reallocate() +status_t SharedBufferServer::reallocateAll()  { +    RWLock::AutoRLock _l(mLock); +      SharedBufferStack& stack( *mSharedStack ); -    uint32_t mask = (1<<mNumBuffers)-1; -    android_atomic_or(mask, &stack.reallocMask);  +    uint32_t mask = mBufferList.getMask(); +    android_atomic_or(mask, &stack.reallocMask); +    return NO_ERROR; +} + +status_t SharedBufferServer::reallocateAllExcept(int buffer) +{ +    RWLock::AutoRLock _l(mLock); + +    SharedBufferStack& stack( *mSharedStack ); +    BufferList temp(mBufferList); +    temp.remove(buffer); +    uint32_t mask = temp.getMask(); +    android_atomic_or(mask, &stack.reallocMask);      return NO_ERROR;  } @@ -403,17 +558,77 @@ int32_t SharedBufferServer::getQueuedCount() const      return stack.queued;  } -status_t SharedBufferServer::assertReallocate(int buffer) +status_t SharedBufferServer::assertReallocate(int buf)  { -    ReallocateCondition condition(this, buffer); +    /* +     * NOTE: it's safe to hold mLock for read while waiting for +     * the ReallocateCondition because that condition is not updated +     * by the thread that holds mLock for write. +     */ +    RWLock::AutoRLock _l(mLock); + +    // TODO: need to validate "buf" +    ReallocateCondition condition(this, buf);      status_t err = waitForCondition(condition);      return err;  } -Region SharedBufferServer::getDirtyRegion(int buffer) const +Region SharedBufferServer::getDirtyRegion(int buf) const +{ +    SharedBufferStack& stack( *mSharedStack ); +    return stack.getDirtyRegion(buf); +} + +/* + * NOTE: this is not thread-safe on the server-side, meaning + * 'head' cannot move during this operation. The client-side + * can safely operate an usual. + * + */ +status_t SharedBufferServer::resize(int newNumBuffers)  { +    if (uint32_t(newNumBuffers) >= SharedBufferStack::NUM_BUFFER_MAX) +        return BAD_VALUE; + +    RWLock::AutoWLock _l(mLock); + +    // for now we're not supporting shrinking +    const int numBuffers = mNumBuffers; +    if (newNumBuffers < numBuffers) +        return BAD_VALUE; +      SharedBufferStack& stack( *mSharedStack ); -    return stack.getDirtyRegion(buffer); +    const int extra = newNumBuffers - numBuffers; + +    // read the head, make sure it's valid +    int32_t head = stack.head; +    if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX) +        return BAD_VALUE; + +    int base = numBuffers; +    int32_t avail = stack.available; +    int tail = head - avail + 1; + +    if (tail >= 0) { +        int8_t* const index = const_cast<int8_t*>(stack.index); +        const int nb = numBuffers - head; +        memmove(&index[head + extra], &index[head], nb); +        base = head; +        // move head 'extra' ahead, this doesn't impact stack.index[head]; +        stack.head = head + extra; +    } +    stack.available += extra; + +    // fill the new free space with unused buffers +    BufferList::const_iterator curr(mBufferList.free_begin()); +    for (int i=0 ; i<extra ; i++) { +        stack.index[base+i] = *curr; +        mBufferList.add(*curr); +        ++curr; +    } + +    mNumBuffers = newNumBuffers; +    return NO_ERROR;  }  SharedBufferStack::Statistics SharedBufferServer::getStats() const @@ -422,6 +637,29 @@ SharedBufferStack::Statistics SharedBufferServer::getStats() const      return stack.stats;  } +// --------------------------------------------------------------------------- +status_t SharedBufferServer::BufferList::add(int value) +{ +    if (uint32_t(value) >= mCapacity) +        return BAD_VALUE; +    uint32_t mask = 1<<(31-value); +    if (mList & mask) +        return ALREADY_EXISTS; +    mList |= mask; +    return NO_ERROR; +} + +status_t SharedBufferServer::BufferList::remove(int value) +{ +    if (uint32_t(value) >= mCapacity) +        return BAD_VALUE; +    uint32_t mask = 1<<(31-value); +    if (!(mList & mask)) +        return NAME_NOT_FOUND; +    mList &= ~mask; +    return NO_ERROR; +} +  // ---------------------------------------------------------------------------  }; // namespace android diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp index 5dd75c3213..8617d94a44 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/surfaceflinger_client/Surface.cpp @@ -17,8 +17,6 @@  #define LOG_TAG "Surface"  #include <stdint.h> -#include <unistd.h> -#include <fcntl.h>  #include <errno.h>  #include <sys/types.h>  #include <sys/stat.h> @@ -28,8 +26,6 @@  #include <utils/CallStack.h>  #include <utils/Log.h> -#include <pixelflinger/pixelflinger.h> -  #include <binder/IPCThreadState.h>  #include <binder/IMemory.h> @@ -55,6 +51,8 @@ static status_t copyBlt(          const sp<GraphicBuffer>& src,           const Region& reg)  { +    // src and dst with, height and format must be identical. no verification +    // is done here.      status_t err;      uint8_t const * src_bits = NULL;      err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits); @@ -67,7 +65,6 @@ static status_t copyBlt(      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; @@ -107,7 +104,7 @@ static status_t copyBlt(  SurfaceControl::SurfaceControl(          const sp<SurfaceComposerClient>& client,           const sp<ISurface>& surface, -        const ISurfaceFlingerClient::surface_data_t& data, +        const ISurfaceComposerClient::surface_data_t& data,          uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)      : mClient(client), mSurface(surface),        mToken(data.token), mIdentity(data.identity), @@ -154,75 +151,75 @@ bool SurfaceControl::isSameSurface(  }  status_t SurfaceControl::setLayer(int32_t layer) { -    const sp<SurfaceComposerClient>& client(mClient);      status_t err = validate();      if (err < 0) return err; +    const sp<SurfaceComposerClient>& client(mClient);      return client->setLayer(mToken, layer);  }  status_t SurfaceControl::setPosition(int32_t x, int32_t y) { -    const sp<SurfaceComposerClient>& client(mClient);      status_t err = validate();      if (err < 0) return err; +    const sp<SurfaceComposerClient>& client(mClient);      return client->setPosition(mToken, x, y);  }  status_t SurfaceControl::setSize(uint32_t w, uint32_t h) { -    const sp<SurfaceComposerClient>& client(mClient);      status_t err = validate();      if (err < 0) return err; +    const sp<SurfaceComposerClient>& client(mClient);      return client->setSize(mToken, w, h);  }  status_t SurfaceControl::hide() { -    const sp<SurfaceComposerClient>& client(mClient);      status_t err = validate();      if (err < 0) return err; +    const sp<SurfaceComposerClient>& client(mClient);      return client->hide(mToken);  }  status_t SurfaceControl::show(int32_t layer) { -    const sp<SurfaceComposerClient>& client(mClient);      status_t err = validate();      if (err < 0) return err; +    const sp<SurfaceComposerClient>& client(mClient);      return client->show(mToken, layer);  }  status_t SurfaceControl::freeze() { -    const sp<SurfaceComposerClient>& client(mClient);      status_t err = validate();      if (err < 0) return err; +    const sp<SurfaceComposerClient>& client(mClient);      return client->freeze(mToken);  }  status_t SurfaceControl::unfreeze() { -    const sp<SurfaceComposerClient>& client(mClient);      status_t err = validate();      if (err < 0) return err; +    const sp<SurfaceComposerClient>& client(mClient);      return client->unfreeze(mToken);  }  status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) { -    const sp<SurfaceComposerClient>& client(mClient);      status_t err = validate();      if (err < 0) return err; +    const sp<SurfaceComposerClient>& client(mClient);      return client->setFlags(mToken, flags, mask);  }  status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) { -    const sp<SurfaceComposerClient>& client(mClient);      status_t err = validate();      if (err < 0) return err; +    const sp<SurfaceComposerClient>& client(mClient);      return client->setTransparentRegionHint(mToken, transparent);  }  status_t SurfaceControl::setAlpha(float alpha) { -    const sp<SurfaceComposerClient>& client(mClient);      status_t err = validate();      if (err < 0) return err; +    const sp<SurfaceComposerClient>& client(mClient);      return client->setAlpha(mToken, alpha);  }  status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { -    const sp<SurfaceComposerClient>& client(mClient);      status_t err = validate();      if (err < 0) return err; +    const sp<SurfaceComposerClient>& client(mClient);      return client->setMatrix(mToken, dsdx, dtdx, dsdy, dtdy);  }  status_t SurfaceControl::setFreezeTint(uint32_t tint) { -    const sp<SurfaceComposerClient>& client(mClient);      status_t err = validate();      if (err < 0) return err; +    const sp<SurfaceComposerClient>& client(mClient);      return client->setFreezeTint(mToken, tint);  } @@ -233,50 +230,27 @@ status_t SurfaceControl::validate() const                  mToken, mIdentity, mClient.get());          return NO_INIT;      } -    SharedClient const* cblk = mClient->mControl; -    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; +    sp<ISurface> sur;      uint32_t identity = 0;      uint32_t width = 0;      uint32_t height = 0; -    sp<SurfaceComposerClient> client; -    sp<ISurface> sur; +    uint32_t format = 0; +    uint32_t flags = 0;      if (SurfaceControl::isValid(control)) { -        token    = control->mToken; -        identity = control->mIdentity; -        client   = control->mClient;          sur      = control->mSurface; +        identity = control->mIdentity;          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->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);      parcel->writeInt32(identity);      parcel->writeInt32(width);      parcel->writeInt32(height); @@ -298,40 +272,117 @@ sp<Surface> SurfaceControl::getSurface() const  //  Surface  // ============================================================================ +class SurfaceClient : public Singleton<SurfaceClient> +{ +    // all these attributes are constants +    sp<ISurfaceComposer> mComposerService; +    sp<ISurfaceComposerClient> mClient; +    status_t mStatus; +    SharedClient* mControl; +    sp<IMemoryHeap> mControlMemory; + +    SurfaceClient() +        : Singleton<SurfaceClient>(), mStatus(NO_INIT) +    { +        sp<ISurfaceComposer> sf(ComposerService::getComposerService()); +        mComposerService = sf; +        mClient = sf->createClientConnection(); +        if (mClient != NULL) { +            mControlMemory = mClient->getControlBlock(); +            if (mControlMemory != NULL) { +                mControl = static_cast<SharedClient *>( +                        mControlMemory->getBase()); +                if (mControl) { +                    mStatus = NO_ERROR; +                } +            } +        } +    } +    friend class Singleton<SurfaceClient>; +public: +    status_t initCheck() const { +        return mStatus; +    } +    SharedClient* getSharedClient() const { +        return mControl; +    } +    ssize_t getTokenForSurface(const sp<ISurface>& sur) const { +        // TODO: we could cache a few tokens here to avoid an IPC +        return mClient->getTokenForSurface(sur); +    } +    void signalServer() const { +        mComposerService->signal(); +    } +}; + +ANDROID_SINGLETON_STATIC_INSTANCE(SurfaceClient); + +// --------------------------------------------------------------------------- +  Surface::Surface(const sp<SurfaceControl>& surface) -    : mClient(surface->mClient), mSurface(surface->mSurface), -      mToken(surface->mToken), mIdentity(surface->mIdentity), +    : mBufferMapper(GraphicBufferMapper::get()), +      mClient(SurfaceClient::getInstance()), +      mSharedBufferClient(NULL), +      mInitCheck(NO_INIT), +      mSurface(surface->mSurface), +      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) +Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref) +    : mBufferMapper(GraphicBufferMapper::get()), +      mClient(SurfaceClient::getInstance()), +      mSharedBufferClient(NULL), +      mInitCheck(NO_INIT)  { -    sp<IBinder> clientBinder = parcel.readStrongBinder(); -    mSurface    = interface_cast<ISurface>(parcel.readStrongBinder()); -    mToken      = parcel.readInt32(); +    mSurface    = interface_cast<ISurface>(ref);      mIdentity   = parcel.readInt32();      mWidth      = parcel.readInt32();      mHeight     = parcel.readInt32();      mFormat     = parcel.readInt32();      mFlags      = parcel.readInt32(); +    init(); +} + +status_t Surface::writeToParcel( +        const sp<Surface>& surface, Parcel* parcel) +{ +    sp<ISurface> sur; +    uint32_t identity = 0; +    uint32_t width = 0; +    uint32_t height = 0; +    uint32_t format = 0; +    uint32_t flags = 0; +    if (Surface::isValid(surface)) { +        sur      = surface->mSurface; +        identity = surface->mIdentity; +        width    = surface->mWidth; +        height   = surface->mHeight; +        format   = surface->mFormat; +        flags    = surface->mFlags; +    } +    parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL); +    parcel->writeInt32(identity); +    parcel->writeInt32(width); +    parcel->writeInt32(height); +    parcel->writeInt32(format); +    parcel->writeInt32(flags); +    return NO_ERROR; -    // 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); +sp<Surface> Surface::readFromParcel( +        const Parcel& data, const sp<Surface>& other) +{ +    sp<Surface> result(other); +    sp<IBinder> binder(data.readStrongBinder()); +    if (other==0 || binder != other->mSurface->asBinder()) { +        result = new Surface(data, binder);      } - -    init(); +    return result;  }  void Surface::init() @@ -342,7 +393,7 @@ void Surface::init()      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; @@ -351,17 +402,29 @@ void Surface::init()      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; +      mConnected = 0; -    mNeedFullUpdate = false; +    mSwapRectangle.makeInvalid(); +    // two buffers by default +    mBuffers.setCapacity(2); +    mBuffers.insertAt(0, 2); + +    if (mSurface != 0 && mClient.initCheck() == NO_ERROR) { +        int32_t token = mClient.getTokenForSurface(mSurface); +        if (token >= 0) { +            mSharedBufferClient = new SharedBufferClient( +                    mClient.getSharedClient(), token, 2, mIdentity); +            mInitCheck = mClient.getSharedClient()->validate(token); +        } +    }  }  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++) { +    size_t size = mBuffers.size(); +    for (size_t i=0 ; i<size ; i++) {          if (mBuffers[i] != 0 && mBuffers[i]->handle != 0) {              getBufferMapper().unregisterBuffer(mBuffers[i]->handle);          } @@ -369,60 +432,55 @@ Surface::~Surface()      // clear all references and trigger an IPC now, to make sure things      // happen without delay, since these resources are quite heavy. -    mClient.clear(); +    mBuffers.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; +    return mInitCheck == NO_ERROR;  }  status_t Surface::validate() 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; +    // check that we initialized ourself properly +    if (mInitCheck != NO_ERROR) { +        LOGE("invalid token (identity=%u)", mIdentity); +        return mInitCheck; +    } + +    // verify the identity of this surface +    uint32_t identity = mSharedBufferClient->getIdentity(); + +    // this is a bit of a (temporary) special case, identity==0 means that +    // no operation are allowed from the client (eg: dequeue/queue), this +    // is used with PUSH_BUFFER surfaces for instance +    if (identity == 0) { +        LOGE("[Surface] invalid operation (identity=%u)", mIdentity); +        return INVALID_OPERATION;      } -    SharedClient const* cblk = mClient->mControl; -    if (cblk == 0) { -        LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity); + +    if (mIdentity != identity) { +        LOGE("[Surface] using an invalid surface, " +                "identity=%u should be %d", +                mIdentity, identity);          return NO_INIT;      } -    status_t err = cblk->validate(mToken); + +    // check the surface didn't become invalid +    status_t err = mSharedBufferClient->getStatus();      if (err != NO_ERROR) { -        LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)", -                mToken, mIdentity, err, strerror(-err)); +        LOGE("surface (identity=%u) is invalid, err=%d (%s)", +                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(); +sp<ISurface> Surface::getISurface() const { +    return mSurface;  }  // ---------------------------------------------------------------------------- @@ -467,21 +525,24 @@ int Surface::perform(android_native_window_t* window,  // ---------------------------------------------------------------------------- -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); +bool Surface::needNewBuffer(int bufIdx, +        uint32_t *pWidth, uint32_t *pHeight, +        uint32_t *pFormat, uint32_t *pUsage) const +{ +    Mutex::Autolock _l(mSurfaceLock); + +    // Always call needNewBuffer(), since it clears the needed buffers flags +    bool needNewBuffer = mSharedBufferClient->needNewBuffer(bufIdx); +    bool validBuffer = mBufferInfo.validateBuffer(mBuffers[bufIdx]); +    bool newNeewBuffer = needNewBuffer || !validBuffer; +    if (newNeewBuffer) { +        mBufferInfo.get(pWidth, pHeight, pFormat, pUsage);      } -    return err; +    return newNeewBuffer;  } -// ---------------------------------------------------------------------------- - -  int Surface::dequeueBuffer(android_native_buffer_t** buffer)  { -    sp<SurfaceComposerClient> client(getClient());      status_t err = validate();      if (err != NO_ERROR)          return err; @@ -492,24 +553,28 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer)          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)); +    // grow the buffer array if needed +    const size_t size = mBuffers.size(); +    const size_t needed = bufIdx+1; +    if (size < needed) { +        mBuffers.insertAt(size, needed-size); +    } + +    uint32_t w, h, format, usage; +    if (needNewBuffer(bufIdx, &w, &h, &format, &usage)) { +        err = getBufferLocked(bufIdx, w, h, format, usage); +        LOGE_IF(err, "getBufferLocked(%ld, %u, %u, %u, %08x) failed (%s)", +                bufIdx, w, h, format, usage, strerror(-err));          if (err == NO_ERROR) {              // reset the width/height with the what we get from the buffer +            const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);              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 +    const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);      if (!err && backBuffer==0) {          err = NO_MEMORY;      } @@ -526,12 +591,11 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer)  int Surface::lockBuffer(android_native_buffer_t* buffer)  { -    sp<SurfaceComposerClient> client(getClient());      status_t err = validate();      if (err != NO_ERROR)          return err; -    int32_t bufIdx = GraphicBuffer::getSelf(buffer)->getIndex(); +    int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));      err = mSharedBufferClient->lock(bufIdx);      LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err));      return err; @@ -539,7 +603,6 @@ int Surface::lockBuffer(android_native_buffer_t* buffer)  int Surface::queueBuffer(android_native_buffer_t* buffer)  {    -    sp<SurfaceComposerClient> client(getClient());      status_t err = validate();      if (err != NO_ERROR)          return err; @@ -548,14 +611,15 @@ int Surface::queueBuffer(android_native_buffer_t* buffer)          mDirtyRegion.set(mSwapRectangle);      } -    int32_t bufIdx = GraphicBuffer::getSelf(buffer)->getIndex(); +    int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer)); +    mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop);      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(); +        // TODO: can we avoid this IPC if we know there is one pending? +        mClient.signalServer();      }      return err;  } @@ -578,6 +642,10 @@ int Surface::query(int what, int* value)  int Surface::perform(int operation, va_list args)  { +    status_t err = validate(); +    if (err != NO_ERROR) +        return err; +      int res = NO_ERROR;      switch (operation) {      case NATIVE_WINDOW_SET_USAGE: @@ -589,6 +657,15 @@ int Surface::perform(int operation, va_list args)      case NATIVE_WINDOW_DISCONNECT:          res = dispatch_disconnect( args );          break; +    case NATIVE_WINDOW_SET_CROP: +        res = dispatch_crop( args ); +        break; +    case NATIVE_WINDOW_SET_BUFFER_COUNT: +        res = dispatch_set_buffer_count( args ); +        break; +    case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: +        res = dispatch_set_buffers_geometry( args ); +        break;      default:          res = NAME_NOT_FOUND;          break; @@ -608,12 +685,25 @@ int Surface::dispatch_disconnect(va_list args) {      int api = va_arg(args, int);      return disconnect( api );  } - +int Surface::dispatch_crop(va_list args) { +    android_native_rect_t const* rect = va_arg(args, android_native_rect_t*); +    return crop( reinterpret_cast<Rect const*>(rect) ); +} +int Surface::dispatch_set_buffer_count(va_list args) { +    size_t bufferCount = va_arg(args, size_t); +    return setBufferCount(bufferCount); +} +int Surface::dispatch_set_buffers_geometry(va_list args) { +    int w = va_arg(args, int); +    int h = va_arg(args, int); +    int f = va_arg(args, int); +    return setBuffersGeometry(w, h, f); +}  void Surface::setUsage(uint32_t reqUsage)  {      Mutex::Autolock _l(mSurfaceLock); -    mUsage = reqUsage; +    mBufferInfo.set(reqUsage);  }  int Surface::connect(int api) @@ -654,19 +744,55 @@ int Surface::disconnect(int api)      return err;  } -uint32_t Surface::getUsage() const +int Surface::crop(Rect const* rect)  {      Mutex::Autolock _l(mSurfaceLock); -    return mUsage; +    // TODO: validate rect size +    mNextBufferCrop = *rect; +    return NO_ERROR;  } +int Surface::setBufferCount(int bufferCount) +{ +    sp<ISurface> s(mSurface); +    if (s == 0) return NO_INIT; + +    class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback { +        sp<ISurface> surface; +        virtual status_t operator()(int bufferCount) const { +            return surface->setBufferCount(bufferCount); +        } +    public: +        SetBufferCountIPC(const sp<ISurface>& surface) : surface(surface) { } +    } ipc(s); + +    status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc); +    LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s", +            bufferCount, strerror(-err)); +    return err; +} + +int Surface::setBuffersGeometry(int w, int h, int format) +{ +    if (w<0 || h<0 || format<0) +        return BAD_VALUE; + +    if ((w && !h) || (!w && h)) +        return BAD_VALUE; + +    Mutex::Autolock _l(mSurfaceLock); +    mBufferInfo.set(w, h, format); +    return NO_ERROR; +} + +// ---------------------------------------------------------------------------- +  int Surface::getConnectedApi() const  {      Mutex::Autolock _l(mSurfaceLock);      return mConnected;  } -  // ----------------------------------------------------------------------------  status_t Surface::lock(SurfaceInfo* info, bool blocking) { @@ -703,45 +829,47 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)      // 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); +    android_native_buffer_t* out; +    status_t err = dequeueBuffer(&out);      LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));      if (err == NO_ERROR) { +        sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));          err = lockBuffer(backBuffer.get());          LOGE_IF(err, "lockBuffer (idx=%d) failed (%s)", -                backBuffer->getIndex(), strerror(-err)); +                getBufferIndex(backBuffer), strerror(-err));          if (err == NO_ERROR) { -            // we handle copy-back here... -              const Rect bounds(backBuffer->width, backBuffer->height); -            Region scratch(bounds); +            const Region boundsRegion(bounds); +            Region scratch(boundsRegion);              Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch); +            newDirtyRegion &= boundsRegion; -            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); -            } - +            // figure out if we can copy the frontbuffer back              const sp<GraphicBuffer>& frontBuffer(mPostedBuffer); -            if (frontBuffer !=0 && -                backBuffer->width  == frontBuffer->width &&  -                backBuffer->height == frontBuffer->height && -                !(mFlags & ISurfaceComposer::eDestroyBackbuffer))  -            { +            const bool canCopyBack = (frontBuffer != 0 && +                    backBuffer->width  == frontBuffer->width && +                    backBuffer->height == frontBuffer->height && +                    backBuffer->format == frontBuffer->format && +                    !(mFlags & ISurfaceComposer::eDestroyBackbuffer)); + +            // the dirty region we report to surfaceflinger is the one +            // given by the user (as opposed to the one *we* return to the +            // user). +            mDirtyRegion = newDirtyRegion; + +            if (canCopyBack) { +                // copy the area that is invalid and not repainted this round                  const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion)); -                if (!copyback.isEmpty() && frontBuffer!=0) { -                    // copy front to back +                if (!copyback.isEmpty())                      copyBlt(backBuffer, frontBuffer, copyback); -                } +            } else { +                // if we can't copy-back anything, modify the user's dirty +                // region to make sure they redraw the whole buffer +                newDirtyRegion = boundsRegion;              } -            mDirtyRegion = newDirtyRegion; +            // keep track of the are of the buffer that is "clean" +            // (ie: that will be redrawn)              mOldDirtyRegion = newDirtyRegion;              void* vaddr; @@ -777,7 +905,7 @@ status_t Surface::unlockAndPost()      err = queueBuffer(mLockedBuffer.get());      LOGE_IF(err, "queueBuffer (idx=%d) failed (%s)", -            mLockedBuffer->getIndex(), strerror(-err)); +            getBufferIndex(mLockedBuffer), strerror(-err));      mPostedBuffer = mLockedBuffer;      mLockedBuffer = 0; @@ -789,7 +917,13 @@ void Surface::setSwapRectangle(const Rect& r) {      mSwapRectangle = r;  } -status_t Surface::getBufferLocked(int index, int usage) +int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const +{ +    return buffer->getIndex(); +} + +status_t Surface::getBufferLocked(int index, +        uint32_t w, uint32_t h, uint32_t format, uint32_t usage)  {      sp<ISurface> s(mSurface);      if (s == 0) return NO_INIT; @@ -797,20 +931,21 @@ status_t Surface::getBufferLocked(int index, int usage)      status_t err = NO_MEMORY;      // free the current buffer -    sp<GraphicBuffer>& currentBuffer(mBuffers[index]); +    sp<GraphicBuffer>& currentBuffer(mBuffers.editItemAt(index));      if (currentBuffer != 0) {          getBufferMapper().unregisterBuffer(currentBuffer->handle);          currentBuffer.clear();      } -    sp<GraphicBuffer> buffer = s->requestBuffer(index, usage); +    sp<GraphicBuffer> buffer = s->requestBuffer(index, w, h, format, 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); +                "Surface (identity=%d) requestBuffer(%d, %u, %u, %u, %08x) " +                "returned a buffer with a null handle", +                mIdentity, index, w, h, format, usage);          err = mSharedBufferClient->getStatus();          LOGE_IF(err,  "Surface (identity=%d) state = %d", mIdentity, err);          if (!err && buffer->handle != NULL) { @@ -820,14 +955,52 @@ status_t Surface::getBufferLocked(int index, int usage)              if (err == NO_ERROR) {                  currentBuffer = buffer;                  currentBuffer->setIndex(index); -                mNeedFullUpdate = true;              }          } else { -            err = err<0 ? err : NO_MEMORY; +            err = err<0 ? err : status_t(NO_MEMORY);          }      }      return err;   } +// ---------------------------------------------------------------------------- +Surface::BufferInfo::BufferInfo() +    : mWidth(0), mHeight(0), mFormat(0), +      mUsage(GRALLOC_USAGE_HW_RENDER), mDirty(0) +{ +} + +void Surface::BufferInfo::set(uint32_t w, uint32_t h, uint32_t format) { +    if ((mWidth != w) || (mHeight != h) || (mFormat != format)) { +        mWidth = w; +        mHeight = h; +        mFormat = format; +        mDirty |= GEOMETRY; +    } +} + +void Surface::BufferInfo::set(uint32_t usage) { +    mUsage = usage; +} + +void Surface::BufferInfo::get(uint32_t *pWidth, uint32_t *pHeight, +        uint32_t *pFormat, uint32_t *pUsage) const { +    *pWidth  = mWidth; +    *pHeight = mHeight; +    *pFormat = mFormat; +    *pUsage  = mUsage; +} + +bool Surface::BufferInfo::validateBuffer(const sp<GraphicBuffer>& buffer) const { +    // make sure we AT LEAST have the usage flags we want +    if (mDirty || buffer==0 || +            ((buffer->usage & mUsage) != mUsage)) { +        mDirty = 0; +        return false; +    } +    return true; +} + +// ----------------------------------------------------------------------------  }; // namespace android diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/surfaceflinger_client/SurfaceComposerClient.cpp index 3117495d3f..4096ac6854 100644 --- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp +++ b/libs/surfaceflinger_client/SurfaceComposerClient.cpp @@ -17,98 +17,137 @@  #define LOG_TAG "SurfaceComposerClient"  #include <stdint.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h>  #include <sys/types.h> -#include <sys/stat.h> -#include <cutils/memory.h> - -#include <utils/Atomic.h>  #include <utils/Errors.h>  #include <utils/threads.h> -#include <utils/KeyedVector.h> +#include <utils/SortedVector.h>  #include <utils/Log.h> +#include <utils/Singleton.h>  #include <binder/IServiceManager.h>  #include <binder/IMemory.h>  #include <ui/DisplayInfo.h> -#include <ui/Rect.h>  #include <surfaceflinger/ISurfaceComposer.h> -#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurfaceComposerClient.h>  #include <surfaceflinger/ISurface.h>  #include <surfaceflinger/SurfaceComposerClient.h>  #include <private/surfaceflinger/LayerState.h>  #include <private/surfaceflinger/SharedBufferStack.h> -#define VERBOSE(...)	((void)0) -//#define VERBOSE			LOGD - -#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  )) -#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))  namespace android { +// --------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService); + +ComposerService::ComposerService() +: Singleton<ComposerService>() { +    const String16 name("SurfaceFlinger"); +    while (getService(name, &mComposerService) != NO_ERROR) { +        usleep(250000); +    } +    mServerCblkMemory = mComposerService->getCblk(); +    mServerCblk = static_cast<surface_flinger_cblk_t volatile *>( +            mServerCblkMemory->getBase()); +} + +sp<ISurfaceComposer> ComposerService::getComposerService() { +    return ComposerService::getInstance().mComposerService; +} + +surface_flinger_cblk_t const volatile * ComposerService::getControlBlock() { +    return ComposerService::getInstance().mServerCblk; +} + +static inline sp<ISurfaceComposer> getComposerService() { +    return ComposerService::getComposerService(); +} + +static inline surface_flinger_cblk_t const volatile * get_cblk() { +    return ComposerService::getControlBlock(); +}  // --------------------------------------------------------------------------- -// Must not be holding SurfaceComposerClient::mLock when acquiring gLock here. -static Mutex                                                gLock; -static sp<ISurfaceComposer>                                 gSurfaceManager; -static DefaultKeyedVector< sp<IBinder>, sp<SurfaceComposerClient> > gActiveConnections; -static SortedVector<sp<SurfaceComposerClient> >             gOpenTransactions; -static sp<IMemoryHeap>                                      gServerCblkMemory; -static volatile surface_flinger_cblk_t*                     gServerCblk; - -static sp<ISurfaceComposer> getComposerService() -{ -    sp<ISurfaceComposer> sc; -    Mutex::Autolock _l(gLock); -    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 +class Composer : public Singleton<Composer> +{ +    Mutex mLock; +    SortedVector< wp<SurfaceComposerClient> > mActiveConnections; +    SortedVector<sp<SurfaceComposerClient> > mOpenTransactions; + +    Composer() : Singleton<Composer>() { +    } + +    void addClientImpl(const sp<SurfaceComposerClient>& client) { +        Mutex::Autolock _l(mLock); +        mActiveConnections.add(client); +    } + +    void removeClientImpl(const sp<SurfaceComposerClient>& client) { +        Mutex::Autolock _l(mLock); +        mActiveConnections.remove(client); +    } + +    void openGlobalTransactionImpl() +    { +        Mutex::Autolock _l(mLock); +        if (mOpenTransactions.size()) { +            LOGE("openGlobalTransaction() called more than once. skipping."); +            return; +        } +        const size_t N = mActiveConnections.size(); +        for (size_t i=0; i<N; i++) { +            sp<SurfaceComposerClient> client(mActiveConnections[i].promote()); +            if (client != 0 && mOpenTransactions.indexOf(client) < 0) { +                if (client->openTransaction() == NO_ERROR) { +                    mOpenTransactions.add(client); +                } else { +                    LOGE("openTransaction on client %p failed", client.get()); +                    // let it go, it'll fail later when the user +                    // tries to do something with the transaction +                }              } -        } 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 sc; -} -static volatile surface_flinger_cblk_t const * get_cblk() -{ -    if (gServerCblk == 0) { +    void closeGlobalTransactionImpl() +    { +        mLock.lock(); +            SortedVector< sp<SurfaceComposerClient> > clients(mOpenTransactions); +            mOpenTransactions.clear(); +        mLock.unlock(); +          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->getBase(); -            LOGE_IF(gServerCblk==0, "Can't get server control block address"); -        } +        sm->openGlobalTransaction(); +            const size_t N = clients.size(); +            for (size_t i=0; i<N; i++) { +                clients[i]->closeTransaction(); +            } +        sm->closeGlobalTransaction();      } -    return gServerCblk; -} + +    friend class Singleton<Composer>; + +public: +    static void addClient(const sp<SurfaceComposerClient>& client) { +        Composer::getInstance().addClientImpl(client); +    } +    static void removeClient(const sp<SurfaceComposerClient>& client) { +        Composer::getInstance().removeClientImpl(client); +    } +    static void openGlobalTransaction() { +        Composer::getInstance().openGlobalTransactionImpl(); +    } +    static void closeGlobalTransaction() { +        Composer::getInstance().closeGlobalTransactionImpl(); +    } +}; + +ANDROID_SINGLETON_STATIC_INSTANCE(Composer);  // --------------------------------------------------------------------------- @@ -120,61 +159,27 @@ static inline int compare_type( const layer_state_t& lhs,  }  SurfaceComposerClient::SurfaceComposerClient() +    : mTransactionOpen(0), mPrebuiltLayerState(0), mStatus(NO_INIT)  { -    sp<ISurfaceComposer> sm(getComposerService()); -    if (sm == 0) { -        _init(0, 0); -        return; -    } - -    _init(sm, sm->createConnection()); - -    if (mClient != 0) { -        Mutex::Autolock _l(gLock); -        VERBOSE("Adding client %p to map", this); -        gActiveConnections.add(mClient->asBinder(), this); -    }  } -SurfaceComposerClient::SurfaceComposerClient( -        const sp<ISurfaceComposer>& sm, const sp<IBinder>& conn) -{ -    _init(sm, interface_cast<ISurfaceFlingerClient>(conn)); -} - - -status_t SurfaceComposerClient::linkToComposerDeath( -        const sp<IBinder::DeathRecipient>& recipient, -        void* cookie, uint32_t flags) +void SurfaceComposerClient::onFirstRef()  {      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()); - -    mPrebuiltLayerState = 0; -    mTransactionOpen = 0; -    mStatus = NO_ERROR; -    mControl = 0; - -    mClient = conn; -    if (mClient == 0) { -        mStatus = NO_INIT; -        return; +    if (sm != 0) { +        sp<ISurfaceComposerClient> conn = sm->createConnection(); +        if (conn != 0) { +            mClient = conn; +            Composer::addClient(this); +            mPrebuiltLayerState = new layer_state_t; +            mStatus = NO_ERROR; +        }      } - -    mControlMemory = mClient->getControlBlock(); -    mSignalServer = sm; -    mControl = static_cast<SharedClient *>(mControlMemory->getBase());  }  SurfaceComposerClient::~SurfaceComposerClient()  { -    VERBOSE("Destroying client %p, conn %p", this, mClient.get()); +    delete mPrebuiltLayerState;      dispose();  } @@ -188,69 +193,31 @@ sp<IBinder> SurfaceComposerClient::connection() const      return (mClient != 0) ? mClient->asBinder() : 0;  } -sp<SurfaceComposerClient> -SurfaceComposerClient::clientForConnection(const sp<IBinder>& conn) +status_t SurfaceComposerClient::linkToComposerDeath( +        const sp<IBinder::DeathRecipient>& recipient, +        void* cookie, uint32_t flags)  { -    sp<SurfaceComposerClient> client; - -    { // scope for lock -        Mutex::Autolock _l(gLock); -        client = gActiveConnections.valueFor(conn); -    } - -    if (client == 0) { -        // Need to make a new client. -        sp<ISurfaceComposer> sm(getComposerService()); -        client = new SurfaceComposerClient(sm, conn); -        if (client != 0 && client->initCheck() == NO_ERROR) { -            Mutex::Autolock _l(gLock); -            gActiveConnections.add(conn, client); -            //LOGD("we have %d connections", gActiveConnections.size()); -        } else { -            client.clear(); -        } -    } - -    return client; +    sp<ISurfaceComposer> sm(getComposerService()); +    return sm->asBinder()->linkToDeath(recipient, cookie, flags);  }  void SurfaceComposerClient::dispose()  {      // this can be called more than once. - -    sp<IMemoryHeap>             controlMemory; -    sp<ISurfaceFlingerClient>   client; - -    { -        Mutex::Autolock _lg(gLock); -        Mutex::Autolock _lm(mLock); - -        mSignalServer = 0; - -        if (mClient != 0) { -            client = mClient; -            mClient.clear(); - -            ssize_t i = gActiveConnections.indexOfKey(client->asBinder()); -            if (i >= 0 && gActiveConnections.valueAt(i) == this) { -                VERBOSE("Removing client %p from map at %d", this, int(i)); -                gActiveConnections.removeItemsAt(i); -            } -        } - -        delete mPrebuiltLayerState; -        mPrebuiltLayerState = 0; -        controlMemory = mControlMemory; -        mControlMemory.clear(); -        mControl = 0; -        mStatus = NO_INIT; +    sp<ISurfaceComposerClient> client; +    Mutex::Autolock _lm(mLock); +    if (mClient != 0) { +        Composer::removeClient(this); +        client = mClient; // hold ref while lock is held +        mClient.clear();      } +    mStatus = NO_INIT;  }  status_t SurfaceComposerClient::getDisplayInfo(          DisplayID dpy, DisplayInfo* info)  { -    if (uint32_t(dpy)>=NUM_DISPLAY_MAX) +    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)          return BAD_VALUE;      volatile surface_flinger_cblk_t const * cblk = get_cblk(); @@ -268,7 +235,7 @@ status_t SurfaceComposerClient::getDisplayInfo(  ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)  { -    if (uint32_t(dpy)>=NUM_DISPLAY_MAX) +    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)          return BAD_VALUE;      volatile surface_flinger_cblk_t const * cblk = get_cblk();      volatile display_cblk_t const * dcblk = cblk->displays + dpy; @@ -277,7 +244,7 @@ ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)  ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)  { -    if (uint32_t(dpy)>=NUM_DISPLAY_MAX) +    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)          return BAD_VALUE;      volatile surface_flinger_cblk_t const * cblk = get_cblk();      volatile display_cblk_t const * dcblk = cblk->displays + dpy; @@ -286,7 +253,7 @@ ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)  ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy)  { -    if (uint32_t(dpy)>=NUM_DISPLAY_MAX) +    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)          return BAD_VALUE;      volatile surface_flinger_cblk_t const * cblk = get_cblk();      volatile display_cblk_t const * dcblk = cblk->displays + dpy; @@ -305,12 +272,6 @@ ssize_t SurfaceComposerClient::getNumberOfDisplays()      return n;  } - -void SurfaceComposerClient::signalServer() -{ -    mSignalServer->signal(); -} -  sp<SurfaceControl> SurfaceComposerClient::createSurface(          int pid,          DisplayID display, @@ -327,7 +288,6 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface(      return SurfaceComposerClient::createSurface(pid, name, display,              w, h, format, flags); -  }  sp<SurfaceControl> SurfaceComposerClient::createSurface( @@ -341,13 +301,11 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface(  {      sp<SurfaceControl> result;      if (mStatus == NO_ERROR) { -        ISurfaceFlingerClient::surface_data_t data; +        ISurfaceComposerClient::surface_data_t data;          sp<ISurface> surface = mClient->createSurface(&data, pid, name,                  display, w, h, format, flags);          if (surface != 0) { -            if (uint32_t(data.token) < NUM_LAYERS_MAX) { -                result = new SurfaceControl(this, surface, data, w, h, format, flags); -            } +            result = new SurfaceControl(this, surface, data, w, h, format, flags);          }      }      return result; @@ -373,56 +331,14 @@ status_t SurfaceComposerClient::destroySurface(SurfaceID sid)  void SurfaceComposerClient::openGlobalTransaction()  { -    Mutex::Autolock _l(gLock); - -    if (gOpenTransactions.size()) { -        LOGE("openGlobalTransaction() called more than once. skipping."); -        return; -    } - -    const size_t N = gActiveConnections.size(); -    VERBOSE("openGlobalTransaction (%ld clients)", N); -    for (size_t i=0; i<N; i++) { -        sp<SurfaceComposerClient> client(gActiveConnections.valueAt(i)); -        if (gOpenTransactions.indexOf(client) < 0) { -            if (client->openTransaction() == NO_ERROR) { -                if (gOpenTransactions.add(client) < 0) { -                    // Ooops! -                    LOGE(   "Unable to add a SurfaceComposerClient " -                            "to the global transaction set (out of memory?)"); -                    client->closeTransaction(); -                    // let it go, it'll fail later when the user -                    // tries to do something with the transaction -                } -            } else { -                LOGE("openTransaction on client %p failed", client.get()); -                // let it go, it'll fail later when the user -                // tries to do something with the transaction -            } -        } -    } +    Composer::openGlobalTransaction();  }  void SurfaceComposerClient::closeGlobalTransaction()  { -    gLock.lock(); -        SortedVector< sp<SurfaceComposerClient> > clients(gOpenTransactions); -        gOpenTransactions.clear(); -    gLock.unlock(); - -    const size_t N = clients.size(); -    VERBOSE("closeGlobalTransaction (%ld clients)", N); - -    sp<ISurfaceComposer> sm(getComposerService()); -    sm->openGlobalTransaction(); -    for (size_t i=0; i<N; i++) { -        clients[i]->closeTransaction(); -    } -    sm->closeGlobalTransaction(); - +    Composer::closeGlobalTransaction();  } -  status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags)  {      sp<ISurfaceComposer> sm(getComposerService()); @@ -447,26 +363,16 @@ status_t SurfaceComposerClient::openTransaction()      if (mStatus != NO_ERROR)          return mStatus;      Mutex::Autolock _l(mLock); -    VERBOSE(   "openTransaction (client %p, mTransactionOpen=%d)", -            this, mTransactionOpen);      mTransactionOpen++; -    if (mPrebuiltLayerState == 0) { -        mPrebuiltLayerState = new layer_state_t; -    }      return NO_ERROR;  } -  status_t SurfaceComposerClient::closeTransaction()  {      if (mStatus != NO_ERROR)          return mStatus;      Mutex::Autolock _l(mLock); - -    VERBOSE(   "closeTransaction (client %p, mTransactionOpen=%d)", -            this, mTransactionOpen); -      if (mTransactionOpen <= 0) {          LOGE(   "closeTransaction (client %p, mTransactionOpen=%d) "                  "called more times than openTransaction()", @@ -488,7 +394,7 @@ status_t SurfaceComposerClient::closeTransaction()      return NO_ERROR;  } -layer_state_t* SurfaceComposerClient::_get_state_l(SurfaceID index) +layer_state_t* SurfaceComposerClient::get_state_l(SurfaceID index)  {      // API usage error, do nothing.      if (mTransactionOpen<=0) { @@ -498,7 +404,7 @@ layer_state_t* SurfaceComposerClient::_get_state_l(SurfaceID index)      }      // use mPrebuiltLayerState just to find out if we already have it -    layer_state_t& dummy = *mPrebuiltLayerState; +    layer_state_t& dummy(*mPrebuiltLayerState);      dummy.surface = index;      ssize_t i = mStates.indexOf(dummy);      if (i < 0) { @@ -508,49 +414,49 @@ layer_state_t* SurfaceComposerClient::_get_state_l(SurfaceID index)      return mStates.editArray() + i;  } -layer_state_t* SurfaceComposerClient::_lockLayerState(SurfaceID id) +layer_state_t* SurfaceComposerClient::lockLayerState(SurfaceID id)  {      layer_state_t* s;      mLock.lock(); -    s = _get_state_l(id); +    s = get_state_l(id);      if (!s) mLock.unlock();      return s;  } -void SurfaceComposerClient::_unlockLayerState() +void SurfaceComposerClient::unlockLayerState()  {      mLock.unlock();  }  status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y)  { -    layer_state_t* s = _lockLayerState(id); +    layer_state_t* s = lockLayerState(id);      if (!s) return BAD_INDEX;      s->what |= ISurfaceComposer::ePositionChanged;      s->x = x;      s->y = y; -    _unlockLayerState(); +    unlockLayerState();      return NO_ERROR;  }  status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h)  { -    layer_state_t* s = _lockLayerState(id); +    layer_state_t* s = lockLayerState(id);      if (!s) return BAD_INDEX;      s->what |= ISurfaceComposer::eSizeChanged;      s->w = w;      s->h = h; -    _unlockLayerState(); +    unlockLayerState();      return NO_ERROR;  }  status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z)  { -    layer_state_t* s = _lockLayerState(id); +    layer_state_t* s = lockLayerState(id);      if (!s) return BAD_INDEX;      s->what |= ISurfaceComposer::eLayerChanged;      s->z = z; -    _unlockLayerState(); +    unlockLayerState();      return NO_ERROR;  } @@ -579,34 +485,34 @@ status_t SurfaceComposerClient::unfreeze(SurfaceID id)  status_t SurfaceComposerClient::setFlags(SurfaceID id,          uint32_t flags, uint32_t mask)  { -    layer_state_t* s = _lockLayerState(id); +    layer_state_t* s = lockLayerState(id);      if (!s) return BAD_INDEX;      s->what |= ISurfaceComposer::eVisibilityChanged;      s->flags &= ~mask;      s->flags |= (flags & mask);      s->mask |= mask; -    _unlockLayerState(); +    unlockLayerState();      return NO_ERROR;  }  status_t SurfaceComposerClient::setTransparentRegionHint(          SurfaceID id, const Region& transparentRegion)  { -    layer_state_t* s = _lockLayerState(id); +    layer_state_t* s = lockLayerState(id);      if (!s) return BAD_INDEX;      s->what |= ISurfaceComposer::eTransparentRegionChanged;      s->transparentRegion = transparentRegion; -    _unlockLayerState(); +    unlockLayerState();      return NO_ERROR;  }  status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha)  { -    layer_state_t* s = _lockLayerState(id); +    layer_state_t* s = lockLayerState(id);      if (!s) return BAD_INDEX;      s->what |= ISurfaceComposer::eAlphaChanged;      s->alpha = alpha; -    _unlockLayerState(); +    unlockLayerState();      return NO_ERROR;  } @@ -615,7 +521,7 @@ status_t SurfaceComposerClient::setMatrix(          float dsdx, float dtdx,          float dsdy, float dtdy )  { -    layer_state_t* s = _lockLayerState(id); +    layer_state_t* s = lockLayerState(id);      if (!s) return BAD_INDEX;      s->what |= ISurfaceComposer::eMatrixChanged;      layer_state_t::matrix22_t matrix; @@ -624,19 +530,20 @@ status_t SurfaceComposerClient::setMatrix(      matrix.dsdy = dsdy;      matrix.dtdy = dtdy;      s->matrix = matrix; -    _unlockLayerState(); +    unlockLayerState();      return NO_ERROR;  }  status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint)  { -    layer_state_t* s = _lockLayerState(id); +    layer_state_t* s = lockLayerState(id);      if (!s) return BAD_INDEX;      s->what |= ISurfaceComposer::eFreezeTintChanged;      s->tint = tint; -    _unlockLayerState(); +    unlockLayerState();      return NO_ERROR;  } +// ----------------------------------------------------------------------------  }; // namespace android diff --git a/libs/surfaceflinger_client/tests/Android.mk b/libs/surfaceflinger_client/tests/Android.mk new file mode 100644 index 0000000000..5053e7d643 --- /dev/null +++ b/libs/surfaceflinger_client/tests/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk b/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk new file mode 100644 index 0000000000..d3dfe04285 --- /dev/null +++ b/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk @@ -0,0 +1,17 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ +	SharedBufferStackTest.cpp + +LOCAL_SHARED_LIBRARIES := \ +	libcutils \ +	libutils \ +    libui \ +    libsurfaceflinger_client + +LOCAL_MODULE:= test-sharedbufferstack + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_EXECUTABLE) diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp new file mode 100644 index 0000000000..f409f48289 --- /dev/null +++ b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp @@ -0,0 +1,279 @@ +/* + * 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. + */ + +#undef NDEBUG + +#include <assert.h> +#include <cutils/memory.h> +#include <cutils/log.h> +#include <utils/Errors.h> +#include <private/surfaceflinger/SharedBufferStack.h> + +using namespace android; + +void log(const char* prefix, int *b, size_t num); +void test0(SharedBufferServer& s, SharedBufferClient& c, size_t num, int* list); + +// ---------------------------------------------------------------------------- + +int main(int argc, char** argv) +{ +    SharedClient client; +    SharedBufferServer s(&client, 0, 4, 0); +    SharedBufferClient c(&client, 0, 4, 0); + +    printf("basic test 0\n"); +    int list0[4] = {0, 1, 2, 3}; +    test0(s, c, 4, list0); + +    printf("basic test 1\n"); +    int list1[4] = {2, 1, 0, 3}; +    test0(s, c, 4, list1); + +    int b = c.dequeue(); +    c.lock(b); +    c.queue(b); +    s.retireAndLock(); + +    printf("basic test 2\n"); +    int list2[4] = {1, 2, 3, 0}; +    test0(s, c, 4, list2); + + +    printf("resize test\n"); +    class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback { +        SharedBufferServer& s; +        virtual status_t operator()(int bufferCount) const { +            return s.resize(bufferCount); +        } +    public: +        SetBufferCountIPC(SharedBufferServer& s) : s(s) { } +    } resize(s); + +    c.setBufferCount(6, resize); +    int list3[6] = {3, 2, 1, 4, 5, 0}; +    test0(s, c, 6, list3); + +    return 0; +} + +void log(const char* prefix, int *b, size_t num) +{ +    printf("%s: ", prefix); +    for (size_t i=0 ; i<num ; i++) { +        printf("%d ", b[i]); +    } +    printf("\n"); +} + +// ---------------------------------------------------------------------------- + +void test0( +        SharedBufferServer& s, +        SharedBufferClient& c, +        size_t num, +        int* list) +{ +    status_t err; +    int b[num], u[num], r[num]; + +    for (size_t i=0 ; i<num ; i++) { +        b[i] = c.dequeue(); +        assert(b[i]==list[i]); +    } +    log("DQ", b, num); + +    for (size_t i=0 ; i<num-1 ; i++) { +        err = c.lock(b[i]); +        assert(err==0); +    } +    log("LK", b, num-1); + +    for (size_t i=0 ; i<num-1 ; i++) { +        err = c.queue(b[i]); +        assert(err==0); +    } +    log(" Q", b, num-1); + + +    for (size_t i=0 ; i<num-1 ; i++) { +        r[i] = s.retireAndLock(); +        assert(r[i]==list[i]); +        err = s.unlock(r[i]); +        assert(err == 0); +    } +    log("RT", r, num-1); + +    err = c.lock(b[num-1]); +    assert(err == 0); +    log("LK", b+num-1, 1); + +    err = c.queue(b[num-1]); +    assert(err == 0); +    log(" Q", b+num-1, 1); + +    r[num-1] = s.retireAndLock(); +    assert(r[num-1]==list[num-1]); +    err = s.unlock(r[num-1]); +    assert(err == 0); +    log("RT", r+num-1, 1); + +    // ------------------------------------ +    printf("\n"); + +    for (size_t i=0 ; i<num ; i++) { +        b[i] = c.dequeue(); +        assert(b[i]==list[i]); +    } +    log("DQ", b, num); + +    for (size_t i=0 ; i<num-1 ; i++) { +        err = c.lock(b[i]); +        assert(err==0); +    } +    log("LK", b, num-1); + +    for (size_t i=0 ; i<num-1 ; i++) { +        u[i] = b[num-2-i]; +    } +    u[num-1] = b[num-1]; + +    for (size_t i=0 ; i<num-1 ; i++) { +        err = c.queue(u[i]); +        assert(err==0); +    } +    log(" Q", u, num-1); + +    for (size_t i=0 ; i<num-1 ; i++) { +        r[i] = s.retireAndLock(); +        assert(r[i]==u[i]); +        err = s.unlock(r[i]); +        assert(err == 0); +    } +    log("RT", r, num-1); + +    err = c.lock(b[num-1]); +    assert(err == 0); +    log("LK", b+num-1, 1); + +    err = c.queue(b[num-1]); +    assert(err == 0); +    log(" Q", b+num-1, 1); + +    r[num-1] = s.retireAndLock(); +    assert(r[num-1]==list[num-1]); +    err = s.unlock(r[num-1]); +    assert(err == 0); +    log("RT", r+num-1, 1); + +    // ------------------------------------ +    printf("\n"); + +    for (size_t i=0 ; i<num ; i++) { +        b[i] = c.dequeue(); +        assert(b[i]==u[i]); +    } +    log("DQ", b, num); + +    for (size_t i=0 ; i<num-1 ; i++) { +        err = c.lock(b[i]); +        assert(err==0); +    } +    log("LK", b, num-1); + +    for (size_t i=0 ; i<num-1 ; i++) { +        err = c.queue(b[i]); +        assert(err==0); +    } +    log(" Q", b, num-1); + +    for (size_t i=0 ; i<num-1 ; i++) { +        r[i] = s.retireAndLock(); +        assert(r[i]==u[i]); +        err = s.unlock(r[i]); +        assert(err == 0); +    } +    log("RT", r, num-1); + +    err = c.lock(u[num-1]); +    assert(err == 0); +    log("LK", u+num-1, 1); + +    err = c.queue(u[num-1]); +    assert(err == 0); +    log(" Q", u+num-1, 1); + +    r[num-1] = s.retireAndLock(); +    assert(r[num-1]==u[num-1]); +    err = s.unlock(r[num-1]); +    assert(err == 0); +    log("RT", r+num-1, 1); + +    // ------------------------------------ +    printf("\n"); + +    b[0] = c.dequeue(); +    assert(b[0]==u[0]); +    log("DQ", b, 1); + +    c.undoDequeue(b[0]); +    assert(err == 0); +    log("UDQ", b, 1); + +    // ------------------------------------ +    printf("\n"); + +    for (size_t i=0 ; i<num ; i++) { +        b[i] = c.dequeue(); +        assert(b[i]==u[i]); +    } +    log("DQ", b, num); + +    for (size_t i=0 ; i<num-1 ; i++) { +        err = c.lock(b[i]); +        assert(err==0); +    } +    log("LK", b, num-1); + +    for (size_t i=0 ; i<num-1 ; i++) { +        err = c.queue(b[i]); +        assert(err==0); +    } +    log(" Q", b, num-1); + +    for (size_t i=0 ; i<num-1 ; i++) { +        r[i] = s.retireAndLock(); +        assert(r[i]==u[i]); +        err = s.unlock(r[i]); +        assert(err == 0); +    } +    log("RT", r, num-1); + +    err = c.lock(u[num-1]); +    assert(err == 0); +    log("LK", u+num-1, 1); + +    err = c.queue(u[num-1]); +    assert(err == 0); +    log(" Q", u+num-1, 1); + +    r[num-1] = s.retireAndLock(); +    assert(r[num-1]==u[num-1]); +    err = s.unlock(r[num-1]); +    assert(err == 0); +    log("RT", r+num-1, 1); +    printf("\n"); +} diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index ba1fd9c9dc..4b5f02517a 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -38,7 +38,7 @@ namespace android {  GraphicBuffer::GraphicBuffer()      : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), -      mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1) +      mInitCheck(NO_ERROR), mIndex(-1)  {      width  =       height =  @@ -51,7 +51,7 @@ GraphicBuffer::GraphicBuffer()  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) +      mInitCheck(NO_ERROR), mIndex(-1)  {      width  =       height =  @@ -67,7 +67,7 @@ GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,          uint32_t inStride, native_handle_t* inHandle, bool keepOwnership)      : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),        mBufferMapper(GraphicBufferMapper::get()), -      mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1) +      mInitCheck(NO_ERROR), mIndex(-1)  {      width  = w;      height = h; @@ -111,6 +111,9 @@ status_t GraphicBuffer::reallocate(uint32_t w, uint32_t h, PixelFormat f,      if (mOwner != ownData)          return INVALID_OPERATION; +    if (handle && w==width && h==height && f==format && reqUsage==usage) +        return NO_ERROR; +      if (handle) {          GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());          allocator.free(handle); @@ -122,17 +125,25 @@ status_t GraphicBuffer::reallocate(uint32_t w, uint32_t h, PixelFormat f,  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<0 && format == PIXEL_FORMAT_RGBX_8888) { +        /* +         * There is currently a bug with some gralloc implementations +         * not supporting RGBX_8888. In this case, we revert to using RGBA_8888 +         * which is not exactly the same, as GL_REPLACE will yield a different +         * result. +         */ +        format = PIXEL_FORMAT_RGBA_8888; +        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;  } @@ -173,7 +184,6 @@ status_t GraphicBuffer::lock(GGLSurface* sur, uint32_t usage)          sur->height = height;          sur->stride = stride;          sur->format = format; -        sur->vstride = mVStride;          sur->data = static_cast<GGLubyte*>(vaddr);      }      return res; @@ -267,14 +277,6 @@ 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 index 6ae7e741b6..d51664dded 100644 --- a/libs/ui/GraphicBufferAllocator.cpp +++ b/libs/ui/GraphicBufferAllocator.cpp @@ -15,6 +15,8 @@  ** limitations under the License.  */ +#define LOG_TAG "GraphicBufferAllocator" +  #include <cutils/log.h>  #include <utils/Singleton.h> @@ -61,9 +63,9 @@ void GraphicBufferAllocator::dump(String8& result) const      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", +        snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %2d | 0x%08x\n",              list.keyAt(i), rec.size/1024.0f,  -            rec.w, rec.h, rec.format, rec.usage); +            rec.w, rec.s, rec.h, rec.format, rec.usage);          result.append(buffer);          total += rec.size;      } @@ -71,16 +73,13 @@ void GraphicBufferAllocator::dump(String8& result) const      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)  { -    // make sure to not allocate a 0 x 0 buffer -    w = clamp(w); -    h = clamp(h); +    // make sure to not allocate a N x 0 or 0 x N buffer, since this is +    // allowed from an API stand-point allocate a 1x1 buffer instead. +    if (!w || !h) +        w = h = 1;      // we have a h/w allocator and h/w buffer is requested      status_t err;  @@ -100,9 +99,9 @@ status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat forma          alloc_rec_t rec;          rec.w = w;          rec.h = h; +        rec.s = *stride;          rec.format = format;          rec.usage = usage; -        rec.vaddr = 0;          rec.size = h * stride[0] * bytesPerPixel(format);          list.add(*handle, rec);      } else { diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 5a05e6a61f..60a0d82e25 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -824,7 +824,7 @@ Asset* AssetManager::openAssetFromZipLocked(const ZipFileRO* pZipFile,      // TODO: look for previously-created shared memory slice?      int method; -    long uncompressedLen; +    size_t uncompressedLen;      //printf("USING Zip '%s'\n", pEntry->getFileName()); diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp index 7e0f881af6..a1401addf3 100644 --- a/libs/utils/ResourceTypes.cpp +++ b/libs/utils/ResourceTypes.cpp @@ -4178,6 +4178,9 @@ void ResTable::print(bool inclValues) const                              case ResTable_config::SCREENSIZE_LARGE:                                  printf(" (large)");                                  break; +                            case ResTable_config::SCREENSIZE_XLARGE: +                                printf(" (xlarge)"); +                                break;                          }                          printf(" lng=%d",                                  type->config.screenLayout&ResTable_config::MASK_SCREENLONG); diff --git a/libs/utils/ZipFileCRO.cpp b/libs/utils/ZipFileCRO.cpp index 45f6c8baa7..16b219cad4 100644 --- a/libs/utils/ZipFileCRO.cpp +++ b/libs/utils/ZipFileCRO.cpp @@ -39,8 +39,8 @@ ZipEntryCRO ZipFileCRO_findEntryByName(ZipFileCRO zipToken,  }  bool ZipFileCRO_getEntryInfo(ZipFileCRO zipToken, ZipEntryRO entryToken, -        int* pMethod, long* pUncompLen, -        long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) { +        int* pMethod, size_t* pUncompLen, +        size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) {      ZipFileRO* zip = (ZipFileRO*)zipToken;      ZipEntryRO entry = (ZipEntryRO)entryToken;      return zip->getEntryInfo(entry, pMethod, pUncompLen, pCompLen, pOffset, diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp index 6c701dd0b6..28dc512bb6 100644 --- a/libs/utils/ZipFileRO.cpp +++ b/libs/utils/ZipFileRO.cpp @@ -29,6 +29,22 @@  #include <fcntl.h>  #include <errno.h>  #include <assert.h> +#include <unistd.h> + +/* + * TEMP_FAILURE_RETRY is defined by some, but not all, versions of + * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's + * not already defined, then define it here. + */ +#ifndef TEMP_FAILURE_RETRY +/* Used to retry syscalls that can return EINTR. */ +#define TEMP_FAILURE_RETRY(exp) ({         \ +    typeof (exp) _rc;                      \ +    do {                                   \ +        _rc = (exp);                       \ +    } while (_rc == -1 && errno == EINTR); \ +    _rc; }) +#endif  using namespace android; @@ -38,6 +54,7 @@ using namespace android;  #define kEOCDSignature      0x06054b50  #define kEOCDLen            22  #define kEOCDNumEntries     8               // offset to #of entries in file +#define kEOCDSize           12              // size of the central directory  #define kEOCDFileOffset     16              // offset to central directory  #define kMaxCommentLen      65535           // longest possible in ushort @@ -90,9 +107,8 @@ int ZipFileRO::entryToIndex(const ZipEntryRO entry) const  status_t ZipFileRO::open(const char* zipFileName)  {      int fd = -1; -    off_t length; -    assert(mFileMap == NULL); +    assert(mDirectoryMap == NULL);      /*       * Open and map the specified file. @@ -103,172 +119,240 @@ status_t ZipFileRO::open(const char* zipFileName)          return NAME_NOT_FOUND;      } -    length = lseek(fd, 0, SEEK_END); -    if (length < 0) { +    mFileLength = lseek(fd, 0, SEEK_END); +    if (mFileLength < kEOCDLen) {          close(fd);          return UNKNOWN_ERROR;      } -    mFileMap = new FileMap(); -    if (mFileMap == NULL) { -        close(fd); -        return NO_MEMORY; -    } -    if (!mFileMap->create(zipFileName, fd, 0, length, true)) { -        LOGW("Unable to map '%s': %s\n", zipFileName, strerror(errno)); -        close(fd); -        return UNKNOWN_ERROR; +    if (mFileName != NULL) { +        free(mFileName);      } +    mFileName = strdup(zipFileName);      mFd = fd;      /* -     * Got it mapped, verify it and create data structures for fast access. +     * Find the Central Directory and store its size and number of entries. +     */ +    if (!mapCentralDirectory()) { +        goto bail; +    } + +    /* +     * Verify Central Directory and create data structures for fast access.       */      if (!parseZipArchive()) { -        mFileMap->release(); -        mFileMap = NULL; -        return UNKNOWN_ERROR; +        goto bail;      }      return OK; + +bail: +    free(mFileName); +    mFileName = NULL; +    close(fd); +    return UNKNOWN_ERROR;  }  /*   * Parse the Zip archive, verifying its contents and initializing internal   * data structures.   */ -bool ZipFileRO::parseZipArchive(void) +bool ZipFileRO::mapCentralDirectory(void)  { -#define CHECK_OFFSET(_off) {                                                \ -        if ((unsigned int) (_off) >= maxOffset) {                           \ -            LOGE("ERROR: bad offset %u (max %d): %s\n",                     \ -                (unsigned int) (_off), maxOffset, #_off);                   \ -            goto bail;                                                      \ -        }                                                                   \ -    } -    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr(); -    const unsigned char* ptr; -    size_t length = mFileMap->getDataLength(); -    bool result = false; -    unsigned int i, numEntries, cdOffset; -    unsigned int val; +    size_t readAmount = kMaxEOCDSearch; +    if (readAmount > (size_t) mFileLength) +        readAmount = mFileLength; + +    unsigned char* scanBuf = (unsigned char*) malloc(readAmount); +    if (scanBuf == NULL) { +        LOGW("couldn't allocate scanBuf: %s", strerror(errno)); +        free(scanBuf); +        return false; +    }      /* -     * The first 4 bytes of the file will either be the local header -     * signature for the first file (kLFHSignature) or, if the archive doesn't -     * have any files in it, the end-of-central-directory signature -     * (kEOCDSignature). +     * Make sure this is a Zip archive.       */ -    val = get4LE(basePtr); -    if (val == kEOCDSignature) { -        LOGI("Found Zip archive, but it looks empty\n"); -        goto bail; -    } else if (val != kLFHSignature) { -        LOGV("Not a Zip archive (found 0x%08x)\n", val); -        goto bail; +    if (lseek(mFd, 0, SEEK_SET) != 0) { +        LOGW("seek to start failed: %s", strerror(errno)); +        free(scanBuf); +        return false; +    } + +    ssize_t actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, sizeof(int32_t))); +    if (actual != (ssize_t) sizeof(int32_t)) { +        LOGI("couldn't read first signature from zip archive: %s", strerror(errno)); +        free(scanBuf); +        return false; +    } + +    { +        unsigned int header = get4LE(scanBuf); +        if (header == kEOCDSignature) { +            LOGI("Found Zip archive, but it looks empty\n"); +            free(scanBuf); +            return false; +        } else if (header != kLFHSignature) { +            LOGV("Not a Zip archive (found 0x%08x)\n", val); +            free(scanBuf); +            return false; +        }      }      /* -     * Find the EOCD.  We'll find it immediately unless they have a file -     * comment. +     * Perform the traditional EOCD snipe hunt. +     * +     * We're searching for the End of Central Directory magic number, +     * which appears at the start of the EOCD block.  It's followed by +     * 18 bytes of EOCD stuff and up to 64KB of archive comment.  We +     * need to read the last part of the file into a buffer, dig through +     * it to find the magic number, parse some values out, and use those +     * to determine the extent of the CD. +     * +     * We start by pulling in the last part of the file.       */ -    ptr = basePtr + length - kEOCDLen; +    off_t searchStart = mFileLength - readAmount; -    while (ptr >= basePtr) { -        if (*ptr == (kEOCDSignature & 0xff) && get4LE(ptr) == kEOCDSignature) +    if (lseek(mFd, searchStart, SEEK_SET) != searchStart) { +        LOGW("seek %ld failed: %s\n",  (long) searchStart, strerror(errno)); +        free(scanBuf); +        return false; +    } +    actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, readAmount)); +    if (actual != (ssize_t) readAmount) { +        LOGW("Zip: read %zd failed: %s\n", readAmount, strerror(errno)); +        free(scanBuf); +        return false; +    } + +    /* +     * Scan backward for the EOCD magic.  In an archive without a trailing +     * comment, we'll find it on the first try.  (We may want to consider +     * doing an initial minimal read; if we don't find it, retry with a +     * second read as above.) +     */ +    int i; +    for (i = readAmount - kEOCDLen; i >= 0; i--) { +        if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) { +            LOGV("+++ Found EOCD at buf+%d\n", i);              break; -        ptr--; +        }      } -    if (ptr < basePtr) { -        LOGI("Could not find end-of-central-directory in Zip\n"); -        goto bail; +    if (i < 0) { +        LOGD("Zip: EOCD not found, %s is not zip\n", mFileName); +        free(scanBuf); +        return false;      } +    off_t eocdOffset = searchStart + i; +    const unsigned char* eocdPtr = scanBuf + i; + +    assert(eocdOffset < mFileLength); +      /* -     * There are two interesting items in the EOCD block: the number of -     * entries in the file, and the file offset of the start of the -     * central directory. -     * -     * (There's actually a count of the #of entries in this file, and for -     * all files which comprise a spanned archive, but for our purposes -     * we're only interested in the current file.  Besides, we expect the -     * two to be equivalent for our stuff.) +     * Grab the CD offset and size, and the number of entries in the +     * archive.  Verify that they look reasonable.       */ -    numEntries = get2LE(ptr + kEOCDNumEntries); -    cdOffset = get4LE(ptr + kEOCDFileOffset); +    unsigned int numEntries = get2LE(eocdPtr + kEOCDNumEntries); +    unsigned int dirSize = get4LE(eocdPtr + kEOCDSize); +    unsigned int dirOffset = get4LE(eocdPtr + kEOCDFileOffset); + +    if ((long long) dirOffset + (long long) dirSize > (long long) eocdOffset) { +        LOGW("bad offsets (dir %ld, size %u, eocd %ld)\n", +            (long) dirOffset, dirSize, (long) eocdOffset); +        free(scanBuf); +        return false; +    } +    if (numEntries == 0) { +        LOGW("empty archive?\n"); +        free(scanBuf); +        return false; +    } -    /* valid offsets are [0,EOCD] */ -    unsigned int maxOffset; -    maxOffset = (ptr - basePtr) +1; +    LOGV("+++ numEntries=%d dirSize=%d dirOffset=%d\n", +        numEntries, dirSize, dirOffset); -    LOGV("+++ numEntries=%d cdOffset=%d\n", numEntries, cdOffset); -    if (numEntries == 0 || cdOffset >= length) { -        LOGW("Invalid entries=%d offset=%d (len=%zd)\n", -            numEntries, cdOffset, length); -        goto bail; +    mDirectoryMap = new FileMap(); +    if (mDirectoryMap == NULL) { +        LOGW("Unable to create directory map: %s", strerror(errno)); +        free(scanBuf); +        return false;      } +    if (!mDirectoryMap->create(mFileName, mFd, dirOffset, dirSize, true)) { +        LOGW("Unable to map '%s' (%zd to %zd): %s\n", mFileName, +                dirOffset, dirOffset + dirSize, strerror(errno)); +        free(scanBuf); +        return false; +    } + +    mNumEntries = numEntries; +    mDirectoryOffset = dirOffset; + +    return true; +} + +bool ZipFileRO::parseZipArchive(void) +{ +    bool result = false; +    const unsigned char* cdPtr = (const unsigned char*) mDirectoryMap->getDataPtr(); +    size_t cdLength = mDirectoryMap->getDataLength(); +    int numEntries = mNumEntries; +      /*       * Create hash table.  We have a minimum 75% load factor, possibly as       * low as 50% after we round off to a power of 2.       */ -    mNumEntries = numEntries; -    mHashTableSize = roundUpPower2(1 + ((numEntries * 4) / 3)); -    mHashTable = (HashEntry*) calloc(1, sizeof(HashEntry) * mHashTableSize); +    mHashTableSize = roundUpPower2(1 + (numEntries * 4) / 3); +    mHashTable = (HashEntry*) calloc(mHashTableSize, sizeof(HashEntry));      /*       * Walk through the central directory, adding entries to the hash       * table.       */ -    ptr = basePtr + cdOffset; -    for (i = 0; i < numEntries; i++) { -        unsigned int fileNameLen, extraLen, commentLen, localHdrOffset; -        const unsigned char* localHdr; -        unsigned int hash; - +    const unsigned char* ptr = cdPtr; +    for (int i = 0; i < numEntries; i++) {          if (get4LE(ptr) != kCDESignature) {              LOGW("Missed a central dir sig (at %d)\n", i);              goto bail;          } -        if (ptr + kCDELen > basePtr + length) { +        if (ptr + kCDELen > cdPtr + cdLength) {              LOGW("Ran off the end (at %d)\n", i);              goto bail;          } -        localHdrOffset = get4LE(ptr + kCDELocalOffset); -        CHECK_OFFSET(localHdrOffset); +        long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset); +        if (localHdrOffset >= mDirectoryOffset) { +            LOGW("bad LFH offset %ld at entry %d\n", localHdrOffset, i); +            goto bail; +        } + +        unsigned int fileNameLen, extraLen, commentLen, hash; +          fileNameLen = get2LE(ptr + kCDENameLen);          extraLen = get2LE(ptr + kCDEExtraLen);          commentLen = get2LE(ptr + kCDECommentLen); -        //LOGV("+++ %d: localHdr=%d fnl=%d el=%d cl=%d\n", -        //    i, localHdrOffset, fileNameLen, extraLen, commentLen); -        //LOGV(" '%.*s'\n", fileNameLen, ptr + kCDELen); -          /* add the CDE filename to the hash table */          hash = computeHash((const char*)ptr + kCDELen, fileNameLen);          addToHash((const char*)ptr + kCDELen, fileNameLen, hash); -        localHdr = basePtr + localHdrOffset; -        if (get4LE(localHdr) != kLFHSignature) { -            LOGW("Bad offset to local header: %d (at %d)\n", -                localHdrOffset, i); +        ptr += kCDELen + fileNameLen + extraLen + commentLen; +        if ((size_t)(ptr - cdPtr) > cdLength) { +            LOGW("bad CD advance (%d vs %zd) at entry %d\n", +                (int) (ptr - cdPtr), cdLength, i);              goto bail;          } - -        ptr += kCDELen + fileNameLen + extraLen + commentLen; -        CHECK_OFFSET(ptr - basePtr);      } - +    LOGV("+++ zip good scan %d entries\n", numEntries);      result = true;  bail:      return result; -#undef CHECK_OFFSET  } -  /*   * Simple string hash function for non-null-terminated strings.   */ @@ -315,7 +399,7 @@ ZipEntryRO ZipFileRO::findEntryByName(const char* fileName) const              memcmp(mHashTable[ent].name, fileName, nameLen) == 0)          {              /* match */ -            return (ZipEntryRO) (ent + kZipEntryAdj); +            return (ZipEntryRO)(long)(ent + kZipEntryAdj);          }          ent = (ent + 1) & (mHashTableSize-1); @@ -354,20 +438,24 @@ ZipEntryRO ZipFileRO::findEntryByIndex(int idx) const   * Returns "false" if the offsets to the fields or the contents of the fields   * appear to be bogus.   */ -bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, long* pUncompLen, -    long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const +bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, +    size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const  { -    int ent = entryToIndex(entry); +    bool ret = false; + +    const int ent = entryToIndex(entry);      if (ent < 0)          return false; +    HashEntry hashEntry = mHashTable[ent]; +      /*       * Recover the start of the central directory entry from the filename -     * pointer. +     * pointer.  The filename is the first entry past the fixed-size data, +     * so we can just subtract back from that.       */ -    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr(); -    const unsigned char* ptr = (const unsigned char*) mHashTable[ent].name; -    size_t zipLength = mFileMap->getDataLength(); +    const unsigned char* ptr = (const unsigned char*) hashEntry.name; +    off_t cdOffset = mDirectoryOffset;      ptr -= kCDELen; @@ -380,48 +468,78 @@ bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, long* pUncompLen,      if (pCrc32 != NULL)          *pCrc32 = get4LE(ptr + kCDECRC); +    size_t compLen = get4LE(ptr + kCDECompLen); +    if (pCompLen != NULL) +        *pCompLen = compLen; +    size_t uncompLen = get4LE(ptr + kCDEUncompLen); +    if (pUncompLen != NULL) +        *pUncompLen = uncompLen; +      /* -     * We need to make sure that the lengths are not so large that somebody -     * trying to map the compressed or uncompressed data runs off the end -     * of the mapped region. +     * If requested, determine the offset of the start of the data.  All we +     * have is the offset to the Local File Header, which is variable size, +     * so we have to read the contents of the struct to figure out where +     * the actual data starts. +     * +     * We also need to make sure that the lengths are not so large that +     * somebody trying to map the compressed or uncompressed data runs +     * off the end of the mapped region. +     * +     * Note we don't verify compLen/uncompLen if they don't request the +     * dataOffset, because dataOffset is expensive to determine.  However, +     * if they don't have the file offset, they're not likely to be doing +     * anything with the contents.       */ -    unsigned long localHdrOffset = get4LE(ptr + kCDELocalOffset); -    if (localHdrOffset + kLFHLen >= zipLength) { -        LOGE("ERROR: bad local hdr offset in zip\n"); -        return false; -    } -    const unsigned char* localHdr = basePtr + localHdrOffset; -    off_t dataOffset = localHdrOffset + kLFHLen -        + get2LE(localHdr + kLFHNameLen) + get2LE(localHdr + kLFHExtraLen); -    if ((unsigned long) dataOffset >= zipLength) { -        LOGE("ERROR: bad data offset in zip\n"); -        return false; -    } +    if (pOffset != NULL) { +        long localHdrOffset = get4LE(ptr + kCDELocalOffset); +        if (localHdrOffset + kLFHLen >= cdOffset) { +            LOGE("ERROR: bad local hdr offset in zip\n"); +            return false; +        } -    if (pCompLen != NULL) { -        *pCompLen = get4LE(ptr + kCDECompLen); -        if (*pCompLen < 0 || (size_t)(dataOffset + *pCompLen) >= zipLength) { -            LOGE("ERROR: bad compressed length in zip\n"); +        unsigned char lfhBuf[kLFHLen]; +        if (lseek(mFd, localHdrOffset, SEEK_SET) != localHdrOffset) { +            LOGW("failed seeking to lfh at offset %ld\n", localHdrOffset);              return false;          } -    } -    if (pUncompLen != NULL) { -        *pUncompLen = get4LE(ptr + kCDEUncompLen); -        if (*pUncompLen < 0) { -            LOGE("ERROR: negative uncompressed length in zip\n"); +        ssize_t actual = +            TEMP_FAILURE_RETRY(read(mFd, lfhBuf, sizeof(lfhBuf))); +        if (actual != sizeof(lfhBuf)) { +            LOGW("failed reading lfh from offset %ld\n", localHdrOffset); +            return false; +        } + +        if (get4LE(lfhBuf) != kLFHSignature) { +            LOGW("didn't find signature at start of lfh, offset=%ld\n", +                localHdrOffset);              return false;          } + +        off_t dataOffset = localHdrOffset + kLFHLen +            + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen); +        if (dataOffset >= cdOffset) { +            LOGW("bad data offset %ld in zip\n", (long) dataOffset); +            return false; +        } + +        /* check lengths */ +        if ((off_t)(dataOffset + compLen) > cdOffset) { +            LOGW("bad compressed length in zip (%ld + %zd > %ld)\n", +                (long) dataOffset, compLen, (long) cdOffset); +            return false; +        } +          if (method == kCompressStored && -            (size_t)(dataOffset + *pUncompLen) >= zipLength) +            (off_t)(dataOffset + uncompLen) > cdOffset)          { -            LOGE("ERROR: bad uncompressed length in zip\n"); +            LOGE("ERROR: bad uncompressed length in zip (%ld + %zd > %ld)\n", +                (long) dataOffset, uncompLen, (long) cdOffset);              return false;          } -    } -    if (pOffset != NULL) {          *pOffset = dataOffset;      } +      return true;  } @@ -457,14 +575,14 @@ FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const       */      FileMap* newMap; -    long compLen; +    size_t compLen;      off_t offset;      if (!getEntryInfo(entry, NULL, NULL, &compLen, &offset, NULL, NULL))          return NULL;      newMap = new FileMap(); -    if (!newMap->create(mFileMap->getFileName(), mFd, offset, compLen, true)) { +    if (!newMap->create(mFileName, mFd, offset, compLen, true)) {          newMap->release();          return NULL;      } @@ -480,19 +598,26 @@ FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const   */  bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer) const  { -    const int kSequentialMin = 32768; +    const size_t kSequentialMin = 32768;      bool result = false;      int ent = entryToIndex(entry);      if (ent < 0)          return -1; -    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();      int method; -    long uncompLen, compLen; +    size_t uncompLen, compLen;      off_t offset; +    const unsigned char* ptr;      getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL); +    FileMap* file = createEntryFileMap(entry); +    if (file == NULL) { +        goto bail; +    } + +    ptr = (const unsigned char*) file->getDataPtr(); +      /*       * Experiment with madvise hint.  When we want to uncompress a file,       * we pull some stuff out of the central dir entry and then hit a @@ -507,17 +632,17 @@ bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer) const       * pair of system calls are negated by a reduction in page faults.       */      if (compLen > kSequentialMin) -        mFileMap->advise(FileMap::SEQUENTIAL); +        file->advise(FileMap::SEQUENTIAL);      if (method == kCompressStored) { -        memcpy(buffer, basePtr + offset, uncompLen); +        memcpy(buffer, ptr, uncompLen);      } else { -        if (!inflateBuffer(buffer, basePtr + offset, uncompLen, compLen)) +        if (!inflateBuffer(buffer, ptr, uncompLen, compLen))              goto bail;      }      if (compLen > kSequentialMin) -        mFileMap->advise(FileMap::NORMAL); +        file->advise(FileMap::NORMAL);      result = true; @@ -537,29 +662,34 @@ bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const      if (ent < 0)          return -1; -    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();      int method; -    long uncompLen, compLen; +    size_t uncompLen, compLen;      off_t offset; +    const unsigned char* ptr;      getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL); -    if (method == kCompressStored) { -        ssize_t actual; +    const FileMap* file = createEntryFileMap(entry); +    if (file == NULL) { +        goto bail; +    } + +    ptr = (const unsigned char*) file->getDataPtr(); -        actual = write(fd, basePtr + offset, uncompLen); +    if (method == kCompressStored) { +        ssize_t actual = write(fd, ptr, uncompLen);          if (actual < 0) {              LOGE("Write failed: %s\n", strerror(errno));              goto bail; -        } else if (actual != uncompLen) { -            LOGE("Partial write during uncompress (%d of %ld)\n", -                (int)actual, uncompLen); +        } else if ((size_t) actual != uncompLen) { +            LOGE("Partial write during uncompress (%zd of %zd)\n", +                actual, uncompLen);              goto bail;          } else {              LOGI("+++ successful write\n");          }      } else { -        if (!inflateBuffer(fd, basePtr+offset, uncompLen, compLen)) +        if (!inflateBuffer(fd, ptr, uncompLen, compLen))              goto bail;      } @@ -573,7 +703,7 @@ bail:   * Uncompress "deflate" data from one buffer to another.   */  /*static*/ bool ZipFileRO::inflateBuffer(void* outBuf, const void* inBuf, -    long uncompLen, long compLen) +    size_t uncompLen, size_t compLen)  {      bool result = false;      z_stream zstream; @@ -582,7 +712,7 @@ bail:      /*       * Initialize the zlib stream struct.       */ -	memset(&zstream, 0, sizeof(zstream)); +    memset(&zstream, 0, sizeof(zstream));      zstream.zalloc = Z_NULL;      zstream.zfree = Z_NULL;      zstream.opaque = Z_NULL; @@ -592,10 +722,10 @@ bail:      zstream.avail_out = uncompLen;      zstream.data_type = Z_UNKNOWN; -	/* -	 * Use the undocumented "negative window bits" feature to tell zlib -	 * that there's no zlib header waiting for it. -	 */ +    /* +     * Use the undocumented "negative window bits" feature to tell zlib +     * that there's no zlib header waiting for it. +     */      zerr = inflateInit2(&zstream, -MAX_WBITS);      if (zerr != Z_OK) {          if (zerr == Z_VERSION_ERROR) { @@ -619,8 +749,8 @@ bail:      }      /* paranoia */ -    if ((long) zstream.total_out != uncompLen) { -        LOGW("Size mismatch on inflated file (%ld vs %ld)\n", +    if (zstream.total_out != uncompLen) { +        LOGW("Size mismatch on inflated file (%ld vs %zd)\n",              zstream.total_out, uncompLen);          goto z_bail;      } @@ -638,10 +768,10 @@ bail:   * Uncompress "deflate" data from one buffer to an open file descriptor.   */  /*static*/ bool ZipFileRO::inflateBuffer(int fd, const void* inBuf, -    long uncompLen, long compLen) +    size_t uncompLen, size_t compLen)  {      bool result = false; -    const int kWriteBufSize = 32768; +    const size_t kWriteBufSize = 32768;      unsigned char writeBuf[kWriteBufSize];      z_stream zstream;      int zerr; @@ -649,7 +779,7 @@ bail:      /*       * Initialize the zlib stream struct.       */ -	memset(&zstream, 0, sizeof(zstream)); +    memset(&zstream, 0, sizeof(zstream));      zstream.zalloc = Z_NULL;      zstream.zfree = Z_NULL;      zstream.opaque = Z_NULL; @@ -659,10 +789,10 @@ bail:      zstream.avail_out = sizeof(writeBuf);      zstream.data_type = Z_UNKNOWN; -	/* -	 * Use the undocumented "negative window bits" feature to tell zlib -	 * that there's no zlib header waiting for it. -	 */ +    /* +     * Use the undocumented "negative window bits" feature to tell zlib +     * that there's no zlib header waiting for it. +     */      zerr = inflateInit2(&zstream, -MAX_WBITS);      if (zerr != Z_OK) {          if (zerr == Z_VERSION_ERROR) { @@ -708,8 +838,8 @@ bail:      assert(zerr == Z_STREAM_END);       /* other errors should've been caught */      /* paranoia */ -    if ((long) zstream.total_out != uncompLen) { -        LOGW("Size mismatch on inflated file (%ld vs %ld)\n", +    if (zstream.total_out != uncompLen) { +        LOGW("Size mismatch on inflated file (%ld vs %zd)\n",              zstream.total_out, uncompLen);          goto z_bail;      } diff --git a/opengl/include/EGL/egl.h b/opengl/include/EGL/egl.h index c269976f4a..99ea342a47 100644 --- a/opengl/include/EGL/egl.h +++ b/opengl/include/EGL/egl.h @@ -1,7 +1,7 @@  /* -*- mode: c; tab-width: 8; -*- */  /* vi: set sw=4 ts=8: */  /* Reference version of egl.h for EGL 1.4. - * $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $ + * $Revision: 9356 $ on $Date: 2009-10-21 02:52:25 -0700 (Wed, 21 Oct 2009) $   */  /* @@ -109,7 +109,6 @@ typedef void *EGLClientBuffer;  #define EGL_NATIVE_RENDERABLE		0x302D  #define EGL_NATIVE_VISUAL_ID		0x302E  #define EGL_NATIVE_VISUAL_TYPE		0x302F -#define EGL_PRESERVED_RESOURCES		0x3030  #define EGL_SAMPLES			0x3031  #define EGL_SAMPLE_BUFFERS		0x3032  #define EGL_SURFACE_TYPE		0x3033 diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h index 545fd0e980..b12115820f 100644 --- a/opengl/include/EGL/eglext.h +++ b/opengl/include/EGL/eglext.h @@ -6,7 +6,7 @@ extern "C" {  #endif  /* -** Copyright (c) 2007-2009 The Khronos Group Inc. +** Copyright (c) 2007-2010 The Khronos Group Inc.  **  ** Permission is hereby granted, free of charge, to any person obtaining a  ** copy of this software and/or associated documentation files (the @@ -34,8 +34,8 @@ extern "C" {  /* Header file version number */  /* Current version at http://www.khronos.org/registry/egl/ */ -/* $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $ */ -#define EGL_EGLEXT_VERSION 3 +/* $Revision: 11249 $ on $Date: 2010-05-05 09:54:28 -0700 (Wed, 05 May 2010) $ */ +#define EGL_EGLEXT_VERSION 5  #ifndef EGL_KHR_config_attribs  #define EGL_KHR_config_attribs 1 @@ -120,6 +120,36 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGL  #define EGL_GL_RENDERBUFFER_KHR			0x30B9	/* eglCreateImageKHR target */  #endif +#ifndef EGL_KHR_reusable_sync +#define EGL_KHR_reusable_sync 1 + +typedef void* EGLSyncKHR; +typedef khronos_utime_nanoseconds_t EGLTimeKHR; + +#define EGL_SYNC_STATUS_KHR			0x30F1 +#define EGL_SIGNALED_KHR			0x30F2 +#define EGL_UNSIGNALED_KHR			0x30F3 +#define EGL_TIMEOUT_EXPIRED_KHR			0x30F5 +#define EGL_CONDITION_SATISFIED_KHR		0x30F6 +#define EGL_SYNC_TYPE_KHR			0x30F7 +#define EGL_SYNC_REUSABLE_KHR			0x30FA +#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR		0x0001	/* eglClientWaitSyncKHR <flags> bitfield */ +#define EGL_FOREVER_KHR				0xFFFFFFFFFFFFFFFFull +#define EGL_NO_SYNC_KHR				((EGLSyncKHR)0) +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync); +EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); +EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode); +EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync); +typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value); +#endif +  #ifndef EGL_KHR_image_base  #define EGL_KHR_image_base 1  /* Most interfaces defined by EGL_KHR_image_pixmap above */ @@ -131,6 +161,67 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGL  /* Interfaces defined by EGL_KHR_image above */  #endif +#ifndef EGL_IMG_context_priority +#define EGL_IMG_context_priority 1 +#define EGL_CONTEXT_PRIORITY_LEVEL_IMG		0x3100 +#define EGL_CONTEXT_PRIORITY_HIGH_IMG		0x3101 +#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG		0x3102 +#define EGL_CONTEXT_PRIORITY_LOW_IMG		0x3103 +#endif + +#ifndef EGL_NV_coverage_sample +#define EGL_NV_coverage_sample 1 +#define EGL_COVERAGE_BUFFERS_NV 0x30E0 +#define EGL_COVERAGE_SAMPLES_NV 0x30E1 +#endif + +#ifndef EGL_NV_depth_nonlinear +#define EGL_NV_depth_nonlinear 1 +#define EGL_DEPTH_ENCODING_NV 0x30E2 +#define EGL_DEPTH_ENCODING_NONE_NV 0 +#define EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3 +#endif + +#ifndef EGL_NV_sync +#define EGL_NV_sync 1 +#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV	0x30E6 +#define EGL_SYNC_STATUS_NV			0x30E7 +#define EGL_SIGNALED_NV				0x30E8 +#define EGL_UNSIGNALED_NV			0x30E9 +#define EGL_SYNC_FLUSH_COMMANDS_BIT_NV		0x0001 +#define EGL_FOREVER_NV				0xFFFFFFFFFFFFFFFFull +#define EGL_ALREADY_SIGNALED_NV			0x30EA +#define EGL_TIMEOUT_EXPIRED_NV			0x30EB +#define EGL_CONDITION_SATISFIED_NV		0x30EC +#define EGL_SYNC_TYPE_NV			0x30ED +#define EGL_SYNC_CONDITION_NV			0x30EE +#define EGL_SYNC_FENCE_NV			0x30EF +#define EGL_NO_SYNC_NV				((EGLSyncNV)0) +typedef void* EGLSyncNV; +typedef unsigned long long EGLTimeNV; +#ifdef EGL_EGLEXT_PROTOTYPES +EGLSyncNV eglCreateFenceSyncNV (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list); +EGLBoolean eglDestroySyncNV (EGLSyncNV sync); +EGLBoolean eglFenceNV (EGLSyncNV sync); +EGLint eglClientWaitSyncNV (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout); +EGLBoolean eglSignalSyncNV (EGLSyncNV sync, EGLenum mode); +EGLBoolean eglGetSyncAttribNV (EGLSyncNV sync, EGLint attribute, EGLint *value); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLSyncNV (EGLAPIENTRYP PFNEGLCREATEFENCESYNCNVPROC) (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCNVPROC) (EGLSyncNV sync); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLFENCENVPROC) (EGLSyncNV sync); +typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCNVPROC) (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCNVPROC) (EGLSyncNV sync, EGLenum mode); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBNVPROC) (EGLSyncNV sync, EGLint attribute, EGLint *value); +#endif + +#ifndef EGL_KHR_fence_sync +#define EGL_KHR_fence_sync 1 +/* Reuses most tokens and entry points from EGL_KHR_reusable_sync */ +#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR	0x30F0 +#define EGL_SYNC_CONDITION_KHR			0x30F8 +#define EGL_SYNC_FENCE_KHR			0x30F9 +#endif  #ifndef EGL_ANDROID_image_native_buffer  #define EGL_ANDROID_image_native_buffer 1 @@ -154,7 +245,6 @@ EGLAPI EGLBoolean EGLAPIENTRY eglSetSwapRectangleANDROID (EGLDisplay dpy, EGLSur  typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSWAPRECTANGLEANDROIDPROC) (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);  #endif -  #ifdef __cplusplus  }  #endif diff --git a/opengl/include/EGL/eglplatform.h b/opengl/include/EGL/eglplatform.h index 53e9e61169..a2c6a7d8ed 100644 --- a/opengl/include/EGL/eglplatform.h +++ b/opengl/include/EGL/eglplatform.h @@ -25,7 +25,7 @@  */  /* Platform-specific types and definitions for egl.h - * $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $ + * $Revision: 9724 $ on $Date: 2009-12-02 02:05:33 -0800 (Wed, 02 Dec 2009) $   *   * Adopters may modify khrplatform.h and this file to suit their platform.   * You are encouraged to submit all modifications to the Khronos group so that @@ -50,8 +50,10 @@  #define EGLAPI KHRONOS_APICALL  #endif +#ifndef EGLAPIENTRY  #define EGLAPIENTRY  KHRONOS_APIENTRY -#define EGLAPIENTRYP KHRONOS_APIENTRY* +#endif +#define EGLAPIENTRYP EGLAPIENTRY*  /* The types NativeDisplayType, NativeWindowType, and NativePixmapType   * are aliases of window-system-dependent types, such as X Display * or diff --git a/opengl/include/GLES/gl.h b/opengl/include/GLES/gl.h index 2e8b97107a..5b8d85a920 100644 --- a/opengl/include/GLES/gl.h +++ b/opengl/include/GLES/gl.h @@ -1,7 +1,7 @@  #ifndef __gl_h_  #define __gl_h_ -/* $Revision: 7172 $ on $Date:: 2009-01-09 11:17:41 -0800 #$ */ +/* $Revision: 10601 $ on $Date:: 2010-03-04 22:15:27 -0800 #$ */  #include <GLES/glplatform.h> @@ -15,6 +15,7 @@ extern "C" {   */  typedef void             GLvoid; +typedef char             GLchar;  typedef unsigned int     GLenum;  typedef unsigned char    GLboolean;  typedef unsigned int     GLbitfield; @@ -678,7 +679,7 @@ GL_API void GL_APIENTRY glGetFixedv (GLenum pname, GLfixed *params);  GL_API void GL_APIENTRY glGetIntegerv (GLenum pname, GLint *params);  GL_API void GL_APIENTRY glGetLightxv (GLenum light, GLenum pname, GLfixed *params);  GL_API void GL_APIENTRY glGetMaterialxv (GLenum face, GLenum pname, GLfixed *params); -GL_API void GL_APIENTRY glGetPointerv (GLenum pname, void **params); +GL_API void GL_APIENTRY glGetPointerv (GLenum pname, GLvoid **params);  GL_API const GLubyte * GL_APIENTRY glGetString (GLenum name);  GL_API void GL_APIENTRY glGetTexEnviv (GLenum env, GLenum pname, GLint *params);  GL_API void GL_APIENTRY glGetTexEnvxv (GLenum env, GLenum pname, GLfixed *params); diff --git a/opengl/include/GLES/glext.h b/opengl/include/GLES/glext.h index a8fe2e9d56..9596148170 100644 --- a/opengl/include/GLES/glext.h +++ b/opengl/include/GLES/glext.h @@ -1,7 +1,7 @@  #ifndef __glext_h_  #define __glext_h_ -/* $Revision: 7172 $ on $Date:: 2009-01-09 11:17:41 -0800 #$ */ +/* $Revision: 10965 $ on $Date:: 2010-04-09 02:11:29 -0700 #$ */  #ifdef __cplusplus  extern "C" { @@ -68,6 +68,11 @@ extern "C" {  typedef void* GLeglImageOES;  #endif +/* GL_OES_element_index_uint */ +#ifndef GL_OES_element_index_uint +#define GL_UNSIGNED_INT                                         0x1405 +#endif +  /* GL_OES_fixed_point */  #ifndef GL_OES_fixed_point  #define GL_FIXED_OES                                            0x140C @@ -201,6 +206,11 @@ typedef void* GLeglImageOES;  #define GL_MIRRORED_REPEAT_OES                                  0x8370  #endif +/* GL_OES_vertex_array_object */ +#ifndef GL_OES_vertex_array_object +#define GL_VERTEX_ARRAY_BINDING_OES                             0x85B5 +#endif +  /*------------------------------------------------------------------------*   * AMD extension tokens   *------------------------------------------------------------------------*/ @@ -219,15 +229,191 @@ typedef void* GLeglImageOES;  #endif  /*------------------------------------------------------------------------* + * APPLE extension tokens + *------------------------------------------------------------------------*/ + +/* GL_APPLE_texture_2D_limited_npot */ +/* No new tokens introduced by this extension. */ + +/*------------------------------------------------------------------------*   * EXT extension tokens   *------------------------------------------------------------------------*/ +/* GL_EXT_blend_minmax */ +#ifndef GL_EXT_blend_minmax +#define GL_MIN_EXT                                              0x8007 +#define GL_MAX_EXT                                              0x8008 +#endif + +/* GL_EXT_discard_framebuffer */ +#ifndef GL_EXT_discard_framebuffer +#define GL_COLOR_EXT                                            0x1800 +#define GL_DEPTH_EXT                                            0x1801 +#define GL_STENCIL_EXT                                          0x1802 +#endif + +/* GL_EXT_multi_draw_arrays */ +/* No new tokens introduced by this extension. */ + +/* GL_EXT_read_format_bgra */ +#ifndef GL_EXT_read_format_bgra +#define GL_BGRA_EXT                                             0x80E1 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT                       0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT                       0x8366 +#endif +  /* GL_EXT_texture_filter_anisotropic */  #ifndef GL_EXT_texture_filter_anisotropic  #define GL_TEXTURE_MAX_ANISOTROPY_EXT                           0x84FE  #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT                       0x84FF  #endif +/* GL_EXT_texture_format_BGRA8888 */ +#ifndef GL_EXT_texture_format_BGRA8888 +#define GL_BGRA_EXT                                             0x80E1 +#endif + +/* GL_EXT_texture_lod_bias */ +#ifndef GL_EXT_texture_lod_bias +#define GL_MAX_TEXTURE_LOD_BIAS_EXT                             0x84FD +#define GL_TEXTURE_FILTER_CONTROL_EXT                           0x8500 +#define GL_TEXTURE_LOD_BIAS_EXT                                 0x8501 +#endif + +/*------------------------------------------------------------------------* + * IMG extension tokens + *------------------------------------------------------------------------*/ + +/* GL_IMG_read_format */ +#ifndef GL_IMG_read_format +#define GL_BGRA_IMG                                             0x80E1 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG                       0x8365 +#endif + +/* GL_IMG_texture_compression_pvrtc */ +#ifndef GL_IMG_texture_compression_pvrtc +#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG                      0x8C00 +#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG                      0x8C01 +#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG                     0x8C02 +#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG                     0x8C03 +#endif + +/* GL_IMG_texture_env_enhanced_fixed_function */ +#ifndef GL_IMG_texture_env_enhanced_fixed_function +#define GL_MODULATE_COLOR_IMG                                   0x8C04 +#define GL_RECIP_ADD_SIGNED_ALPHA_IMG                           0x8C05 +#define GL_TEXTURE_ALPHA_MODULATE_IMG                           0x8C06 +#define GL_FACTOR_ALPHA_MODULATE_IMG                            0x8C07 +#define GL_FRAGMENT_ALPHA_MODULATE_IMG                          0x8C08 +#define GL_ADD_BLEND_IMG                                        0x8C09 +#define GL_DOT3_RGBA_IMG                                        0x86AF +#endif + +/* GL_IMG_user_clip_plane */ +#ifndef GL_IMG_user_clip_plane +#define GL_CLIP_PLANE0_IMG                                      0x3000 +#define GL_CLIP_PLANE1_IMG                                      0x3001 +#define GL_CLIP_PLANE2_IMG                                      0x3002 +#define GL_CLIP_PLANE3_IMG                                      0x3003 +#define GL_CLIP_PLANE4_IMG                                      0x3004 +#define GL_CLIP_PLANE5_IMG                                      0x3005 +#define GL_MAX_CLIP_PLANES_IMG                                  0x0D32 +#endif + +/* GL_IMG_multisampled_render_to_texture */ +#ifndef GL_IMG_multisampled_render_to_texture +#define GL_RENDERBUFFER_SAMPLES_IMG                             0x9133 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG               0x9134 +#define GL_MAX_SAMPLES_IMG                                      0x9135 +#define GL_TEXTURE_SAMPLES_IMG                                  0x9136 +#endif + +/*------------------------------------------------------------------------* + * NV extension tokens + *------------------------------------------------------------------------*/ + +/* GL_NV_fence */ +#ifndef GL_NV_fence +#define GL_ALL_COMPLETED_NV                                     0x84F2 +#define GL_FENCE_STATUS_NV                                      0x84F3 +#define GL_FENCE_CONDITION_NV                                   0x84F4 +#endif + +/*------------------------------------------------------------------------* + * QCOM extension tokens + *------------------------------------------------------------------------*/ + +/* GL_QCOM_driver_control */ +/* No new tokens introduced by this extension. */ + +/* GL_QCOM_extended_get */ +#ifndef GL_QCOM_extended_get +#define GL_TEXTURE_WIDTH_QCOM                                   0x8BD2 +#define GL_TEXTURE_HEIGHT_QCOM                                  0x8BD3 +#define GL_TEXTURE_DEPTH_QCOM                                   0x8BD4 +#define GL_TEXTURE_INTERNAL_FORMAT_QCOM                         0x8BD5 +#define GL_TEXTURE_FORMAT_QCOM                                  0x8BD6 +#define GL_TEXTURE_TYPE_QCOM                                    0x8BD7 +#define GL_TEXTURE_IMAGE_VALID_QCOM                             0x8BD8 +#define GL_TEXTURE_NUM_LEVELS_QCOM                              0x8BD9 +#define GL_TEXTURE_TARGET_QCOM                                  0x8BDA +#define GL_TEXTURE_OBJECT_VALID_QCOM                            0x8BDB +#define GL_STATE_RESTORE                                        0x8BDC +#endif + +/* GL_QCOM_extended_get2 */ +/* No new tokens introduced by this extension. */ + +/* GL_QCOM_perfmon_global_mode */ +#ifndef GL_QCOM_perfmon_global_mode +#define GL_PERFMON_GLOBAL_MODE_QCOM                             0x8FA0 +#endif + +/* GL_QCOM_writeonly_rendering */ +#ifndef GL_QCOM_writeonly_rendering +#define GL_WRITEONLY_RENDERING_QCOM                             0x8823 +#endif + +/* GL_QCOM_tiled_rendering */ +#ifndef GL_QCOM_tiled_rendering +#define GL_COLOR_BUFFER_BIT0_QCOM                               0x00000001 +#define GL_COLOR_BUFFER_BIT1_QCOM                               0x00000002 +#define GL_COLOR_BUFFER_BIT2_QCOM                               0x00000004 +#define GL_COLOR_BUFFER_BIT3_QCOM                               0x00000008 +#define GL_COLOR_BUFFER_BIT4_QCOM                               0x00000010 +#define GL_COLOR_BUFFER_BIT5_QCOM                               0x00000020 +#define GL_COLOR_BUFFER_BIT6_QCOM                               0x00000040 +#define GL_COLOR_BUFFER_BIT7_QCOM                               0x00000080 +#define GL_DEPTH_BUFFER_BIT0_QCOM                               0x00000100 +#define GL_DEPTH_BUFFER_BIT1_QCOM                               0x00000200 +#define GL_DEPTH_BUFFER_BIT2_QCOM                               0x00000400 +#define GL_DEPTH_BUFFER_BIT3_QCOM                               0x00000800 +#define GL_DEPTH_BUFFER_BIT4_QCOM                               0x00001000 +#define GL_DEPTH_BUFFER_BIT5_QCOM                               0x00002000 +#define GL_DEPTH_BUFFER_BIT6_QCOM                               0x00004000 +#define GL_DEPTH_BUFFER_BIT7_QCOM                               0x00008000 +#define GL_STENCIL_BUFFER_BIT0_QCOM                             0x00010000 +#define GL_STENCIL_BUFFER_BIT1_QCOM                             0x00020000 +#define GL_STENCIL_BUFFER_BIT2_QCOM                             0x00040000 +#define GL_STENCIL_BUFFER_BIT3_QCOM                             0x00080000 +#define GL_STENCIL_BUFFER_BIT4_QCOM                             0x00100000 +#define GL_STENCIL_BUFFER_BIT5_QCOM                             0x00200000 +#define GL_STENCIL_BUFFER_BIT6_QCOM                             0x00400000 +#define GL_STENCIL_BUFFER_BIT7_QCOM                             0x00800000 +#define GL_MULTISAMPLE_BUFFER_BIT0_QCOM                         0x01000000 +#define GL_MULTISAMPLE_BUFFER_BIT1_QCOM                         0x02000000 +#define GL_MULTISAMPLE_BUFFER_BIT2_QCOM                         0x04000000 +#define GL_MULTISAMPLE_BUFFER_BIT3_QCOM                         0x08000000 +#define GL_MULTISAMPLE_BUFFER_BIT4_QCOM                         0x10000000 +#define GL_MULTISAMPLE_BUFFER_BIT5_QCOM                         0x20000000 +#define GL_MULTISAMPLE_BUFFER_BIT6_QCOM                         0x40000000 +#define GL_MULTISAMPLE_BUFFER_BIT7_QCOM                         0x80000000 +#endif + +/*------------------------------------------------------------------------* + * End of extension tokens, start of corresponding extension functions + *------------------------------------------------------------------------*/ +  /*------------------------------------------------------------------------*   * OES extension functions   *------------------------------------------------------------------------*/ @@ -456,11 +642,11 @@ typedef void (GL_APIENTRYP PFNGLGENERATEMIPMAPOESPROC) (GLenum target);  #ifdef GL_GLEXT_PROTOTYPES  GL_API void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);  GL_API GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target); -GL_API void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, void** params); +GL_API void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid ** params);  #endif  typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);  typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target); -typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void** params); +typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, GLvoid ** params);  #endif  /* GL_OES_matrix_get */ @@ -576,6 +762,21 @@ typedef void (GL_APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname,  #define GL_OES_texture_mirrored_repeat 1  #endif +/* GL_OES_vertex_array_object */ +#ifndef GL_OES_vertex_array_object +#define GL_OES_vertex_array_object 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_API void GL_APIENTRY glBindVertexArrayOES (GLuint array); +GL_API void GL_APIENTRY glDeleteVertexArraysOES (GLsizei n, const GLuint *arrays); +GL_API void GL_APIENTRY glGenVertexArraysOES (GLsizei n, GLuint *arrays); +GL_API GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array); +#endif +typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array); +typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays); +typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays); +typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array); +#endif +  /*------------------------------------------------------------------------*   * AMD extension functions   *------------------------------------------------------------------------*/ @@ -591,14 +792,207 @@ typedef void (GL_APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname,  #endif  /*------------------------------------------------------------------------* + * APPLE extension functions + *------------------------------------------------------------------------*/ + +/* GL_APPLE_texture_2D_limited_npot */ +#ifndef GL_APPLE_texture_2D_limited_npot +#define GL_APPLE_texture_2D_limited_npot 1 +#endif + +/*------------------------------------------------------------------------*   * EXT extension functions   *------------------------------------------------------------------------*/ +/* GL_EXT_blend_minmax */ +#ifndef GL_EXT_blend_minmax +#define GL_EXT_blend_minmax 1 +#endif + +/* GL_EXT_discard_framebuffer */ +#ifndef GL_EXT_discard_framebuffer +#define GL_EXT_discard_framebuffer 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_API void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments); +#endif +typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); +#endif + +/* GL_EXT_multi_draw_arrays */ +#ifndef GL_EXT_multi_draw_arrays +#define GL_EXT_multi_draw_arrays 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_API void GL_APIENTRY glMultiDrawArraysEXT (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); +GL_API void GL_APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); +typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); +#endif + +/* GL_EXT_read_format_bgra */ +#ifndef GL_EXT_read_format_bgra +#define GL_EXT_read_format_bgra 1 +#endif +  /* GL_EXT_texture_filter_anisotropic */  #ifndef GL_EXT_texture_filter_anisotropic  #define GL_EXT_texture_filter_anisotropic 1  #endif +/* GL_EXT_texture_format_BGRA8888 */ +#ifndef GL_EXT_texture_format_BGRA8888 +#define GL_EXT_texture_format_BGRA8888 1 +#endif + +/* GL_EXT_texture_lod_bias */ +#ifndef GL_EXT_texture_lod_bias +#define GL_EXT_texture_lod_bias 1 +#endif + +/*------------------------------------------------------------------------* + * IMG extension functions + *------------------------------------------------------------------------*/ + +/* GL_IMG_read_format */ +#ifndef GL_IMG_read_format +#define GL_IMG_read_format 1 +#endif + +/* GL_IMG_texture_compression_pvrtc */ +#ifndef GL_IMG_texture_compression_pvrtc +#define GL_IMG_texture_compression_pvrtc 1 +#endif + +/* GL_IMG_texture_env_enhanced_fixed_function */ +#ifndef GL_IMG_texture_env_enhanced_fixed_function +#define GL_IMG_texture_env_enhanced_fixed_function 1 +#endif + +/* GL_IMG_user_clip_plane */ +#ifndef GL_IMG_user_clip_plane +#define GL_IMG_user_clip_plane 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_API void GL_APIENTRY glClipPlanefIMG (GLenum p, const GLfloat *eqn); +GL_API void GL_APIENTRY glClipPlanexIMG (GLenum p, const GLfixed *eqn); +#endif +typedef void (GL_APIENTRYP PFNGLCLIPPLANEFIMGPROC) (GLenum p, const GLfloat *eqn); +typedef void (GL_APIENTRYP PFNGLCLIPPLANEXIMGPROC) (GLenum p, const GLfixed *eqn); +#endif + +/* GL_IMG_multisampled_render_to_texture */ +#ifndef GL_IMG_multisampled_render_to_texture +#define GL_IMG_multisampled_render_to_texture 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_API void GL_APIENTRY glRenderbufferStorageMultisampleIMG (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GL_API void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); +#endif +typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMG) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMG) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); +#endif + +/*------------------------------------------------------------------------* + * NV extension functions + *------------------------------------------------------------------------*/ + +/* NV_fence */ +#ifndef GL_NV_fence +#define GL_NV_fence 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_API void GL_APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences); +GL_API void GL_APIENTRY glGenFencesNV (GLsizei n, GLuint *fences); +GL_API GLboolean GL_APIENTRY glIsFenceNV (GLuint fence); +GL_API GLboolean GL_APIENTRY glTestFenceNV (GLuint fence); +GL_API void GL_APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params); +GL_API void GL_APIENTRY glFinishFenceNV (GLuint fence); +GL_API void GL_APIENTRY glSetFenceNV (GLuint fence, GLenum condition); +#endif +typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); +typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); +typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); +typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); +typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); +typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); +#endif + +/*------------------------------------------------------------------------* + * QCOM extension functions + *------------------------------------------------------------------------*/ + +/* GL_QCOM_driver_control */ +#ifndef GL_QCOM_driver_control +#define GL_QCOM_driver_control 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_API void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls); +GL_API void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString); +GL_API void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl); +GL_API void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl); +#endif +typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls); +typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString); +typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl); +typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl); +#endif + +/* GL_QCOM_extended_get */ +#ifndef GL_QCOM_extended_get +#define GL_QCOM_extended_get 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_API void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures); +GL_API void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers); +GL_API void GL_APIENTRY glExtGetRenderbuffersQCOM (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers); +GL_API void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers); +GL_API void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params); +GL_API void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param); +GL_API void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels); +GL_API void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, GLvoid **params); +#endif +typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures); +typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers); +typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers); +typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers); +typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param); +typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels); +typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, GLvoid **params); +#endif + +/* GL_QCOM_extended_get2 */ +#ifndef GL_QCOM_extended_get2 +#define GL_QCOM_extended_get2 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_API void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders); +GL_API void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms); +GL_API GLboolean GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program); +GL_API void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, GLchar *source, GLint *length); +#endif +typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders); +typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms); +typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program); +typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length); +#endif + +/* GL_QCOM_perfmon_global_mode */ +#ifndef GL_QCOM_perfmon_global_mode +#define GL_QCOM_perfmon_global_mode 1 +#endif + +/* GL_QCOM_writeonly_rendering */ +#ifndef GL_QCOM_writeonly_rendering +#define GL_QCOM_writeonly_rendering 1 +#endif + +/* GL_QCOM_tiled_rendering */ +#ifndef GL_QCOM_tiled_rendering +#define GL_QCOM_tiled_rendering 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_API void GL_APIENTRY glStartTilingQCOM (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask); +GL_API void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask); +#endif +typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask); +typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask); +#endif +  #ifdef __cplusplus  }  #endif diff --git a/opengl/include/GLES/glplatform.h b/opengl/include/GLES/glplatform.h index 198e679db2..2db6ee2ca6 100644 --- a/opengl/include/GLES/glplatform.h +++ b/opengl/include/GLES/glplatform.h @@ -1,7 +1,7 @@  #ifndef __glplatform_h_  #define __glplatform_h_ -/* $Revision: 7172 $ on $Date:: 2009-01-09 11:17:41 -0800 #$ */ +/* $Revision: 10601 $ on $Date:: 2010-03-04 22:15:27 -0800 #$ */  /*   * This document is licensed under the SGI Free Software B License Version @@ -9,7 +9,6 @@   */  /* Platform-specific types and definitions for OpenGL ES 1.X  gl.h - * Last modified on 2008/12/19   *   * Adopters may modify khrplatform.h and this file to suit their platform.   * You are encouraged to submit all modifications to the Khronos group so that @@ -24,10 +23,8 @@  #define GL_API      KHRONOS_APICALL  #endif -#if defined(ANDROID) - +#ifndef GL_APIENTRY  #define GL_APIENTRY KHRONOS_APIENTRY -  #endif  #endif /* __glplatform_h_ */ diff --git a/opengl/include/GLES2/gl2.h b/opengl/include/GLES2/gl2.h index 0182a676d1..e1d3b87cc5 100644 --- a/opengl/include/GLES2/gl2.h +++ b/opengl/include/GLES2/gl2.h @@ -1,7 +1,7 @@  #ifndef __gl2_h_  #define __gl2_h_ -/* $Revision: 7173 $ on $Date:: 2009-01-09 11:18:21 -0800 #$ */ +/* $Revision: 10602 $ on $Date:: 2010-03-04 22:35:34 -0800 #$ */  #include <GLES2/gl2platform.h> @@ -19,6 +19,7 @@ extern "C" {   *-----------------------------------------------------------------------*/  typedef void             GLvoid; +typedef char             GLchar;  typedef unsigned int     GLenum;  typedef unsigned char    GLboolean;  typedef unsigned int     GLbitfield; @@ -472,7 +473,7 @@ typedef khronos_ssize_t  GLsizeiptr;  GL_APICALL void         GL_APIENTRY glActiveTexture (GLenum texture);  GL_APICALL void         GL_APIENTRY glAttachShader (GLuint program, GLuint shader); -GL_APICALL void         GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const char* name); +GL_APICALL void         GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar* name);  GL_APICALL void         GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);  GL_APICALL void         GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);  GL_APICALL void         GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); @@ -482,8 +483,8 @@ GL_APICALL void         GL_APIENTRY glBlendEquation ( GLenum mode );  GL_APICALL void         GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);  GL_APICALL void         GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);  GL_APICALL void         GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -GL_APICALL void         GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void* data, GLenum usage); -GL_APICALL void         GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void* data); +GL_APICALL void         GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage); +GL_APICALL void         GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);  GL_APICALL GLenum       GL_APIENTRY glCheckFramebufferStatus (GLenum target);  GL_APICALL void         GL_APIENTRY glClear (GLbitfield mask);  GL_APICALL void         GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); @@ -491,8 +492,8 @@ GL_APICALL void         GL_APIENTRY glClearDepthf (GLclampf depth);  GL_APICALL void         GL_APIENTRY glClearStencil (GLint s);  GL_APICALL void         GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);  GL_APICALL void         GL_APIENTRY glCompileShader (GLuint shader); -GL_APICALL void         GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data); -GL_APICALL void         GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data); +GL_APICALL void         GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data); +GL_APICALL void         GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data);  GL_APICALL void         GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);  GL_APICALL void         GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);  GL_APICALL GLuint       GL_APIENTRY glCreateProgram (void); @@ -511,7 +512,7 @@ GL_APICALL void         GL_APIENTRY glDetachShader (GLuint program, GLuint shade  GL_APICALL void         GL_APIENTRY glDisable (GLenum cap);  GL_APICALL void         GL_APIENTRY glDisableVertexAttribArray (GLuint index);  GL_APICALL void         GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count); -GL_APICALL void         GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void* indices); +GL_APICALL void         GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);  GL_APICALL void         GL_APIENTRY glEnable (GLenum cap);  GL_APICALL void         GL_APIENTRY glEnableVertexAttribArray (GLuint index);  GL_APICALL void         GL_APIENTRY glFinish (void); @@ -524,10 +525,10 @@ GL_APICALL void         GL_APIENTRY glGenerateMipmap (GLenum target);  GL_APICALL void         GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers);  GL_APICALL void         GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);  GL_APICALL void         GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures); -GL_APICALL void         GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name); -GL_APICALL void         GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name); +GL_APICALL void         GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); +GL_APICALL void         GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);  GL_APICALL void         GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders); -GL_APICALL int          GL_APIENTRY glGetAttribLocation (GLuint program, const char* name); +GL_APICALL int          GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name);  GL_APICALL void         GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params);  GL_APICALL void         GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);  GL_APICALL GLenum       GL_APIENTRY glGetError (void); @@ -535,21 +536,21 @@ GL_APICALL void         GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params);  GL_APICALL void         GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);  GL_APICALL void         GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params);  GL_APICALL void         GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params); -GL_APICALL void         GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, char* infolog); +GL_APICALL void         GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);  GL_APICALL void         GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);  GL_APICALL void         GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params); -GL_APICALL void         GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog); +GL_APICALL void         GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);  GL_APICALL void         GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); -GL_APICALL void         GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, char* source); +GL_APICALL void         GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);  GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name);  GL_APICALL void         GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params);  GL_APICALL void         GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params);  GL_APICALL void         GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params);  GL_APICALL void         GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params); -GL_APICALL int          GL_APIENTRY glGetUniformLocation (GLuint program, const char* name); +GL_APICALL int          GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar* name);  GL_APICALL void         GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params);  GL_APICALL void         GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params); -GL_APICALL void         GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void** pointer); +GL_APICALL void         GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer);  GL_APICALL void         GL_APIENTRY glHint (GLenum target, GLenum mode);  GL_APICALL GLboolean    GL_APIENTRY glIsBuffer (GLuint buffer);  GL_APICALL GLboolean    GL_APIENTRY glIsEnabled (GLenum cap); @@ -562,25 +563,25 @@ GL_APICALL void         GL_APIENTRY glLineWidth (GLfloat width);  GL_APICALL void         GL_APIENTRY glLinkProgram (GLuint program);  GL_APICALL void         GL_APIENTRY glPixelStorei (GLenum pname, GLint param);  GL_APICALL void         GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); -GL_APICALL void         GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels); +GL_APICALL void         GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);  GL_APICALL void         GL_APIENTRY glReleaseShaderCompiler (void);  GL_APICALL void         GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);  GL_APICALL void         GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);  GL_APICALL void         GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height); -GL_APICALL void         GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length); -GL_APICALL void         GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const char** string, const GLint* length); +GL_APICALL void         GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length); +GL_APICALL void         GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar** string, const GLint* length);  GL_APICALL void         GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);  GL_APICALL void         GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);  GL_APICALL void         GL_APIENTRY glStencilMask (GLuint mask);  GL_APICALL void         GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);  GL_APICALL void         GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);  GL_APICALL void         GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass); -GL_APICALL void         GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat,  GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels); +GL_APICALL void         GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);  GL_APICALL void         GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);  GL_APICALL void         GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params);  GL_APICALL void         GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);  GL_APICALL void         GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params); -GL_APICALL void         GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels); +GL_APICALL void         GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels);  GL_APICALL void         GL_APIENTRY glUniform1f (GLint location, GLfloat x);  GL_APICALL void         GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v);  GL_APICALL void         GL_APIENTRY glUniform1i (GLint location, GLint x); @@ -610,7 +611,7 @@ GL_APICALL void         GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GL  GL_APICALL void         GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);  GL_APICALL void         GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);  GL_APICALL void         GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values); -GL_APICALL void         GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr); +GL_APICALL void         GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);  GL_APICALL void         GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);  #ifdef __cplusplus diff --git a/opengl/include/GLES2/gl2ext.h b/opengl/include/GLES2/gl2ext.h index 72f1ae79ad..d8c9f41deb 100644 --- a/opengl/include/GLES2/gl2ext.h +++ b/opengl/include/GLES2/gl2ext.h @@ -1,7 +1,7 @@  #ifndef __gl2ext_h_  #define __gl2ext_h_ -/* $Revision: 8271 $ on $Date:: 2009-05-21 09:33:40 -0700 #$ */ +/* $Revision: 10969 $ on $Date:: 2010-04-09 02:27:15 -0700 #$ */  #ifdef __cplusplus  extern "C" { @@ -57,6 +57,11 @@ extern "C" {  typedef void* GLeglImageOES;  #endif +/* GL_OES_element_index_uint */ +#ifndef GL_OES_element_index_uint +#define GL_UNSIGNED_INT                                         0x1405 +#endif +  /* GL_OES_get_program_binary */  #ifndef GL_OES_get_program_binary  #define GL_PROGRAM_BINARY_LENGTH_OES                            0x8741 @@ -100,8 +105,8 @@ typedef void* GLeglImageOES;  #define GL_STENCIL_INDEX4_OES                                   0x8D47  #endif -/* GL_OES_texture3D */ -#ifndef GL_OES_texture3D +/* GL_OES_texture_3D */ +#ifndef GL_OES_texture_3D  #define GL_TEXTURE_WRAP_R_OES                                   0x8072  #define GL_TEXTURE_3D_OES                                       0x806F  #define GL_TEXTURE_BINDING_3D_OES                               0x806A @@ -110,11 +115,28 @@ typedef void* GLeglImageOES;  #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES        0x8CD4  #endif +/* GL_OES_texture_float */ +/* No new tokens introduced by this extension. */ + +/* GL_OES_texture_float_linear */ +/* No new tokens introduced by this extension. */ +  /* GL_OES_texture_half_float */  #ifndef GL_OES_texture_half_float  #define GL_HALF_FLOAT_OES                                       0x8D61  #endif +/* GL_OES_texture_half_float_linear */ +/* No new tokens introduced by this extension. */ + +/* GL_OES_texture_npot */ +/* No new tokens introduced by this extension. */ + +/* GL_OES_vertex_array_object */ +#ifndef GL_OES_vertex_array_object +#define GL_VERTEX_ARRAY_BINDING_OES                             0x85B5 +#endif +  /* GL_OES_vertex_half_float */  /* GL_HALF_FLOAT_OES defined in GL_OES_texture_half_float already. */ @@ -141,11 +163,6 @@ typedef void* GLeglImageOES;  #define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD                      0x87EE  #endif -/* GL_AMD_program_binary_Z400 */ -#ifndef GL_AMD_program_binary_Z400 -#define GL_Z400_BINARY_AMD                                      0x8740 -#endif -  /* GL_AMD_performance_monitor */  #ifndef GL_AMD_performance_monitor  #define GL_COUNTER_TYPE_AMD                                     0x8BC0 @@ -157,35 +174,78 @@ typedef void* GLeglImageOES;  #define GL_PERFMON_RESULT_AMD                                   0x8BC6  #endif +/* GL_AMD_program_binary_Z400 */ +#ifndef GL_AMD_program_binary_Z400 +#define GL_Z400_BINARY_AMD                                      0x8740 +#endif +  /*------------------------------------------------------------------------*   * EXT extension tokens   *------------------------------------------------------------------------*/ +/* GL_EXT_blend_minmax */ +#ifndef GL_EXT_blend_minmax +#define GL_MIN_EXT                                              0x8007 +#define GL_MAX_EXT                                              0x8008 +#endif + +/* GL_EXT_discard_framebuffer */ +#ifndef GL_EXT_discard_framebuffer +#define GL_COLOR_EXT                                            0x1800 +#define GL_DEPTH_EXT                                            0x1801 +#define GL_STENCIL_EXT                                          0x1802 +#endif + +/* GL_EXT_multi_draw_arrays */ +/* No new tokens introduced by this extension. */ + +/* GL_EXT_read_format_bgra */ +#ifndef GL_EXT_read_format_bgra +#define GL_BGRA_EXT                                             0x80E1 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT                       0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT                       0x8366 +#endif +  /* GL_EXT_texture_filter_anisotropic */  #ifndef GL_EXT_texture_filter_anisotropic  #define GL_TEXTURE_MAX_ANISOTROPY_EXT                           0x84FE  #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT                       0x84FF  #endif +/* GL_EXT_texture_format_BGRA8888 */ +#ifndef GL_EXT_texture_format_BGRA8888 +#define GL_BGRA_EXT                                             0x80E1 +#endif +  /* GL_EXT_texture_type_2_10_10_10_REV */  #ifndef GL_EXT_texture_type_2_10_10_10_REV  #define GL_UNSIGNED_INT_2_10_10_10_REV_EXT                      0x8368  #endif -/* GL_EXT_texture_format_BGRA8888 */ -#ifndef GL_EXT_texture_format_BGRA8888 -#define GL_BGRA                                                 0x80E1 +/* GL_EXT_texture_compression_dxt1 */ +#ifndef GL_EXT_texture_compression_dxt1 +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT                         0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT                        0x83F1  #endif  /*------------------------------------------------------------------------*   * IMG extension tokens   *------------------------------------------------------------------------*/ +/* GL_IMG_program_binary */ +#ifndef GL_IMG_program_binary +#define GL_SGX_PROGRAM_BINARY_IMG                               0x9130 +#endif +  /* GL_IMG_read_format */  #ifndef GL_IMG_read_format -#define GL_BGRA                                                 0x80E1 -#define GL_UNSIGNED_SHORT_4_4_4_4_REV                           0x8365 -#define GL_UNSIGNED_SHORT_1_5_5_5_REV                           0x8366 +#define GL_BGRA_IMG                                             0x80E1 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG                       0x8365 +#endif + +/* GL_IMG_shader_binary */ +#ifndef GL_IMG_shader_binary +#define GL_SGX_BINARY_IMG                                       0x8C0A  #endif  /* GL_IMG_texture_compression_pvrtc */ @@ -196,6 +256,14 @@ typedef void* GLeglImageOES;  #define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG                     0x8C03  #endif +/* GL_IMG_multisampled_render_to_texture */ +#ifndef GL_IMG_multisampled_render_to_texture +#define GL_RENDERBUFFER_SAMPLES_IMG                             0x9133 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG               0x9134 +#define GL_MAX_SAMPLES_IMG                                      0x9135 +#define GL_TEXTURE_SAMPLES_IMG                                  0x9136 +#endif +  /*------------------------------------------------------------------------*   * NV extension tokens   *------------------------------------------------------------------------*/ @@ -207,6 +275,24 @@ typedef void* GLeglImageOES;  #define GL_FENCE_CONDITION_NV                                   0x84F4  #endif +/* GL_NV_coverage_sample */ +#ifndef GL_NV_coverage_sample +#define GL_COVERAGE_COMPONENT_NV                                0x8ED0 +#define GL_COVERAGE_COMPONENT4_NV                               0x8ED1 +#define GL_COVERAGE_ATTACHMENT_NV                               0x8ED2 +#define GL_COVERAGE_BUFFERS_NV                                  0x8ED3 +#define GL_COVERAGE_SAMPLES_NV                                  0x8ED4 +#define GL_COVERAGE_ALL_FRAGMENTS_NV                            0x8ED5 +#define GL_COVERAGE_EDGE_FRAGMENTS_NV                           0x8ED6 +#define GL_COVERAGE_AUTOMATIC_NV                                0x8ED7 +#define GL_COVERAGE_BUFFER_BIT_NV                               0x8000 +#endif + +/* GL_NV_depth_nonlinear */ +#ifndef GL_NV_depth_nonlinear +#define GL_DEPTH_COMPONENT16_NONLINEAR_NV                       0x8E2C +#endif +  /*------------------------------------------------------------------------*   * QCOM extension tokens   *------------------------------------------------------------------------*/ @@ -214,11 +300,70 @@ typedef void* GLeglImageOES;  /* GL_QCOM_driver_control */  /* No new tokens introduced by this extension. */ +/* GL_QCOM_extended_get */ +#ifndef GL_QCOM_extended_get +#define GL_TEXTURE_WIDTH_QCOM                                   0x8BD2 +#define GL_TEXTURE_HEIGHT_QCOM                                  0x8BD3 +#define GL_TEXTURE_DEPTH_QCOM                                   0x8BD4 +#define GL_TEXTURE_INTERNAL_FORMAT_QCOM                         0x8BD5 +#define GL_TEXTURE_FORMAT_QCOM                                  0x8BD6 +#define GL_TEXTURE_TYPE_QCOM                                    0x8BD7 +#define GL_TEXTURE_IMAGE_VALID_QCOM                             0x8BD8 +#define GL_TEXTURE_NUM_LEVELS_QCOM                              0x8BD9 +#define GL_TEXTURE_TARGET_QCOM                                  0x8BDA +#define GL_TEXTURE_OBJECT_VALID_QCOM                            0x8BDB +#define GL_STATE_RESTORE                                        0x8BDC +#endif + +/* GL_QCOM_extended_get2 */ +/* No new tokens introduced by this extension. */ +  /* GL_QCOM_perfmon_global_mode */  #ifndef GL_QCOM_perfmon_global_mode  #define GL_PERFMON_GLOBAL_MODE_QCOM                             0x8FA0  #endif +/* GL_QCOM_writeonly_rendering */ +#ifndef GL_QCOM_writeonly_rendering +#define GL_WRITEONLY_RENDERING_QCOM                             0x8823 +#endif + +/* GL_QCOM_tiled_rendering */ +#ifndef GL_QCOM_tiled_rendering +#define GL_COLOR_BUFFER_BIT0_QCOM                               0x00000001 +#define GL_COLOR_BUFFER_BIT1_QCOM                               0x00000002 +#define GL_COLOR_BUFFER_BIT2_QCOM                               0x00000004 +#define GL_COLOR_BUFFER_BIT3_QCOM                               0x00000008 +#define GL_COLOR_BUFFER_BIT4_QCOM                               0x00000010 +#define GL_COLOR_BUFFER_BIT5_QCOM                               0x00000020 +#define GL_COLOR_BUFFER_BIT6_QCOM                               0x00000040 +#define GL_COLOR_BUFFER_BIT7_QCOM                               0x00000080 +#define GL_DEPTH_BUFFER_BIT0_QCOM                               0x00000100 +#define GL_DEPTH_BUFFER_BIT1_QCOM                               0x00000200 +#define GL_DEPTH_BUFFER_BIT2_QCOM                               0x00000400 +#define GL_DEPTH_BUFFER_BIT3_QCOM                               0x00000800 +#define GL_DEPTH_BUFFER_BIT4_QCOM                               0x00001000 +#define GL_DEPTH_BUFFER_BIT5_QCOM                               0x00002000 +#define GL_DEPTH_BUFFER_BIT6_QCOM                               0x00004000 +#define GL_DEPTH_BUFFER_BIT7_QCOM                               0x00008000 +#define GL_STENCIL_BUFFER_BIT0_QCOM                             0x00010000 +#define GL_STENCIL_BUFFER_BIT1_QCOM                             0x00020000 +#define GL_STENCIL_BUFFER_BIT2_QCOM                             0x00040000 +#define GL_STENCIL_BUFFER_BIT3_QCOM                             0x00080000 +#define GL_STENCIL_BUFFER_BIT4_QCOM                             0x00100000 +#define GL_STENCIL_BUFFER_BIT5_QCOM                             0x00200000 +#define GL_STENCIL_BUFFER_BIT6_QCOM                             0x00400000 +#define GL_STENCIL_BUFFER_BIT7_QCOM                             0x00800000 +#define GL_MULTISAMPLE_BUFFER_BIT0_QCOM                         0x01000000 +#define GL_MULTISAMPLE_BUFFER_BIT1_QCOM                         0x02000000 +#define GL_MULTISAMPLE_BUFFER_BIT2_QCOM                         0x04000000 +#define GL_MULTISAMPLE_BUFFER_BIT3_QCOM                         0x08000000 +#define GL_MULTISAMPLE_BUFFER_BIT4_QCOM                         0x10000000 +#define GL_MULTISAMPLE_BUFFER_BIT5_QCOM                         0x20000000 +#define GL_MULTISAMPLE_BUFFER_BIT6_QCOM                         0x40000000 +#define GL_MULTISAMPLE_BUFFER_BIT7_QCOM                         0x80000000 +#endif +  /*------------------------------------------------------------------------*   * End of extension tokens, start of corresponding extension functions   *------------------------------------------------------------------------*/ @@ -237,17 +382,6 @@ typedef void* GLeglImageOES;  #define GL_OES_compressed_paletted_texture 1  #endif -/* GL_OES_EGL_image */ -#ifndef GL_OES_EGL_image -#define GL_OES_EGL_image 1 -#ifdef GL_GLEXT_PROTOTYPES -GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image); -GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image); -#endif -typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image); -typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image); -#endif -  /* GL_OES_depth24 */  #ifndef GL_OES_depth24  #define GL_OES_depth24 1 @@ -263,6 +397,17 @@ typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenu  #define GL_OES_depth_texture 1  #endif +/* GL_OES_EGL_image */ +#ifndef GL_OES_EGL_image +#define GL_OES_EGL_image 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image); +GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image); +#endif +typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image); +typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image); +#endif +  /* GL_OES_element_index_uint */  #ifndef GL_OES_element_index_uint  #define GL_OES_element_index_uint 1 @@ -282,11 +427,11 @@ typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenu  #ifndef GL_OES_get_program_binary  #define GL_OES_get_program_binary 1  #ifdef GL_GLEXT_PROTOTYPES -GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); -GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const void *binary, GLint length); +GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); +GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);  #endif -typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); -typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLint length); +typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); +typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);  #endif  /* GL_OES_mapbuffer */ @@ -295,11 +440,11 @@ typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum bi  #ifdef GL_GLEXT_PROTOTYPES  GL_APICALL void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);  GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target); -GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, void** params); +GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid** params);  #endif  typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);  typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target); -typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void** params); +typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, GLvoid** params);  #endif  /* GL_OES_packed_depth_stencil */ @@ -331,46 +476,61 @@ typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum  #ifndef GL_OES_texture_3D  #define GL_OES_texture_3D 1  #ifdef GL_GLEXT_PROTOTYPES -GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels); -GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); +GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels); +GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);  GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data); -GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data); +GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data); +GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);  GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);  #endif  typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels); -typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); +typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);  typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data); -typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data); +typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data); +typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);  typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);  #endif -/* GL_OES_texture_float_linear */ -#ifndef GL_OES_texture_float_linear -#define GL_OES_texture_float_linear 1 -#endif - -/* GL_OES_texture_half_float_linear */ -#ifndef GL_OES_texture_half_float_linear -#define GL_OES_texture_half_float_linear 1 -#endif -  /* GL_OES_texture_float */  #ifndef GL_OES_texture_float  #define GL_OES_texture_float 1  #endif +/* GL_OES_texture_float_linear */ +#ifndef GL_OES_texture_float_linear +#define GL_OES_texture_float_linear 1 +#endif +  /* GL_OES_texture_half_float */  #ifndef GL_OES_texture_half_float  #define GL_OES_texture_half_float 1  #endif +/* GL_OES_texture_half_float_linear */ +#ifndef GL_OES_texture_half_float_linear +#define GL_OES_texture_half_float_linear 1 +#endif +  /* GL_OES_texture_npot */  #ifndef GL_OES_texture_npot  #define GL_OES_texture_npot 1  #endif +/* GL_OES_vertex_array_object */ +#ifndef GL_OES_vertex_array_object +#define GL_OES_vertex_array_object 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glBindVertexArrayOES (GLuint array); +GL_APICALL void GL_APIENTRY glDeleteVertexArraysOES (GLsizei n, const GLuint *arrays); +GL_APICALL void GL_APIENTRY glGenVertexArraysOES (GLsizei n, GLuint *arrays); +GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array); +#endif +typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array); +typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays); +typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays); +typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array); +#endif +  /* GL_OES_vertex_half_float */  #ifndef GL_OES_vertex_half_float  #define GL_OES_vertex_half_float 1 @@ -395,20 +555,15 @@ typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum  #define GL_AMD_compressed_ATC_texture 1  #endif -/* GL_AMD_program_binary_Z400 */ -#ifndef GL_AMD_program_binary_Z400 -#define GL_AMD_program_binary_Z400 1 -#endif -  /* AMD_performance_monitor */  #ifndef GL_AMD_performance_monitor  #define GL_AMD_performance_monitor 1  #ifdef GL_GLEXT_PROTOTYPES  GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups);  GL_APICALL void GL_APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); -GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, char *groupString); -GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString); -GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, void *data); +GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); +GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); +GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, GLvoid *data);  GL_APICALL void GL_APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors);  GL_APICALL void GL_APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors);  GL_APICALL void GL_APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList); @@ -418,9 +573,9 @@ GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLen  #endif  typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups);  typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); -typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, char *groupString); -typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString); -typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data); +typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); +typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); +typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data);  typedef void (GL_APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);  typedef void (GL_APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);  typedef void (GL_APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList); @@ -429,39 +584,99 @@ typedef void (GL_APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor);  typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);  #endif +/* GL_AMD_program_binary_Z400 */ +#ifndef GL_AMD_program_binary_Z400 +#define GL_AMD_program_binary_Z400 1 +#endif +  /*------------------------------------------------------------------------*   * EXT extension functions   *------------------------------------------------------------------------*/ +/* GL_EXT_blend_minmax */ +#ifndef GL_EXT_blend_minmax +#define GL_EXT_blend_minmax 1 +#endif + +/* GL_EXT_discard_framebuffer */ +#ifndef GL_EXT_discard_framebuffer +#define GL_EXT_discard_framebuffer 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments); +#endif +typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); +#endif + +#ifndef GL_EXT_multi_draw_arrays +#define GL_EXT_multi_draw_arrays 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glMultiDrawArraysEXT (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); +GL_APICALL void GL_APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); +typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); +#endif + +/* GL_EXT_read_format_bgra */ +#ifndef GL_EXT_read_format_bgra +#define GL_EXT_read_format_bgra 1 +#endif +  /* GL_EXT_texture_filter_anisotropic */  #ifndef GL_EXT_texture_filter_anisotropic  #define GL_EXT_texture_filter_anisotropic 1  #endif +/* GL_EXT_texture_format_BGRA8888 */ +#ifndef GL_EXT_texture_format_BGRA8888 +#define GL_EXT_texture_format_BGRA8888 1 +#endif +  /* GL_EXT_texture_type_2_10_10_10_REV */  #ifndef GL_EXT_texture_type_2_10_10_10_REV  #define GL_EXT_texture_type_2_10_10_10_REV 1  #endif -/* GL_EXT_texture_format_BGRA8888 */ -#ifndef GL_EXT_texture_format_BGRA8888 -#define GL_EXT_texture_format_BGRA8888 1 +/* GL_EXT_texture_compression_dxt1 */ +#ifndef GL_EXT_texture_compression_dxt1 +#define GL_EXT_texture_compression_dxt1 1  #endif  /*------------------------------------------------------------------------*   * IMG extension functions   *------------------------------------------------------------------------*/ +/* GL_IMG_program_binary */ +#ifndef GL_IMG_program_binary +#define GL_IMG_program_binary 1 +#endif +  /* GL_IMG_read_format */  #ifndef GL_IMG_read_format  #define GL_IMG_read_format 1  #endif +/* GL_IMG_shader_binary */ +#ifndef GL_IMG_shader_binary +#define GL_IMG_shader_binary 1 +#endif +  /* GL_IMG_texture_compression_pvrtc */  #ifndef GL_IMG_texture_compression_pvrtc  #define GL_IMG_texture_compression_pvrtc 1  #endif +/* GL_IMG_multisampled_render_to_texture */ +#ifndef GL_IMG_multisampled_render_to_texture +#define GL_IMG_multisampled_render_to_texture 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleIMG (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); +#endif +typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMG) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMG) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); +#endif +  /*------------------------------------------------------------------------*   * NV extension functions   *------------------------------------------------------------------------*/ @@ -487,6 +702,22 @@ typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);  typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);  #endif +/* GL_NV_coverage_sample */ +#ifndef GL_NV_coverage_sample +#define GL_NV_coverage_sample 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glCoverageMaskNV (GLboolean mask); +GL_APICALL void GL_APIENTRY glCoverageOperationNV (GLenum operation); +#endif +typedef void (GL_APIENTRYP PFNGLCOVERAGEMASKNVPROC) (GLboolean mask); +typedef void (GL_APIENTRYP PFNGLCOVERAGEOPERATIONNVPROC) (GLenum operation); +#endif + +/* GL_NV_depth_nonlinear */ +#ifndef GL_NV_depth_nonlinear +#define GL_NV_depth_nonlinear 1 +#endif +  /*------------------------------------------------------------------------*   * QCOM extension functions   *------------------------------------------------------------------------*/ @@ -496,21 +727,75 @@ typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition)  #define GL_QCOM_driver_control 1  #ifdef GL_GLEXT_PROTOTYPES  GL_APICALL void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls); -GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString); +GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);  GL_APICALL void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl);  GL_APICALL void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl);  #endif  typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls); -typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString); +typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);  typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);  typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);  #endif +/* GL_QCOM_extended_get */ +#ifndef GL_QCOM_extended_get +#define GL_QCOM_extended_get 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures); +GL_APICALL void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers); +GL_APICALL void GL_APIENTRY glExtGetRenderbuffersQCOM (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers); +GL_APICALL void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers); +GL_APICALL void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param); +GL_APICALL void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels); +GL_APICALL void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, GLvoid **params); +#endif +typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures); +typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers); +typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers); +typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers); +typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param); +typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels); +typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, GLvoid **params); +#endif + +/* GL_QCOM_extended_get2 */ +#ifndef GL_QCOM_extended_get2 +#define GL_QCOM_extended_get2 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders); +GL_APICALL void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms); +GL_APICALL GLboolean GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program); +GL_APICALL void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, GLchar *source, GLint *length); +#endif +typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders); +typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms); +typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program); +typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length); +#endif +  /* GL_QCOM_perfmon_global_mode */  #ifndef GL_QCOM_perfmon_global_mode  #define GL_QCOM_perfmon_global_mode 1  #endif +/* GL_QCOM_writeonly_rendering */ +#ifndef GL_QCOM_writeonly_rendering +#define GL_QCOM_writeonly_rendering 1 +#endif + +/* GL_QCOM_tiled_rendering */ +#ifndef GL_QCOM_tiled_rendering +#define GL_QCOM_tiled_rendering 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glStartTilingQCOM (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask); +GL_APICALL void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask); +#endif +typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask); +typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask); +#endif +  #ifdef __cplusplus  }  #endif diff --git a/opengl/include/GLES2/gl2platform.h b/opengl/include/GLES2/gl2platform.h index 3e9036c162..c9fa3c4d64 100644 --- a/opengl/include/GLES2/gl2platform.h +++ b/opengl/include/GLES2/gl2platform.h @@ -1,7 +1,7 @@  #ifndef __gl2platform_h_  #define __gl2platform_h_ -/* $Revision: 7173 $ on $Date:: 2009-01-09 11:18:21 -0800 #$ */ +/* $Revision: 10602 $ on $Date:: 2010-03-04 22:35:34 -0800 #$ */  /*   * This document is licensed under the SGI Free Software B License Version @@ -9,7 +9,6 @@   */  /* Platform-specific types and definitions for OpenGL ES 2.X  gl2.h - * Last modified on 2008/12/19   *   * Adopters may modify khrplatform.h and this file to suit their platform.   * You are encouraged to submit all modifications to the Khronos group so that @@ -24,6 +23,8 @@  #define GL_APICALL  KHRONOS_APICALL  #endif +#ifndef GL_APIENTRY  #define GL_APIENTRY KHRONOS_APIENTRY +#endif  #endif /* __gl2platform_h_ */ diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk index 6cb146c060..8abd649968 100644 --- a/opengl/libagl/Android.mk +++ b/opengl/libagl/Android.mk @@ -37,6 +37,10 @@ ifeq ($(TARGET_ARCH),arm)  	LOCAL_CFLAGS += -fstrict-aliasing  endif +ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true) +    LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER +endif +  ifneq ($(TARGET_SIMULATOR),true)      # we need to access the private Bionic header <bionic_tls.h>      # on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp index b6e0aae74e..7cb01d0e1a 100644 --- a/opengl/libagl/egl.cpp +++ b/opengl/libagl/egl.cpp @@ -1525,8 +1525,13 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,      }      if (ggl_unlikely(attrib_list==0)) { -        *num_config = 0; -        return EGL_TRUE; +        /* +         * A NULL attrib_list should be treated as though it was an empty +         * one (terminated with EGL_NONE) as defined in +         * section 3.4.1 "Querying Configurations" in the EGL specification. +         */ +        static const EGLint dummy = EGL_NONE; +        attrib_list = &dummy;      }      int numAttributes = 0; diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp index 9407bd5530..d67612e681 100644 --- a/opengl/libagl/texture.cpp +++ b/opengl/libagl/texture.cpp @@ -1515,7 +1515,7 @@ void glReadPixels(          ogles_error(c, GL_INVALID_VALUE);          return;      } -    if (x<0 || x<0) { +    if (x<0 || y<0) {          ogles_error(c, GL_INVALID_VALUE);          return;      } diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 89b3e1f2ab..ba09d082fe 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -239,7 +239,7 @@ struct tls_t  // ---------------------------------------------------------------------------- -egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS]; +static egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];  static egl_display_t gDisplay[NUM_DISPLAYS];  static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;  static pthread_key_t gEGLThreadLocalStorageKey = -1; @@ -843,10 +843,12 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,      EGLint patch_index = -1;      GLint attr;      size_t size = 0; -    while ((attr=attrib_list[size]) != EGL_NONE) { -        if (attr == EGL_CONFIG_ID) -            patch_index = size; -        size += 2; +    if (attrib_list) { +        while ((attr=attrib_list[size]) != EGL_NONE) { +            if (attr == EGL_CONFIG_ID) +                patch_index = size; +            size += 2; +        }      }      if (patch_index >= 0) {          size += 2; // we need copy the sentinel as well diff --git a/opengl/libs/GLES2/gl2_api.in b/opengl/libs/GLES2/gl2_api.in index 9c2e69aea0..5164450ba9 100644 --- a/opengl/libs/GLES2/gl2_api.in +++ b/opengl/libs/GLES2/gl2_api.in @@ -4,7 +4,7 @@ void API_ENTRY(glActiveTexture)(GLenum texture) {  void API_ENTRY(glAttachShader)(GLuint program, GLuint shader) {      CALL_GL_API(glAttachShader, program, shader);  } -void API_ENTRY(glBindAttribLocation)(GLuint program, GLuint index, const char* name) { +void API_ENTRY(glBindAttribLocation)(GLuint program, GLuint index, const GLchar* name) {      CALL_GL_API(glBindAttribLocation, program, index, name);  }  void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) { @@ -34,10 +34,10 @@ void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) {  void API_ENTRY(glBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {      CALL_GL_API(glBlendFuncSeparate, srcRGB, dstRGB, srcAlpha, dstAlpha);  } -void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const void* data, GLenum usage) { +void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) {      CALL_GL_API(glBufferData, target, size, data, usage);  } -void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const void* data) { +void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) {      CALL_GL_API(glBufferSubData, target, offset, size, data);  }  GLenum API_ENTRY(glCheckFramebufferStatus)(GLenum target) { @@ -61,10 +61,10 @@ void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLbo  void API_ENTRY(glCompileShader)(GLuint shader) {      CALL_GL_API(glCompileShader, shader);  } -void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data) { +void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) {      CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data);  } -void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) { +void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) {      CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data);  }  void API_ENTRY(glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { @@ -121,7 +121,7 @@ void API_ENTRY(glDisableVertexAttribArray)(GLuint index) {  void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) {      CALL_GL_API(glDrawArrays, mode, first, count);  } -void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, GLenum type, const void* indices) { +void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) {      CALL_GL_API(glDrawElements, mode, count, type, indices);  }  void API_ENTRY(glEnable)(GLenum cap) { @@ -160,16 +160,16 @@ void API_ENTRY(glGenRenderbuffers)(GLsizei n, GLuint* renderbuffers) {  void API_ENTRY(glGenTextures)(GLsizei n, GLuint* textures) {      CALL_GL_API(glGenTextures, n, textures);  } -void API_ENTRY(glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) { +void API_ENTRY(glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) {      CALL_GL_API(glGetActiveAttrib, program, index, bufsize, length, size, type, name);  } -void API_ENTRY(glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) { +void API_ENTRY(glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) {      CALL_GL_API(glGetActiveUniform, program, index, bufsize, length, size, type, name);  }  void API_ENTRY(glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {      CALL_GL_API(glGetAttachedShaders, program, maxcount, count, shaders);  } -int API_ENTRY(glGetAttribLocation)(GLuint program, const char* name) { +int API_ENTRY(glGetAttribLocation)(GLuint program, const GLchar* name) {      CALL_GL_API_RETURN(glGetAttribLocation, program, name);  }  void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean* params) { @@ -193,7 +193,7 @@ void API_ENTRY(glGetIntegerv)(GLenum pname, GLint* params) {  void API_ENTRY(glGetProgramiv)(GLuint program, GLenum pname, GLint* params) {      CALL_GL_API(glGetProgramiv, program, pname, params);  } -void API_ENTRY(glGetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) { +void API_ENTRY(glGetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) {      CALL_GL_API(glGetProgramInfoLog, program, bufsize, length, infolog);  }  void API_ENTRY(glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params) { @@ -202,13 +202,13 @@ void API_ENTRY(glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint*  void API_ENTRY(glGetShaderiv)(GLuint shader, GLenum pname, GLint* params) {      CALL_GL_API(glGetShaderiv, shader, pname, params);  } -void API_ENTRY(glGetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) { +void API_ENTRY(glGetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) {      CALL_GL_API(glGetShaderInfoLog, shader, bufsize, length, infolog);  }  void API_ENTRY(glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {      CALL_GL_API(glGetShaderPrecisionFormat, shadertype, precisiontype, range, precision);  } -void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, char* source) { +void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) {      CALL_GL_API(glGetShaderSource, shader, bufsize, length, source);  }  const GLubyte* API_ENTRY(glGetString)(GLenum name) { @@ -226,7 +226,7 @@ void API_ENTRY(glGetUniformfv)(GLuint program, GLint location, GLfloat* params)  void API_ENTRY(glGetUniformiv)(GLuint program, GLint location, GLint* params) {      CALL_GL_API(glGetUniformiv, program, location, params);  } -int API_ENTRY(glGetUniformLocation)(GLuint program, const char* name) { +int API_ENTRY(glGetUniformLocation)(GLuint program, const GLchar* name) {      CALL_GL_API_RETURN(glGetUniformLocation, program, name);  }  void API_ENTRY(glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params) { @@ -235,7 +235,7 @@ void API_ENTRY(glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params)  void API_ENTRY(glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params) {      CALL_GL_API(glGetVertexAttribiv, index, pname, params);  } -void API_ENTRY(glGetVertexAttribPointerv)(GLuint index, GLenum pname, void** pointer) { +void API_ENTRY(glGetVertexAttribPointerv)(GLuint index, GLenum pname, GLvoid** pointer) {      CALL_GL_API(glGetVertexAttribPointerv, index, pname, pointer);  }  void API_ENTRY(glHint)(GLenum target, GLenum mode) { @@ -274,7 +274,7 @@ void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) {  void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) {      CALL_GL_API(glPolygonOffset, factor, units);  } -void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) { +void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) {      CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);  }  void API_ENTRY(glReleaseShaderCompiler)(void) { @@ -289,10 +289,10 @@ void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) {  void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) {      CALL_GL_API(glScissor, x, y, width, height);  } -void API_ENTRY(glShaderBinary)(GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length) { +void API_ENTRY(glShaderBinary)(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) {      CALL_GL_API(glShaderBinary, n, shaders, binaryformat, binary, length);  } -void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const char** string, const GLint* length) { +void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) {      CALL_GL_API(glShaderSource, shader, count, string, length);  }  void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) { @@ -313,7 +313,7 @@ void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) {  void API_ENTRY(glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) {      CALL_GL_API(glStencilOpSeparate, face, fail, zfail, zpass);  } -void API_ENTRY(glTexImage2D)(GLenum target, GLint level, GLint internalformat,  GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) { +void API_ENTRY(glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) {      CALL_GL_API(glTexImage2D, target, level, internalformat, width, height, border, format, type, pixels);  }  void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) { @@ -328,7 +328,7 @@ void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) {  void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint* params) {      CALL_GL_API(glTexParameteriv, target, pname, params);  } -void API_ENTRY(glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) { +void API_ENTRY(glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) {      CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset, width, height, format, type, pixels);  }  void API_ENTRY(glUniform1f)(GLint location, GLfloat x) { @@ -418,7 +418,7 @@ void API_ENTRY(glVertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, G  void API_ENTRY(glVertexAttrib4fv)(GLuint indx, const GLfloat* values) {      CALL_GL_API(glVertexAttrib4fv, indx, values);  } -void API_ENTRY(glVertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr) { +void API_ENTRY(glVertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) {      CALL_GL_API(glVertexAttribPointer, indx, size, type, normalized, stride, ptr);  }  void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) { diff --git a/opengl/libs/GLES2/gl2ext_api.in b/opengl/libs/GLES2/gl2ext_api.in index 6eeecb33dc..e965625178 100644 --- a/opengl/libs/GLES2/gl2ext_api.in +++ b/opengl/libs/GLES2/gl2ext_api.in @@ -4,10 +4,10 @@ void API_ENTRY(__glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES imag  void API_ENTRY(__glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) {      CALL_GL_API(glEGLImageTargetRenderbufferStorageOES, target, image);  } -void API_ENTRY(glGetProgramBinaryOES)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) { +void API_ENTRY(glGetProgramBinaryOES)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary) {      CALL_GL_API(glGetProgramBinaryOES, program, bufSize, length, binaryFormat, binary);  } -void API_ENTRY(glProgramBinaryOES)(GLuint program, GLenum binaryFormat, const void *binary, GLint length) { +void API_ENTRY(glProgramBinaryOES)(GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length) {      CALL_GL_API(glProgramBinaryOES, program, binaryFormat, binary, length);  }  void* API_ENTRY(glMapBufferOES)(GLenum target, GLenum access) { @@ -16,40 +16,52 @@ void* API_ENTRY(glMapBufferOES)(GLenum target, GLenum access) {  GLboolean API_ENTRY(glUnmapBufferOES)(GLenum target) {      CALL_GL_API_RETURN(glUnmapBufferOES, target);  } -void API_ENTRY(glGetBufferPointervOES)(GLenum target, GLenum pname, void** params) { +void API_ENTRY(glGetBufferPointervOES)(GLenum target, GLenum pname, GLvoid** params) {      CALL_GL_API(glGetBufferPointervOES, target, pname, params);  } -void API_ENTRY(glTexImage3DOES)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels) { +void API_ENTRY(glTexImage3DOES)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels) {      CALL_GL_API(glTexImage3DOES, target, level, internalformat, width, height, depth, border, format, type, pixels);  } -void API_ENTRY(glTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) { +void API_ENTRY(glTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels) {      CALL_GL_API(glTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);  }  void API_ENTRY(glCopyTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) {      CALL_GL_API(glCopyTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, x, y, width, height);  } -void API_ENTRY(glCompressedTexImage3DOES)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data) { +void API_ENTRY(glCompressedTexImage3DOES)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data) {      CALL_GL_API(glCompressedTexImage3DOES, target, level, internalformat, width, height, depth, border, imageSize, data);  } -void API_ENTRY(glCompressedTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data) { +void API_ENTRY(glCompressedTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data) {      CALL_GL_API(glCompressedTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);  }  void API_ENTRY(glFramebufferTexture3DOES)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) {      CALL_GL_API(glFramebufferTexture3DOES, target, attachment, textarget, texture, level, zoffset);  } +void API_ENTRY(glBindVertexArrayOES)(GLuint array) { +    CALL_GL_API(glBindVertexArrayOES, array); +} +void API_ENTRY(glDeleteVertexArraysOES)(GLsizei n, const GLuint *arrays) { +    CALL_GL_API(glDeleteVertexArraysOES, n, arrays); +} +void API_ENTRY(glGenVertexArraysOES)(GLsizei n, GLuint *arrays) { +    CALL_GL_API(glGenVertexArraysOES, n, arrays); +} +GLboolean API_ENTRY(glIsVertexArrayOES)(GLuint array) { +    CALL_GL_API_RETURN(glIsVertexArrayOES, array); +}  void API_ENTRY(glGetPerfMonitorGroupsAMD)(GLint *numGroups, GLsizei groupsSize, GLuint *groups) {      CALL_GL_API(glGetPerfMonitorGroupsAMD, numGroups, groupsSize, groups);  }  void API_ENTRY(glGetPerfMonitorCountersAMD)(GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters) {      CALL_GL_API(glGetPerfMonitorCountersAMD, group, numCounters, maxActiveCounters, counterSize, counters);  } -void API_ENTRY(glGetPerfMonitorGroupStringAMD)(GLuint group, GLsizei bufSize, GLsizei *length, char *groupString) { +void API_ENTRY(glGetPerfMonitorGroupStringAMD)(GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString) {      CALL_GL_API(glGetPerfMonitorGroupStringAMD, group, bufSize, length, groupString);  } -void API_ENTRY(glGetPerfMonitorCounterStringAMD)(GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString) { +void API_ENTRY(glGetPerfMonitorCounterStringAMD)(GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString) {      CALL_GL_API(glGetPerfMonitorCounterStringAMD, group, counter, bufSize, length, counterString);  } -void API_ENTRY(glGetPerfMonitorCounterInfoAMD)(GLuint group, GLuint counter, GLenum pname, void *data) { +void API_ENTRY(glGetPerfMonitorCounterInfoAMD)(GLuint group, GLuint counter, GLenum pname, GLvoid *data) {      CALL_GL_API(glGetPerfMonitorCounterInfoAMD, group, counter, pname, data);  }  void API_ENTRY(glGenPerfMonitorsAMD)(GLsizei n, GLuint *monitors) { @@ -70,6 +82,21 @@ void API_ENTRY(glEndPerfMonitorAMD)(GLuint monitor) {  void API_ENTRY(glGetPerfMonitorCounterDataAMD)(GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten) {      CALL_GL_API(glGetPerfMonitorCounterDataAMD, monitor, pname, dataSize, data, bytesWritten);  } +void API_ENTRY(glDiscardFramebufferEXT)(GLenum target, GLsizei numAttachments, const GLenum *attachments) { +    CALL_GL_API(glDiscardFramebufferEXT, target, numAttachments, attachments); +} +void API_ENTRY(glMultiDrawArraysEXT)(GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) { +    CALL_GL_API(glMultiDrawArraysEXT, mode, first, count, primcount); +} +void API_ENTRY(glMultiDrawElementsEXT)(GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount) { +    CALL_GL_API(glMultiDrawElementsEXT, mode, count, type, indices, primcount); +} +void API_ENTRY(glRenderbufferStorageMultisampleIMG)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { +    CALL_GL_API(glRenderbufferStorageMultisampleIMG, target, samples, internalformat, width, height); +} +void API_ENTRY(glFramebufferTexture2DMultisampleIMG)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) { +    CALL_GL_API(glFramebufferTexture2DMultisampleIMG, target, attachment, textarget, texture, level, samples); +}  void API_ENTRY(glDeleteFencesNV)(GLsizei n, const GLuint *fences) {      CALL_GL_API(glDeleteFencesNV, n, fences);  } @@ -91,10 +118,16 @@ void API_ENTRY(glFinishFenceNV)(GLuint fence) {  void API_ENTRY(glSetFenceNV)(GLuint fence, GLenum condition) {      CALL_GL_API(glSetFenceNV, fence, condition);  } +void API_ENTRY(glCoverageMaskNV)(GLboolean mask) { +    CALL_GL_API(glCoverageMaskNV, mask); +} +void API_ENTRY(glCoverageOperationNV)(GLenum operation) { +    CALL_GL_API(glCoverageOperationNV, operation); +}  void API_ENTRY(glGetDriverControlsQCOM)(GLint *num, GLsizei size, GLuint *driverControls) {      CALL_GL_API(glGetDriverControlsQCOM, num, size, driverControls);  } -void API_ENTRY(glGetDriverControlStringQCOM)(GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString) { +void API_ENTRY(glGetDriverControlStringQCOM)(GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString) {      CALL_GL_API(glGetDriverControlStringQCOM, driverControl, bufSize, length, driverControlString);  }  void API_ENTRY(glEnableDriverControlQCOM)(GLuint driverControl) { @@ -103,3 +136,45 @@ void API_ENTRY(glEnableDriverControlQCOM)(GLuint driverControl) {  void API_ENTRY(glDisableDriverControlQCOM)(GLuint driverControl) {      CALL_GL_API(glDisableDriverControlQCOM, driverControl);  } +void API_ENTRY(glExtGetTexturesQCOM)(GLuint *textures, GLint maxTextures, GLint *numTextures) { +    CALL_GL_API(glExtGetTexturesQCOM, textures, maxTextures, numTextures); +} +void API_ENTRY(glExtGetBuffersQCOM)(GLuint *buffers, GLint maxBuffers, GLint *numBuffers) { +    CALL_GL_API(glExtGetBuffersQCOM, buffers, maxBuffers, numBuffers); +} +void API_ENTRY(glExtGetRenderbuffersQCOM)(GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers) { +    CALL_GL_API(glExtGetRenderbuffersQCOM, renderbuffers, maxRenderbuffers, numRenderbuffers); +} +void API_ENTRY(glExtGetFramebuffersQCOM)(GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers) { +    CALL_GL_API(glExtGetFramebuffersQCOM, framebuffers, maxFramebuffers, numFramebuffers); +} +void API_ENTRY(glExtGetTexLevelParameterivQCOM)(GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params) { +    CALL_GL_API(glExtGetTexLevelParameterivQCOM, texture, face, level, pname, params); +} +void API_ENTRY(glExtTexObjectStateOverrideiQCOM)(GLenum target, GLenum pname, GLint param) { +    CALL_GL_API(glExtTexObjectStateOverrideiQCOM, target, pname, param); +} +void API_ENTRY(glExtGetTexSubImageQCOM)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels) { +    CALL_GL_API(glExtGetTexSubImageQCOM, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texels); +} +void API_ENTRY(glExtGetBufferPointervQCOM)(GLenum target, GLvoid **params) { +    CALL_GL_API(glExtGetBufferPointervQCOM, target, params); +} +void API_ENTRY(glExtGetShadersQCOM)(GLuint *shaders, GLint maxShaders, GLint *numShaders) { +    CALL_GL_API(glExtGetShadersQCOM, shaders, maxShaders, numShaders); +} +void API_ENTRY(glExtGetProgramsQCOM)(GLuint *programs, GLint maxPrograms, GLint *numPrograms) { +    CALL_GL_API(glExtGetProgramsQCOM, programs, maxPrograms, numPrograms); +} +GLboolean API_ENTRY(glExtIsProgramBinaryQCOM)(GLuint program) { +    CALL_GL_API_RETURN(glExtIsProgramBinaryQCOM, program); +} +void API_ENTRY(glExtGetProgramBinarySourceQCOM)(GLuint program, GLenum shadertype, GLchar *source, GLint *length) { +    CALL_GL_API(glExtGetProgramBinarySourceQCOM, program, shadertype, source, length); +} +void API_ENTRY(glStartTilingQCOM)(GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask) { +    CALL_GL_API(glStartTilingQCOM, x, y, width, height, preserveMask); +} +void API_ENTRY(glEndTilingQCOM)(GLbitfield preserveMask) { +    CALL_GL_API(glEndTilingQCOM, preserveMask); +} diff --git a/opengl/libs/GLES_CM/gl_api.in b/opengl/libs/GLES_CM/gl_api.in index 5437d47f20..7f20c4fda4 100644 --- a/opengl/libs/GLES_CM/gl_api.in +++ b/opengl/libs/GLES_CM/gl_api.in @@ -259,7 +259,7 @@ void API_ENTRY(glGetLightxv)(GLenum light, GLenum pname, GLfixed *params) {  void API_ENTRY(glGetMaterialxv)(GLenum face, GLenum pname, GLfixed *params) {      CALL_GL_API(glGetMaterialxv, face, pname, params);  } -void API_ENTRY(glGetPointerv)(GLenum pname, void **params) { +void API_ENTRY(glGetPointerv)(GLenum pname, GLvoid **params) {      CALL_GL_API(glGetPointerv, pname, params);  }  const GLubyte * API_ENTRY(glGetString)(GLenum name) { diff --git a/opengl/libs/GLES_CM/glext_api.in b/opengl/libs/GLES_CM/glext_api.in index 2c8648e259..5393fa61a0 100644 --- a/opengl/libs/GLES_CM/glext_api.in +++ b/opengl/libs/GLES_CM/glext_api.in @@ -205,7 +205,7 @@ void* API_ENTRY(glMapBufferOES)(GLenum target, GLenum access) {  GLboolean API_ENTRY(glUnmapBufferOES)(GLenum target) {      CALL_GL_API_RETURN(glUnmapBufferOES, target);  } -void API_ENTRY(glGetBufferPointervOES)(GLenum target, GLenum pname, void** params) { +void API_ENTRY(glGetBufferPointervOES)(GLenum target, GLenum pname, GLvoid ** params) {      CALL_GL_API(glGetBufferPointervOES, target, pname, params);  }  void API_ENTRY(glCurrentPaletteMatrixOES)(GLuint matrixpaletteindex) { @@ -268,3 +268,111 @@ void API_ENTRY(glGetTexGenivOES)(GLenum coord, GLenum pname, GLint *params) {  void API_ENTRY(glGetTexGenxvOES)(GLenum coord, GLenum pname, GLfixed *params) {      CALL_GL_API(glGetTexGenxvOES, coord, pname, params);  } +void API_ENTRY(glBindVertexArrayOES)(GLuint array) { +    CALL_GL_API(glBindVertexArrayOES, array); +} +void API_ENTRY(glDeleteVertexArraysOES)(GLsizei n, const GLuint *arrays) { +    CALL_GL_API(glDeleteVertexArraysOES, n, arrays); +} +void API_ENTRY(glGenVertexArraysOES)(GLsizei n, GLuint *arrays) { +    CALL_GL_API(glGenVertexArraysOES, n, arrays); +} +GLboolean API_ENTRY(glIsVertexArrayOES)(GLuint array) { +    CALL_GL_API_RETURN(glIsVertexArrayOES, array); +} +void API_ENTRY(glDiscardFramebufferEXT)(GLenum target, GLsizei numAttachments, const GLenum *attachments) { +    CALL_GL_API(glDiscardFramebufferEXT, target, numAttachments, attachments); +} +void API_ENTRY(glMultiDrawArraysEXT)(GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) { +    CALL_GL_API(glMultiDrawArraysEXT, mode, first, count, primcount); +} +void API_ENTRY(glMultiDrawElementsEXT)(GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount) { +    CALL_GL_API(glMultiDrawElementsEXT, mode, count, type, indices, primcount); +} +void API_ENTRY(glClipPlanefIMG)(GLenum p, const GLfloat *eqn) { +    CALL_GL_API(glClipPlanefIMG, p, eqn); +} +void API_ENTRY(glClipPlanexIMG)(GLenum p, const GLfixed *eqn) { +    CALL_GL_API(glClipPlanexIMG, p, eqn); +} +void API_ENTRY(glRenderbufferStorageMultisampleIMG)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { +    CALL_GL_API(glRenderbufferStorageMultisampleIMG, target, samples, internalformat, width, height); +} +void API_ENTRY(glFramebufferTexture2DMultisampleIMG)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) { +    CALL_GL_API(glFramebufferTexture2DMultisampleIMG, target, attachment, textarget, texture, level, samples); +} +void API_ENTRY(glDeleteFencesNV)(GLsizei n, const GLuint *fences) { +    CALL_GL_API(glDeleteFencesNV, n, fences); +} +void API_ENTRY(glGenFencesNV)(GLsizei n, GLuint *fences) { +    CALL_GL_API(glGenFencesNV, n, fences); +} +GLboolean API_ENTRY(glIsFenceNV)(GLuint fence) { +    CALL_GL_API_RETURN(glIsFenceNV, fence); +} +GLboolean API_ENTRY(glTestFenceNV)(GLuint fence) { +    CALL_GL_API_RETURN(glTestFenceNV, fence); +} +void API_ENTRY(glGetFenceivNV)(GLuint fence, GLenum pname, GLint *params) { +    CALL_GL_API(glGetFenceivNV, fence, pname, params); +} +void API_ENTRY(glFinishFenceNV)(GLuint fence) { +    CALL_GL_API(glFinishFenceNV, fence); +} +void API_ENTRY(glSetFenceNV)(GLuint fence, GLenum condition) { +    CALL_GL_API(glSetFenceNV, fence, condition); +} +void API_ENTRY(glGetDriverControlsQCOM)(GLint *num, GLsizei size, GLuint *driverControls) { +    CALL_GL_API(glGetDriverControlsQCOM, num, size, driverControls); +} +void API_ENTRY(glGetDriverControlStringQCOM)(GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString) { +    CALL_GL_API(glGetDriverControlStringQCOM, driverControl, bufSize, length, driverControlString); +} +void API_ENTRY(glEnableDriverControlQCOM)(GLuint driverControl) { +    CALL_GL_API(glEnableDriverControlQCOM, driverControl); +} +void API_ENTRY(glDisableDriverControlQCOM)(GLuint driverControl) { +    CALL_GL_API(glDisableDriverControlQCOM, driverControl); +} +void API_ENTRY(glExtGetTexturesQCOM)(GLuint *textures, GLint maxTextures, GLint *numTextures) { +    CALL_GL_API(glExtGetTexturesQCOM, textures, maxTextures, numTextures); +} +void API_ENTRY(glExtGetBuffersQCOM)(GLuint *buffers, GLint maxBuffers, GLint *numBuffers) { +    CALL_GL_API(glExtGetBuffersQCOM, buffers, maxBuffers, numBuffers); +} +void API_ENTRY(glExtGetRenderbuffersQCOM)(GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers) { +    CALL_GL_API(glExtGetRenderbuffersQCOM, renderbuffers, maxRenderbuffers, numRenderbuffers); +} +void API_ENTRY(glExtGetFramebuffersQCOM)(GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers) { +    CALL_GL_API(glExtGetFramebuffersQCOM, framebuffers, maxFramebuffers, numFramebuffers); +} +void API_ENTRY(glExtGetTexLevelParameterivQCOM)(GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params) { +    CALL_GL_API(glExtGetTexLevelParameterivQCOM, texture, face, level, pname, params); +} +void API_ENTRY(glExtTexObjectStateOverrideiQCOM)(GLenum target, GLenum pname, GLint param) { +    CALL_GL_API(glExtTexObjectStateOverrideiQCOM, target, pname, param); +} +void API_ENTRY(glExtGetTexSubImageQCOM)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels) { +    CALL_GL_API(glExtGetTexSubImageQCOM, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texels); +} +void API_ENTRY(glExtGetBufferPointervQCOM)(GLenum target, GLvoid **params) { +    CALL_GL_API(glExtGetBufferPointervQCOM, target, params); +} +void API_ENTRY(glExtGetShadersQCOM)(GLuint *shaders, GLint maxShaders, GLint *numShaders) { +    CALL_GL_API(glExtGetShadersQCOM, shaders, maxShaders, numShaders); +} +void API_ENTRY(glExtGetProgramsQCOM)(GLuint *programs, GLint maxPrograms, GLint *numPrograms) { +    CALL_GL_API(glExtGetProgramsQCOM, programs, maxPrograms, numPrograms); +} +GLboolean API_ENTRY(glExtIsProgramBinaryQCOM)(GLuint program) { +    CALL_GL_API_RETURN(glExtIsProgramBinaryQCOM, program); +} +void API_ENTRY(glExtGetProgramBinarySourceQCOM)(GLuint program, GLenum shadertype, GLchar *source, GLint *length) { +    CALL_GL_API(glExtGetProgramBinarySourceQCOM, program, shadertype, source, length); +} +void API_ENTRY(glStartTilingQCOM)(GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask) { +    CALL_GL_API(glStartTilingQCOM, x, y, width, height, preserveMask); +} +void API_ENTRY(glEndTilingQCOM)(GLbitfield preserveMask) { +    CALL_GL_API(glEndTilingQCOM, preserveMask); +} diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h index 1fba209f77..c8f529ac05 100644 --- a/opengl/libs/egl_impl.h +++ b/opengl/libs/egl_impl.h @@ -31,6 +31,7 @@ namespace android {  struct egl_connection_t  { +    inline egl_connection_t() : dso(0) { }      void *              dso;      gl_hooks_t *        hooks[2];      EGLint              major; diff --git a/opengl/libs/entries.in b/opengl/libs/entries.in index bbe3e236b2..61acb5f09e 100644 --- a/opengl/libs/entries.in +++ b/opengl/libs/entries.in @@ -4,13 +4,14 @@ GL_ENTRY(void, glAlphaFuncx, GLenum func, GLclampx ref)  GL_ENTRY(void, glAlphaFuncxOES, GLenum func, GLclampx ref)  GL_ENTRY(void, glAttachShader, GLuint program, GLuint shader)  GL_ENTRY(void, glBeginPerfMonitorAMD, GLuint monitor) -GL_ENTRY(void, glBindAttribLocation, GLuint program, GLuint index, const char* name) +GL_ENTRY(void, glBindAttribLocation, GLuint program, GLuint index, const GLchar* name)  GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer)  GL_ENTRY(void, glBindFramebuffer, GLenum target, GLuint framebuffer)  GL_ENTRY(void, glBindFramebufferOES, GLenum target, GLuint framebuffer)  GL_ENTRY(void, glBindRenderbuffer, GLenum target, GLuint renderbuffer)  GL_ENTRY(void, glBindRenderbufferOES, GLenum target, GLuint renderbuffer)  GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture) +GL_ENTRY(void, glBindVertexArrayOES, GLuint array)  GL_ENTRY(void, glBlendColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)  GL_ENTRY(void, glBlendEquation,  GLenum mode )  GL_ENTRY(void, glBlendEquationOES, GLenum mode) @@ -34,8 +35,10 @@ GL_ENTRY(void, glClearDepthxOES, GLclampx depth)  GL_ENTRY(void, glClearStencil, GLint s)  GL_ENTRY(void, glClientActiveTexture, GLenum texture)  GL_ENTRY(void, glClipPlanef, GLenum plane, const GLfloat *equation) +GL_ENTRY(void, glClipPlanefIMG, GLenum p, const GLfloat *eqn)  GL_ENTRY(void, glClipPlanefOES, GLenum plane, const GLfloat *equation)  GL_ENTRY(void, glClipPlanex, GLenum plane, const GLfixed *equation) +GL_ENTRY(void, glClipPlanexIMG, GLenum p, const GLfixed *eqn)  GL_ENTRY(void, glClipPlanexOES, GLenum plane, const GLfixed *equation)  GL_ENTRY(void, glColor4f, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)  GL_ENTRY(void, glColor4ub, GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) @@ -45,12 +48,14 @@ GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLbo  GL_ENTRY(void, glColorPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)  GL_ENTRY(void, glCompileShader, GLuint shader)  GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) -GL_ENTRY(void, glCompressedTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data) +GL_ENTRY(void, glCompressedTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data)  GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) -GL_ENTRY(void, glCompressedTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data) +GL_ENTRY(void, glCompressedTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data)  GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)  GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)  GL_ENTRY(void, glCopyTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glCoverageMaskNV, GLboolean mask) +GL_ENTRY(void, glCoverageOperationNV, GLenum operation)  GL_ENTRY(GLuint, glCreateProgram, void)  GL_ENTRY(GLuint, glCreateShader, GLenum type)  GL_ENTRY(void, glCullFace, GLenum mode) @@ -65,6 +70,7 @@ GL_ENTRY(void, glDeleteRenderbuffers, GLsizei n, const GLuint* renderbuffers)  GL_ENTRY(void, glDeleteRenderbuffersOES, GLsizei n, const GLuint* renderbuffers)  GL_ENTRY(void, glDeleteShader, GLuint shader)  GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *textures) +GL_ENTRY(void, glDeleteVertexArraysOES, GLsizei n, const GLuint *arrays)  GL_ENTRY(void, glDepthFunc, GLenum func)  GL_ENTRY(void, glDepthMask, GLboolean flag)  GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar) @@ -76,6 +82,7 @@ GL_ENTRY(void, glDisable, GLenum cap)  GL_ENTRY(void, glDisableClientState, GLenum array)  GL_ENTRY(void, glDisableDriverControlQCOM, GLuint driverControl)  GL_ENTRY(void, glDisableVertexAttribArray, GLuint index) +GL_ENTRY(void, glDiscardFramebufferEXT, GLenum target, GLsizei numAttachments, const GLenum *attachments)  GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count)  GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)  GL_ENTRY(void, glDrawTexfOES, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height) @@ -93,6 +100,19 @@ GL_ENTRY(void, glEnableClientState, GLenum array)  GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl)  GL_ENTRY(void, glEnableVertexAttribArray, GLuint index)  GL_ENTRY(void, glEndPerfMonitorAMD, GLuint monitor) +GL_ENTRY(void, glEndTilingQCOM, GLbitfield preserveMask) +GL_ENTRY(void, glExtGetBufferPointervQCOM, GLenum target, GLvoid **params) +GL_ENTRY(void, glExtGetBuffersQCOM, GLuint *buffers, GLint maxBuffers, GLint *numBuffers) +GL_ENTRY(void, glExtGetFramebuffersQCOM, GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers) +GL_ENTRY(void, glExtGetProgramBinarySourceQCOM, GLuint program, GLenum shadertype, GLchar *source, GLint *length) +GL_ENTRY(void, glExtGetProgramsQCOM, GLuint *programs, GLint maxPrograms, GLint *numPrograms) +GL_ENTRY(void, glExtGetRenderbuffersQCOM, GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers) +GL_ENTRY(void, glExtGetShadersQCOM, GLuint *shaders, GLint maxShaders, GLint *numShaders) +GL_ENTRY(void, glExtGetTexLevelParameterivQCOM, GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params) +GL_ENTRY(void, glExtGetTexSubImageQCOM, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels) +GL_ENTRY(void, glExtGetTexturesQCOM, GLuint *textures, GLint maxTextures, GLint *numTextures) +GL_ENTRY(GLboolean, glExtIsProgramBinaryQCOM, GLuint program) +GL_ENTRY(void, glExtTexObjectStateOverrideiQCOM, GLenum target, GLenum pname, GLint param)  GL_ENTRY(void, glFinish, void)  GL_ENTRY(void, glFinishFenceNV, GLuint fence)  GL_ENTRY(void, glFlush, void) @@ -105,6 +125,7 @@ GL_ENTRY(void, glFogxvOES, GLenum pname, const GLfixed *params)  GL_ENTRY(void, glFramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)  GL_ENTRY(void, glFramebufferRenderbufferOES, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)  GL_ENTRY(void, glFramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +GL_ENTRY(void, glFramebufferTexture2DMultisampleIMG, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)  GL_ENTRY(void, glFramebufferTexture2DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)  GL_ENTRY(void, glFramebufferTexture3DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)  GL_ENTRY(void, glFrontFace, GLenum mode) @@ -120,20 +141,21 @@ GL_ENTRY(void, glGenPerfMonitorsAMD, GLsizei n, GLuint *monitors)  GL_ENTRY(void, glGenRenderbuffers, GLsizei n, GLuint* renderbuffers)  GL_ENTRY(void, glGenRenderbuffersOES, GLsizei n, GLuint* renderbuffers)  GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures) +GL_ENTRY(void, glGenVertexArraysOES, GLsizei n, GLuint *arrays)  GL_ENTRY(void, glGenerateMipmap, GLenum target)  GL_ENTRY(void, glGenerateMipmapOES, GLenum target) -GL_ENTRY(void, glGetActiveAttrib, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) -GL_ENTRY(void, glGetActiveUniform, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) +GL_ENTRY(void, glGetActiveAttrib, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +GL_ENTRY(void, glGetActiveUniform, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)  GL_ENTRY(void, glGetAttachedShaders, GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) -GL_ENTRY(int, glGetAttribLocation, GLuint program, const char* name) +GL_ENTRY(int, glGetAttribLocation, GLuint program, const GLchar* name)  GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean *params)  GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint *params) -GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, void** params) +GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, GLvoid ** params)  GL_ENTRY(void, glGetClipPlanef, GLenum pname, GLfloat eqn[4])  GL_ENTRY(void, glGetClipPlanefOES, GLenum pname, GLfloat eqn[4])  GL_ENTRY(void, glGetClipPlanex, GLenum pname, GLfixed eqn[4])  GL_ENTRY(void, glGetClipPlanexOES, GLenum pname, GLfixed eqn[4]) -GL_ENTRY(void, glGetDriverControlStringQCOM, GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString) +GL_ENTRY(void, glGetDriverControlStringQCOM, GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString)  GL_ENTRY(void, glGetDriverControlsQCOM, GLint *num, GLsizei size, GLuint *driverControls)  GL_ENTRY(GLenum, glGetError, void)  GL_ENTRY(void, glGetFenceivNV, GLuint fence, GLenum pname, GLint *params) @@ -150,20 +172,20 @@ GL_ENTRY(void, glGetMaterialfv, GLenum face, GLenum pname, GLfloat *params)  GL_ENTRY(void, glGetMaterialxv, GLenum face, GLenum pname, GLfixed *params)  GL_ENTRY(void, glGetMaterialxvOES, GLenum face, GLenum pname, GLfixed *params)  GL_ENTRY(void, glGetPerfMonitorCounterDataAMD, GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten) -GL_ENTRY(void, glGetPerfMonitorCounterInfoAMD, GLuint group, GLuint counter, GLenum pname, void *data) -GL_ENTRY(void, glGetPerfMonitorCounterStringAMD, GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString) +GL_ENTRY(void, glGetPerfMonitorCounterInfoAMD, GLuint group, GLuint counter, GLenum pname, GLvoid *data) +GL_ENTRY(void, glGetPerfMonitorCounterStringAMD, GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString)  GL_ENTRY(void, glGetPerfMonitorCountersAMD, GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters) -GL_ENTRY(void, glGetPerfMonitorGroupStringAMD, GLuint group, GLsizei bufSize, GLsizei *length, char *groupString) +GL_ENTRY(void, glGetPerfMonitorGroupStringAMD, GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString)  GL_ENTRY(void, glGetPerfMonitorGroupsAMD, GLint *numGroups, GLsizei groupsSize, GLuint *groups) -GL_ENTRY(void, glGetPointerv, GLenum pname, void **params) -GL_ENTRY(void, glGetProgramBinaryOES, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) -GL_ENTRY(void, glGetProgramInfoLog, GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) +GL_ENTRY(void, glGetPointerv, GLenum pname, GLvoid **params) +GL_ENTRY(void, glGetProgramBinaryOES, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary) +GL_ENTRY(void, glGetProgramInfoLog, GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)  GL_ENTRY(void, glGetProgramiv, GLuint program, GLenum pname, GLint* params)  GL_ENTRY(void, glGetRenderbufferParameteriv, GLenum target, GLenum pname, GLint* params)  GL_ENTRY(void, glGetRenderbufferParameterivOES, GLenum target, GLenum pname, GLint* params) -GL_ENTRY(void, glGetShaderInfoLog, GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) +GL_ENTRY(void, glGetShaderInfoLog, GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)  GL_ENTRY(void, glGetShaderPrecisionFormat, GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) -GL_ENTRY(void, glGetShaderSource, GLuint shader, GLsizei bufsize, GLsizei* length, char* source) +GL_ENTRY(void, glGetShaderSource, GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)  GL_ENTRY(void, glGetShaderiv, GLuint shader, GLenum pname, GLint* params)  GL_ENTRY(const GLubyte *, glGetString, GLenum name)  GL_ENTRY(void, glGetTexEnvfv, GLenum env, GLenum pname, GLfloat *params) @@ -177,10 +199,10 @@ GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat *params  GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint *params)  GL_ENTRY(void, glGetTexParameterxv, GLenum target, GLenum pname, GLfixed *params)  GL_ENTRY(void, glGetTexParameterxvOES, GLenum target, GLenum pname, GLfixed *params) -GL_ENTRY(int, glGetUniformLocation, GLuint program, const char* name) +GL_ENTRY(int, glGetUniformLocation, GLuint program, const GLchar* name)  GL_ENTRY(void, glGetUniformfv, GLuint program, GLint location, GLfloat* params)  GL_ENTRY(void, glGetUniformiv, GLuint program, GLint location, GLint* params) -GL_ENTRY(void, glGetVertexAttribPointerv, GLuint index, GLenum pname, void** pointer) +GL_ENTRY(void, glGetVertexAttribPointerv, GLuint index, GLenum pname, GLvoid** pointer)  GL_ENTRY(void, glGetVertexAttribfv, GLuint index, GLenum pname, GLfloat* params)  GL_ENTRY(void, glGetVertexAttribiv, GLuint index, GLenum pname, GLint* params)  GL_ENTRY(void, glHint, GLenum target, GLenum mode) @@ -194,6 +216,7 @@ GL_ENTRY(GLboolean, glIsRenderbuffer, GLuint renderbuffer)  GL_ENTRY(GLboolean, glIsRenderbufferOES, GLuint renderbuffer)  GL_ENTRY(GLboolean, glIsShader, GLuint shader)  GL_ENTRY(GLboolean, glIsTexture, GLuint texture) +GL_ENTRY(GLboolean, glIsVertexArrayOES, GLuint array)  GL_ENTRY(void, glLightModelf, GLenum pname, GLfloat param)  GL_ENTRY(void, glLightModelfv, GLenum pname, const GLfloat *params)  GL_ENTRY(void, glLightModelx, GLenum pname, GLfixed param) @@ -228,6 +251,8 @@ GL_ENTRY(void, glMatrixMode, GLenum mode)  GL_ENTRY(void, glMultMatrixf, const GLfloat *m)  GL_ENTRY(void, glMultMatrixx, const GLfixed *m)  GL_ENTRY(void, glMultMatrixxOES, const GLfixed *m) +GL_ENTRY(void, glMultiDrawArraysEXT, GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) +GL_ENTRY(void, glMultiDrawElementsEXT, GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount)  GL_ENTRY(void, glMultiTexCoord4f, GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)  GL_ENTRY(void, glMultiTexCoord4x, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)  GL_ENTRY(void, glMultiTexCoord4xOES, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) @@ -254,12 +279,13 @@ GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)  GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units)  GL_ENTRY(void, glPolygonOffsetxOES, GLfixed factor, GLfixed units)  GL_ENTRY(void, glPopMatrix, void) -GL_ENTRY(void, glProgramBinaryOES, GLuint program, GLenum binaryFormat, const void *binary, GLint length) +GL_ENTRY(void, glProgramBinaryOES, GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length)  GL_ENTRY(void, glPushMatrix, void)  GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed mantissa[16], GLint exponent[16])  GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)  GL_ENTRY(void, glReleaseShaderCompiler, void)  GL_ENTRY(void, glRenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +GL_ENTRY(void, glRenderbufferStorageMultisampleIMG, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)  GL_ENTRY(void, glRenderbufferStorageOES, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)  GL_ENTRY(void, glRotatef, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)  GL_ENTRY(void, glRotatex, GLfixed angle, GLfixed x, GLfixed y, GLfixed z) @@ -274,8 +300,9 @@ GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height)  GL_ENTRY(void, glSelectPerfMonitorCountersAMD, GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList)  GL_ENTRY(void, glSetFenceNV, GLuint fence, GLenum condition)  GL_ENTRY(void, glShadeModel, GLenum mode) -GL_ENTRY(void, glShaderBinary, GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length) -GL_ENTRY(void, glShaderSource, GLuint shader, GLsizei count, const char** string, const GLint* length) +GL_ENTRY(void, glShaderBinary, GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) +GL_ENTRY(void, glShaderSource, GLuint shader, GLsizei count, const GLchar** string, const GLint* length) +GL_ENTRY(void, glStartTilingQCOM, GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask)  GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask)  GL_ENTRY(void, glStencilFuncSeparate, GLenum face, GLenum func, GLint ref, GLuint mask)  GL_ENTRY(void, glStencilMask, GLuint mask) @@ -298,8 +325,8 @@ GL_ENTRY(void, glTexGeniOES, GLenum coord, GLenum pname, GLint param)  GL_ENTRY(void, glTexGenivOES, GLenum coord, GLenum pname, const GLint *params)  GL_ENTRY(void, glTexGenxOES, GLenum coord, GLenum pname, GLfixed param)  GL_ENTRY(void, glTexGenxvOES, GLenum coord, GLenum pname, const GLfixed *params) -GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat,  GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) -GL_ENTRY(void, glTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels) +GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +GL_ENTRY(void, glTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels)  GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param)  GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat *params)  GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param) @@ -309,7 +336,7 @@ GL_ENTRY(void, glTexParameterxOES, GLenum target, GLenum pname, GLfixed param)  GL_ENTRY(void, glTexParameterxv, GLenum target, GLenum pname, const GLfixed *params)  GL_ENTRY(void, glTexParameterxvOES, GLenum target, GLenum pname, const GLfixed *params)  GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) -GL_ENTRY(void, glTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) +GL_ENTRY(void, glTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels)  GL_ENTRY(void, glTranslatef, GLfloat x, GLfloat y, GLfloat z)  GL_ENTRY(void, glTranslatex, GLfixed x, GLfixed y, GLfixed z)  GL_ENTRY(void, glTranslatexOES, GLfixed x, GLfixed y, GLfixed z) @@ -343,7 +370,7 @@ GL_ENTRY(void, glVertexAttrib3f, GLuint indx, GLfloat x, GLfloat y, GLfloat z)  GL_ENTRY(void, glVertexAttrib3fv, GLuint indx, const GLfloat* values)  GL_ENTRY(void, glVertexAttrib4f, GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)  GL_ENTRY(void, glVertexAttrib4fv, GLuint indx, const GLfloat* values) -GL_ENTRY(void, glVertexAttribPointer, GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr) +GL_ENTRY(void, glVertexAttribPointer, GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)  GL_ENTRY(void, glVertexPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)  GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height)  GL_ENTRY(void, glWeightPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp index 2361db5f32..f274c7c4ef 100644 --- a/opengl/tests/gl2_basic/gl2_basic.cpp +++ b/opengl/tests/gl2_basic/gl2_basic.cpp @@ -195,7 +195,6 @@ void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {      X(EGL_NATIVE_RENDERABLE),      X(EGL_NATIVE_VISUAL_ID),      X(EGL_NATIVE_VISUAL_TYPE), -    X(EGL_PRESERVED_RESOURCES),      X(EGL_SAMPLES),      X(EGL_SAMPLE_BUFFERS),      X(EGL_SURFACE_TYPE), diff --git a/opengl/tests/gl_basic/gl_basic.cpp b/opengl/tests/gl_basic/gl_basic.cpp index feb964a151..0cc8398a4a 100644 --- a/opengl/tests/gl_basic/gl_basic.cpp +++ b/opengl/tests/gl_basic/gl_basic.cpp @@ -114,7 +114,6 @@ void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {      X(EGL_NATIVE_RENDERABLE),      X(EGL_NATIVE_VISUAL_ID),      X(EGL_NATIVE_VISUAL_TYPE), -    X(EGL_PRESERVED_RESOURCES),      X(EGL_SAMPLES),      X(EGL_SAMPLE_BUFFERS),      X(EGL_SURFACE_TYPE), diff --git a/opengl/tests/gl_jni/jni/gl_code.cpp b/opengl/tests/gl_jni/jni/gl_code.cpp index 33b25ab6c7..f031c79cd3 100644 --- a/opengl/tests/gl_jni/jni/gl_code.cpp +++ b/opengl/tests/gl_jni/jni/gl_code.cpp @@ -180,4 +180,5 @@ JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobjec  JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * env, jobject obj)  {      background = 1.0f - background; -}
\ No newline at end of file +} + diff --git a/vpn/java/android/net/vpn/VpnManager.java b/vpn/java/android/net/vpn/VpnManager.java index ce522c848f..ce40b5d0c1 100644 --- a/vpn/java/android/net/vpn/VpnManager.java +++ b/vpn/java/android/net/vpn/VpnManager.java @@ -85,7 +85,8 @@ public class VpnManager {      // TODO(oam): Test VPN when EFS is enabled (will do later)...      public static String getProfilePath() { -        return Environment.getDataDirectory().getPath() + PROFILES_PATH; +        // This call will return the correct path if Encrypted FS is enabled or not. +        return Environment.getSecureDataDirectory().getPath() + PROFILES_PATH;      }      /** |