Rect SurfaceTexture::getCurrentCrop() const {
    Mutex::Autolock lock(mMutex);

    Rect outCrop = mCurrentCrop;
    if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
        int32_t newWidth = mCurrentCrop.width();
        int32_t newHeight = mCurrentCrop.height();

        if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) {
            newWidth = newHeight * mDefaultWidth / mDefaultHeight;
            ST_LOGV("too wide: newWidth = %d", newWidth);
        } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) {
            newHeight = newWidth * mDefaultHeight / mDefaultWidth;
            ST_LOGV("too tall: newHeight = %d", newHeight);
        }

        // The crop is too wide
        if (newWidth < mCurrentCrop.width()) {
            int32_t dw = (newWidth - mCurrentCrop.width())/2;
            outCrop.left -=dw;
            outCrop.right += dw;
        // The crop is too tall
        } else if (newHeight < mCurrentCrop.height()) {
            int32_t dh = (newHeight - mCurrentCrop.height())/2;
            outCrop.top -= dh;
            outCrop.bottom += dh;
        }

        ST_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
            outCrop.left, outCrop.top,
            outCrop.right,outCrop.bottom);
    }

    return outCrop;
}
void SurfaceTexture::freeBufferLocked(int slotIndex) {
    ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
    if (slotIndex == mCurrentTexture) {
        mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
    }
    EGLImageKHR img = mEglSlots[slotIndex].mEglImage;
    if (img != EGL_NO_IMAGE_KHR) {
        ST_LOGV("destroying EGLImage dpy=%p img=%p", mEglDisplay, img);
        eglDestroyImageKHR(mEglDisplay, img);
    }
    mEglSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
    ConsumerBase::freeBufferLocked(slotIndex);
}
SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
        GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) :
    mCurrentTransform(0),
    mCurrentTimestamp(0),
    mFilteringEnabled(true),
    mTexName(tex),
#ifdef USE_FENCE_SYNC
    mUseFenceSync(useFenceSync),
#else
    mUseFenceSync(false),
#endif
    mTexTarget(texTarget),
    mEglDisplay(EGL_NO_DISPLAY),
    mEglContext(EGL_NO_CONTEXT),
    mAbandoned(false),
    mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
    mAttached(true)
{
    // Choose a name using the PID and a process-unique ID.
    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
    ST_LOGV("SurfaceTexture");
    if (bufferQueue == 0) {
        ST_LOGV("Creating a new BufferQueue");
        mBufferQueue = new BufferQueue(allowSynchronousMode);
    }
    else {
        mBufferQueue = bufferQueue;
    }

    memcpy(mCurrentTransformMatrix, mtxIdentity,
            sizeof(mCurrentTransformMatrix));

    // Note that we can't create an sp<...>(this) in a ctor that will not keep a
    // reference once the ctor ends, as that would cause the refcount of 'this'
    // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>
    // that's what we create.
    wp<BufferQueue::ConsumerListener> listener;
    sp<BufferQueue::ConsumerListener> proxy;
    listener = static_cast<BufferQueue::ConsumerListener*>(this);
    proxy = new BufferQueue::ProxyConsumerListener(listener);

    status_t err = mBufferQueue->consumerConnect(proxy);
    if (err != NO_ERROR) {
        ST_LOGE("SurfaceTexture: error connecting to BufferQueue: %s (%d)",
                strerror(-err), err);
    } else {
        mBufferQueue->setConsumerName(mName);
        mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
    }
}
void SurfaceTexture::onFrameAvailable() {
    ST_LOGV("onFrameAvailable");

    sp<FrameAvailableListener> listener;
    { // scope for the lock
        Mutex::Autolock lock(mMutex);
        listener = mFrameAvailableListener;
    }

    if (listener != NULL) {
        ST_LOGV("actually calling onFrameAvailable");
        listener->onFrameAvailable();
    }
}
Ejemplo n.º 5
0
status_t GLConsumer::detachFromContext() {
    ATRACE_CALL();
#ifndef MTK_DEFAULT_AOSP
    ST_LOGI("detachFromContext");
#else
    ST_LOGV("detachFromContext");
#endif
    Mutex::Autolock lock(mMutex);

    if (mAbandoned) {
        ST_LOGE("detachFromContext: abandoned GLConsumer");
        return NO_INIT;
    }

    if (!mAttached) {
        ST_LOGE("detachFromContext: GLConsumer is not attached to a "
                "context");
        return INVALID_OPERATION;
    }

    EGLDisplay dpy = eglGetCurrentDisplay();
    EGLContext ctx = eglGetCurrentContext();

    if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) {
        ST_LOGE("detachFromContext: invalid current EGLDisplay");
        return INVALID_OPERATION;
    }

    if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) {
        ST_LOGE("detachFromContext: invalid current EGLContext");
        return INVALID_OPERATION;
    }

    if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) {
        status_t err = syncForReleaseLocked(dpy);
        if (err != OK) {
            return err;
        }

        glDeleteTextures(1, &mTexName);
    }

    // Because we're giving up the EGLDisplay we need to free all the EGLImages
    // that are associated with it.  They'll be recreated when the
    // GLConsumer gets attached to a new OpenGL ES context (and thus gets a
    // new EGLDisplay).
    for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
        EGLImageKHR img = mEglSlots[i].mEglImage;
        if (img != EGL_NO_IMAGE_KHR) {
            eglDestroyImageKHR(mEglDisplay, img);
            mEglSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
        }
    }

    mEglDisplay = EGL_NO_DISPLAY;
    mEglContext = EGL_NO_CONTEXT;
    mAttached = false;

    return OK;
}
Ejemplo n.º 6
0
GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
        uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
    ConsumerBase(bq, isControlledByApp),
    mCurrentTransform(0),
    mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
    mCurrentFence(Fence::NO_FENCE),
    mCurrentTimestamp(0),
    mCurrentFrameNumber(0),
    mDefaultWidth(1),
    mDefaultHeight(1),
    mFilteringEnabled(true),
    mTexName(tex),
    mUseFenceSync(useFenceSync),
    mTexTarget(texTarget),
    mEglDisplay(EGL_NO_DISPLAY),
    mEglContext(EGL_NO_CONTEXT),
    mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
    mAttached(true)
{
#ifndef MTK_DEFAULT_AOSP
    ST_LOGI("GLConsumer");
#else
    ST_LOGV("GLConsumer");
#endif

    memcpy(mCurrentTransformMatrix, mtxIdentity,
            sizeof(mCurrentTransformMatrix));

    mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
}
Ejemplo n.º 7
0
status_t GLConsumer::bindUnslottedBufferLocked(EGLDisplay dpy) {
    ST_LOGV("bindUnslottedBuffer ct=%d ctb=%p",
            mCurrentTexture, mCurrentTextureBuf.get());

    // Create a temporary EGLImageKHR.
    Rect crop;
    EGLImageKHR image = createImage(dpy, mCurrentTextureBuf, mCurrentCrop);
    if (image == EGL_NO_IMAGE_KHR) {
        return UNKNOWN_ERROR;
    }

    // Attach the current buffer to the GL texture.
    glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);

    GLint error;
    status_t err = OK;
    while ((error = glGetError()) != GL_NO_ERROR) {
        ST_LOGE("bindUnslottedBuffer: error binding external texture image %p "
                "(slot %d): %#04x", image, mCurrentTexture, error);
        err = UNKNOWN_ERROR;
    }

    // We destroy the EGLImageKHR here because the current buffer may no
    // longer be associated with one of the buffer slots, so we have
    // nowhere to to store it.  If the buffer is still associated with a
    // slot then another EGLImageKHR will be created next time that buffer
    // gets acquired in updateTexImage.
    eglDestroyImageKHR(dpy, image);

    return err;
}
Ejemplo n.º 8
0
status_t SurfaceTexture::connect(int api,
        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
    ST_LOGV("connect: api=%d", api);
    Mutex::Autolock lock(mMutex);

    if (mAbandoned) {
        ST_LOGE("connect: SurfaceTexture has been abandoned!");
        return NO_INIT;
    }

    int err = NO_ERROR;
    switch (api) {
        case NATIVE_WINDOW_API_EGL:
        case NATIVE_WINDOW_API_CPU:
        case NATIVE_WINDOW_API_MEDIA:
        case NATIVE_WINDOW_API_CAMERA:
            if (mConnectedApi != NO_CONNECTED_API) {
                ST_LOGE("connect: already connected (cur=%d, req=%d)",
                        mConnectedApi, api);
                err = -EINVAL;
            } else {
                mConnectedApi = api;
                *outWidth = mDefaultWidth;
                *outHeight = mDefaultHeight;
                *outTransform = 0;
            }
            break;
        default:
            err = -EINVAL;
            break;
    }
    return err;
}
GLConsumer::GLConsumer(GLuint tex, bool allowSynchronousMode,
                       GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) :
    ConsumerBase(bufferQueue == 0 ? new BufferQueue(allowSynchronousMode) : bufferQueue),
    mCurrentTransform(0),
    mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
    mCurrentFence(Fence::NO_FENCE),
    mCurrentTimestamp(0),
    mDefaultWidth(1),
    mDefaultHeight(1),
    mFilteringEnabled(true),
    mTexName(tex),
    mUseFenceSync(useFenceSync),
    mTexTarget(texTarget),
    mEglDisplay(EGL_NO_DISPLAY),
    mEglContext(EGL_NO_CONTEXT),
    mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
    mAttached(true)
{
    ST_LOGV("GLConsumer");

    memcpy(mCurrentTransformMatrix, mtxIdentity,
           sizeof(mCurrentTransformMatrix));

    mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
}
Ejemplo n.º 10
0
BufferQueue::BufferQueue(  bool allowSynchronousMode, int bufferCount ) :
    mDefaultWidth(1),
    mDefaultHeight(1),
    mPixelFormat(PIXEL_FORMAT_RGBA_8888),
    mMinUndequeuedBuffers(bufferCount),
    mMinAsyncBufferSlots(bufferCount + 1),
    mMinSyncBufferSlots(bufferCount),
    mBufferCount(mMinAsyncBufferSlots),
    mClientBufferCount(0),
    mServerBufferCount(mMinAsyncBufferSlots),
    mSynchronousMode(false),
    mAllowSynchronousMode(allowSynchronousMode),
    mConnectedApi(NO_CONNECTED_API),
    mAbandoned(false),
    mFrameCounter(0),
    mBufferHasBeenQueued(false),
    mDefaultBufferFormat(0),
    mConsumerUsageBits(0),
    mTransformHint(0)
{
    // Choose a name using the PID and a process-unique ID.
    mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());

    ST_LOGV("BufferQueue");
    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
    mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
    if (mGraphicBufferAlloc == 0) {
        ST_LOGE("createGraphicBufferAlloc() failed in BufferQueue()");
    }
}
Ejemplo n.º 11
0
status_t BufferQueue::setSynchronousMode(bool enabled) {
    ATRACE_CALL();
    ST_LOGV("setSynchronousMode: enabled=%d", enabled);
    Mutex::Autolock lock(mMutex);

    if (mAbandoned) {
        ST_LOGE("setSynchronousMode: SurfaceTexture has been abandoned!");
        return NO_INIT;
    }

    status_t err = OK;
    if (!mAllowSynchronousMode && enabled)
        return err;

    if (!enabled) {
        // going to asynchronous mode, drain the queue
        err = drainQueueLocked();
        if (err != NO_ERROR)
            return err;
    }

    if (mSynchronousMode != enabled) {
        // - if we're going to asynchronous mode, the queue is guaranteed to be
        // empty here
        // - if the client set the number of buffers, we're guaranteed that
        // we have at least 3 (because we don't allow less)
        mSynchronousMode = enabled;
        mDequeueCondition.broadcast();
    }
    return err;
}
Ejemplo n.º 12
0
status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
        EGLSyncKHR fence) {
    ATRACE_CALL();
    ATRACE_BUFFER_INDEX(buf);

    Mutex::Autolock _l(mMutex);

    if (buf == INVALID_BUFFER_SLOT) {
        return -EINVAL;
    }

    mSlots[buf].mEglDisplay = display;
    mSlots[buf].mFence = fence;

    // The buffer can now only be released if its in the acquired state
    if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
        mSlots[buf].mBufferState = BufferSlot::FREE;
    } else if (mSlots[buf].mNeedsCleanupOnRelease) {
        ST_LOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState);
        mSlots[buf].mNeedsCleanupOnRelease = false;
        return STALE_BUFFER_SLOT;
    } else {
        ST_LOGE("attempted to release buf %d but its state was %d", buf, mSlots[buf].mBufferState);
        return -EINVAL;
    }

    mDequeueCondition.broadcast();
    return OK;
}
BufferQueue::BufferQueue(bool allowSynchronousMode,
        const sp<IGraphicBufferAlloc>& allocator) :
    mDefaultWidth(1),
    mDefaultHeight(1),
    mMaxAcquiredBufferCount(1),
    mDefaultMaxBufferCount(2),
    mOverrideMaxBufferCount(0),
    mSynchronousMode(false),
    mAllowSynchronousMode(allowSynchronousMode),
    mConnectedApi(NO_CONNECTED_API),
    mAbandoned(false),
    mFrameCounter(0),
    mBufferHasBeenQueued(false),
    mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
    mConsumerUsageBits(0),
    mTransformHint(0)
{
    // Choose a name using the PID and a process-unique ID.
    mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());

    ST_LOGV("BufferQueue");
    if (allocator == NULL) {
        sp<ISurfaceComposer> composer(ComposerService::getComposerService());
        mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
        if (mGraphicBufferAlloc == 0) {
            ST_LOGE("createGraphicBufferAlloc() failed in BufferQueue()");
        }
    } else {
        mGraphicBufferAlloc = allocator;
    }
}
void BufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) {
    ATRACE_CALL();
    ST_LOGV("cancelBuffer: slot=%d", buf);
    Mutex::Autolock lock(mMutex);

    if (mAbandoned) {
        ST_LOGW("cancelBuffer: BufferQueue has been abandoned!");
        return;
    }

    int maxBufferCount = getMaxBufferCountLocked();
    if (buf < 0 || buf >= maxBufferCount) {
        ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
                maxBufferCount, buf);
        return;
    } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
        ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
                buf, mSlots[buf].mBufferState);
        return;
    } else if (fence == NULL) {
        ST_LOGE("cancelBuffer: fence is NULL");
        return;
    }
    mSlots[buf].mBufferState = BufferSlot::FREE;
    mSlots[buf].mFrameNumber = 0;
    mSlots[buf].mFence = fence;
    mDequeueCondition.broadcast();
}
status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
    ATRACE_CALL();
    ST_LOGV("requestBuffer: slot=%d", slot);
    Mutex::Autolock lock(mMutex);
    if (mAbandoned) {
        ST_LOGE("requestBuffer: BufferQueue has been abandoned!");
        return NO_INIT;
    }
    int maxBufferCount = getMaxBufferCountLocked();
    if (slot < 0 || maxBufferCount <= slot) {
        ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
                maxBufferCount, slot);
        return BAD_VALUE;
    } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
        // XXX: I vaguely recall there was some reason this can be valid, but
        // for the life of me I can't recall under what circumstances that's
        // the case.
        ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)",
                slot, mSlots[slot].mBufferState);
        return BAD_VALUE;
    }
    mSlots[slot].mRequestBufferCalled = true;
    *buf = mSlots[slot].mGraphicBuffer;
    return NO_ERROR;
}
SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
        GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) :
    ConsumerBase(bufferQueue == 0 ? new BufferQueue(allowSynchronousMode) : bufferQueue),
    mCurrentTransform(0),
    mCurrentTimestamp(0),
    mFilteringEnabled(true),
    mTexName(tex),
#ifdef USE_FENCE_SYNC
    mUseFenceSync(useFenceSync),
#else
    mUseFenceSync(false),
#endif
    mTexTarget(texTarget),
    mEglDisplay(EGL_NO_DISPLAY),
    mEglContext(EGL_NO_CONTEXT),
    mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
    mAttached(true)
{
    ST_LOGV("SurfaceTexture");

    memcpy(mCurrentTransformMatrix, mtxIdentity,
            sizeof(mCurrentTransformMatrix));

    mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
}
Ejemplo n.º 17
0
status_t GLConsumer::updateTexImage() {
    ATRACE_CALL();
    ST_LOGV("updateTexImage");
    Mutex::Autolock lock(mMutex);

    if (mAbandoned) {
        ST_LOGE("updateTexImage: GLConsumer is abandoned!");
        return NO_INIT;
    }

    // Make sure the EGL state is the same as in previous calls.
    status_t err = checkAndUpdateEglStateLocked();
    if (err != NO_ERROR) {
        return err;
    }

    BufferQueue::BufferItem item;

    // Acquire the next buffer.
    // In asynchronous mode the list is guaranteed to be one buffer
    // deep, while in synchronous mode we use the oldest buffer.
    err = acquireBufferLocked(&item, 0);
    if (err != NO_ERROR) {
        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
            // We always bind the texture even if we don't update its contents.
            ST_LOGV("updateTexImage: no buffers were available");
            glBindTexture(mTexTarget, mTexName);
            err = NO_ERROR;
        } else {
            ST_LOGE("updateTexImage: acquire failed: %s (%d)",
                strerror(-err), err);
        }
        return err;
    }

    // Release the previous buffer.
    err = updateAndReleaseLocked(item);
    if (err != NO_ERROR) {
        // We always bind the texture.
        glBindTexture(mTexTarget, mTexName);
        return err;
    }

    // Bind the new buffer to the GL texture, and wait until it's ready.
    return bindTextureImageLocked();
}
Ejemplo n.º 18
0
void GLConsumer::freeBufferLocked(int slotIndex) {
    ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
    if (slotIndex == mCurrentTexture) {
        mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
    }
    EGLImageKHR img = mEglSlots[slotIndex].mEglImage;
    if (img != EGL_NO_IMAGE_KHR) {
#ifndef MTK_DEFAULT_AOSP
        ST_LOGI("destroying EGLImage dpy=%p img=%p", mEglDisplay, img);
#else
        ST_LOGV("destroying EGLImage dpy=%p img=%p", mEglDisplay, img);
#endif
        eglDestroyImageKHR(mEglDisplay, img);
    }
    mEglSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
    ConsumerBase::freeBufferLocked(slotIndex);
}
status_t BufferQueue::setBufferCount(int bufferCount) {
    ST_LOGV("setBufferCount: count=%d", bufferCount);

    sp<ConsumerListener> listener;
    {
        Mutex::Autolock lock(mMutex);

        if (mAbandoned) {
            ST_LOGE("setBufferCount: BufferQueue has been abandoned!");
            return NO_INIT;
        }
        if (bufferCount > NUM_BUFFER_SLOTS) {
            ST_LOGE("setBufferCount: bufferCount too large (max %d)",
                    NUM_BUFFER_SLOTS);
            return BAD_VALUE;
        }

        // Error out if the user has dequeued buffers
        int maxBufferCount = getMaxBufferCountLocked();
        for (int i=0 ; i<maxBufferCount; i++) {
            if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
                ST_LOGE("setBufferCount: client owns some buffers");
                return -EINVAL;
            }
        }

        const int minBufferSlots = getMinMaxBufferCountLocked();
        if (bufferCount == 0) {
            mOverrideMaxBufferCount = 0;
            mDequeueCondition.broadcast();
            return NO_ERROR;
        }

        if (bufferCount < minBufferSlots) {
            ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
                    "minimum (%d)", bufferCount, minBufferSlots);
            return BAD_VALUE;
        }

        // here we're guaranteed that the client doesn't have dequeued buffers
        // and will release all of its buffer references.
        //
        // XXX: Should this use drainQueueAndFreeBuffersLocked instead?
        freeAllBuffersLocked();
        mOverrideMaxBufferCount = bufferCount;
        mBufferHasBeenQueued = false;
        mDequeueCondition.broadcast();
        listener = mConsumerListener;
    } // scope for lock

    if (listener != NULL) {
        listener->onBuffersReleased();
    }

    return NO_ERROR;
}
Ejemplo n.º 20
0
status_t BufferQueue::setBufferCount(int bufferCount) {
    ST_LOGV("setBufferCount: count=%d", bufferCount);

    sp<ConsumerListener> listener;
    {
        Mutex::Autolock lock(mMutex);

        if (mAbandoned) {
            ST_LOGE("setBufferCount: SurfaceTexture has been abandoned!");
            return NO_INIT;
        }
        if (bufferCount > NUM_BUFFER_SLOTS) {
            ST_LOGE("setBufferCount: bufferCount larger than slots available");
            return BAD_VALUE;
        }

        // Error out if the user has dequeued buffers
        for (int i=0 ; i<mBufferCount ; i++) {
            if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
                ST_LOGE("setBufferCount: client owns some buffers");
                return -EINVAL;
            }
        }

        const int minBufferSlots = mSynchronousMode ?
            mMinSyncBufferSlots : mMinAsyncBufferSlots;
        if (bufferCount == 0) {
            mClientBufferCount = 0;
            bufferCount = (mServerBufferCount >= minBufferSlots) ?
                    mServerBufferCount : minBufferSlots;
            return setBufferCountServerLocked(bufferCount);
        }

        if (bufferCount < minBufferSlots) {
            ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
                    "minimum (%d)", bufferCount, minBufferSlots);
            return BAD_VALUE;
        }

        // here we're guaranteed that the client doesn't have dequeued buffers
        // and will release all of its buffer references.
        freeAllBuffersLocked();
        mBufferCount = bufferCount;
        mClientBufferCount = bufferCount;
        mBufferHasBeenQueued = false;
        mQueue.clear();
        mDequeueCondition.broadcast();
        listener = mConsumerListener;
    } // scope for lock

    if (listener != NULL) {
        listener->onBuffersReleased();
    }

    return OK;
}
Ejemplo n.º 21
0
status_t SurfaceTexture::setTransform(uint32_t transform) {
    ST_LOGV("setTransform: xform=%#x", transform);
    Mutex::Autolock lock(mMutex);
    if (mAbandoned) {
        ST_LOGE("setTransform: SurfaceTexture has been abandoned!");
        return NO_INIT;
    }
    mNextTransform = transform;
    return OK;
}
Ejemplo n.º 22
0
status_t BufferQueue::getReleasedBuffers(uint32_t* slotMask) {
    ST_LOGV("getReleasedBuffers");
    Mutex::Autolock lock(mMutex);

    if (mAbandoned) {
        ST_LOGE("getReleasedBuffers: BufferQueue has been abandoned!");
        return NO_INIT;
    }

    uint32_t mask = 0;
    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
        if (!mSlots[i].mAcquireCalled) {
            mask |= 1 << i;
        }
    }
    *slotMask = mask;

    ST_LOGV("getReleasedBuffers: returning mask %#x", mask);
    return NO_ERROR;
}
Ejemplo n.º 23
0
status_t GLConsumer::attachToContext(uint32_t tex) {
    ATRACE_CALL();
#ifndef MTK_DEFAULT_AOSP
    ST_LOGI("attachToContext");
#else
    ST_LOGV("attachToContext");
#endif
    Mutex::Autolock lock(mMutex);

    if (mAbandoned) {
        ST_LOGE("attachToContext: abandoned GLConsumer");
        return NO_INIT;
    }

    if (mAttached) {
        ST_LOGE("attachToContext: GLConsumer is already attached to a "
                "context");
        return INVALID_OPERATION;
    }

    EGLDisplay dpy = eglGetCurrentDisplay();
    EGLContext ctx = eglGetCurrentContext();

    if (dpy == EGL_NO_DISPLAY) {
        ST_LOGE("attachToContext: invalid current EGLDisplay");
        return INVALID_OPERATION;
    }

    if (ctx == EGL_NO_CONTEXT) {
        ST_LOGE("attachToContext: invalid current EGLContext");
        return INVALID_OPERATION;
    }

    // We need to bind the texture regardless of whether there's a current
    // buffer.
    glBindTexture(mTexTarget, GLuint(tex));

    if (mCurrentTextureBuf != NULL) {
        // The EGLImageKHR that was associated with the slot was destroyed when
        // the GLConsumer was detached from the old context, so we need to
        // recreate it here.
        status_t err = bindUnslottedBufferLocked(dpy);
        if (err != NO_ERROR) {
            return err;
        }
    }

    mEglDisplay = dpy;
    mEglContext = ctx;
    mTexName = tex;
    mAttached = true;

    return OK;
}
Ejemplo n.º 24
0
status_t SurfaceTexture::setCrop(const Rect& crop) {
    ST_LOGV("setCrop: crop=[%d,%d,%d,%d]", crop.left, crop.top, crop.right,
            crop.bottom);

    Mutex::Autolock lock(mMutex);
    if (mAbandoned) {
        ST_LOGE("setCrop: SurfaceTexture has been abandoned!");
        return NO_INIT;
    }
    mNextCrop = crop;
    return OK;
}
Ejemplo n.º 25
0
status_t BufferQueue::consumerConnect(const sp<ConsumerListener>& consumerListener) {
    ST_LOGV("consumerConnect");
    Mutex::Autolock lock(mMutex);

    if (mAbandoned) {
        ST_LOGE("consumerConnect: BufferQueue has been abandoned!");
        return NO_INIT;
    }

    mConsumerListener = consumerListener;

    return OK;
}
Ejemplo n.º 26
0
status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h)
{
    ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
    if (!w || !h) {
        ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
                w, h);
        return BAD_VALUE;
    }

    Mutex::Autolock lock(mMutex);
    mDefaultWidth = w;
    mDefaultHeight = h;
    return OK;
}
Ejemplo n.º 27
0
status_t BufferQueue::consumerDisconnect() {
    ST_LOGV("consumerDisconnect");
    Mutex::Autolock lock(mMutex);

    if (mConsumerListener == NULL) {
        ST_LOGE("consumerDisconnect: No consumer is connected!");
        return -EINVAL;
    }

    mAbandoned = true;
    mConsumerListener = NULL;
    mQueue.clear();
    freeAllBuffersLocked();
    mDequeueCondition.broadcast();
    return OK;
}
Ejemplo n.º 28
0
status_t SurfaceTexture::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
    ST_LOGV("requestBuffer: slot=%d", slot);
    Mutex::Autolock lock(mMutex);
    if (mAbandoned) {
        ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
        return NO_INIT;
    }
    if (slot < 0 || mBufferCount <= slot) {
        ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
                mBufferCount, slot);
        return BAD_VALUE;
    }
    mSlots[slot].mRequestBufferCalled = true;
    *buf = mSlots[slot].mGraphicBuffer;
    return NO_ERROR;
}
Ejemplo n.º 29
0
status_t SurfaceTexture::setScalingMode(int mode) {
    ST_LOGV("setScalingMode: mode=%d", mode);

    switch (mode) {
        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
            break;
        default:
            ST_LOGE("unknown scaling mode: %d", mode);
            return BAD_VALUE;
    }

    Mutex::Autolock lock(mMutex);
    mNextScalingMode = mode;
    return OK;
}
Ejemplo n.º 30
0
status_t SurfaceTexture::performQcomOperation(int operation, int arg1, int arg2, int arg3)
{
     ST_LOGV("SurfaceTexture::performQcomOperation operation=%d", operation);

     switch(operation) {
        case NATIVE_WINDOW_SET_BUFFERS_SIZE:
            mReqSize = arg1;
            break;
        case NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY:
            mNextBufferInfo.width = arg1;
            mNextBufferInfo.height = arg2;
            mNextBufferInfo.format = arg3;
            break;
        default: return BAD_VALUE;
     };
     return OK;
}