michael@0: /* michael@0: * Copyright (C) 2010 The Android Open Source Project michael@0: * Copyright (C) 2012-2013 Mozilla Foundation michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: michael@0: #include "base/basictypes.h" michael@0: #include "mozilla/layers/GrallocTextureClient.h" michael@0: #include "mozilla/layers/ImageBridgeChild.h" michael@0: #include "mozilla/layers/ShadowLayers.h" michael@0: #include "mozilla/layers/ShadowLayerUtilsGralloc.h" michael@0: #include "GonkNativeWindow.h" michael@0: #include "nsDebug.h" michael@0: michael@0: /** michael@0: * DOM_CAMERA_LOGI() is enabled in debug builds, and turned on by setting michael@0: * NSPR_LOG_MODULES=Camera:N environment variable, where N >= 3. michael@0: * michael@0: * CNW_LOGE() is always enabled. michael@0: */ michael@0: #define CNW_LOGD(...) DOM_CAMERA_LOGI(__VA_ARGS__) michael@0: #define CNW_LOGE(...) {(void)printf_stderr(__VA_ARGS__);} michael@0: michael@0: using namespace android; michael@0: using namespace mozilla; michael@0: using namespace mozilla::gfx; michael@0: using namespace mozilla::layers; michael@0: michael@0: class nsProxyReleaseTask : public CancelableTask michael@0: { michael@0: public: michael@0: nsProxyReleaseTask(TextureClient* aClient) michael@0: : mTextureClient(aClient) { michael@0: } michael@0: michael@0: virtual void Run() MOZ_OVERRIDE michael@0: { michael@0: mTextureClient = nullptr; michael@0: } michael@0: michael@0: virtual void Cancel() MOZ_OVERRIDE {} michael@0: michael@0: private: michael@0: mozilla::RefPtr mTextureClient; michael@0: }; michael@0: michael@0: GonkNativeWindow::GonkNativeWindow() : michael@0: mAbandoned(false), michael@0: mDefaultWidth(1), michael@0: mDefaultHeight(1), michael@0: mPixelFormat(PIXEL_FORMAT_RGBA_8888), michael@0: mBufferCount(MIN_BUFFER_SLOTS + 1), michael@0: mConnectedApi(NO_CONNECTED_API), michael@0: mFrameCounter(0), michael@0: mNewFrameCallback(nullptr) { michael@0: } michael@0: michael@0: GonkNativeWindow::~GonkNativeWindow() { michael@0: freeAllBuffersLocked(); michael@0: } michael@0: michael@0: void GonkNativeWindow::abandon() michael@0: { michael@0: CNW_LOGD("abandon"); michael@0: Mutex::Autolock lock(mMutex); michael@0: mQueue.clear(); michael@0: mAbandoned = true; michael@0: freeAllBuffersLocked(); michael@0: mDequeueCondition.signal(); michael@0: } michael@0: michael@0: void GonkNativeWindow::freeAllBuffersLocked() michael@0: { michael@0: CNW_LOGD("freeAllBuffersLocked"); michael@0: michael@0: for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) { michael@0: if (mSlots[i].mGraphicBuffer != NULL) { michael@0: if (mSlots[i].mTextureClient) { michael@0: mSlots[i].mTextureClient->ClearRecycleCallback(); michael@0: // release TextureClient in ImageBridge thread michael@0: nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[i].mTextureClient); michael@0: mSlots[i].mTextureClient = NULL; michael@0: ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task); michael@0: } michael@0: mSlots[i].mGraphicBuffer = NULL; michael@0: mSlots[i].mBufferState = BufferSlot::FREE; michael@0: mSlots[i].mFrameNumber = 0; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void GonkNativeWindow::clearRenderingStateBuffersLocked() michael@0: { michael@0: CNW_LOGD("clearRenderingStateBuffersLocked"); michael@0: michael@0: for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) { michael@0: if (mSlots[i].mGraphicBuffer != NULL) { michael@0: // Clear RENDERING state buffer michael@0: if (mSlots[i].mBufferState == BufferSlot::RENDERING) { michael@0: if (mSlots[i].mTextureClient) { michael@0: mSlots[i].mTextureClient->ClearRecycleCallback(); michael@0: // release TextureClient in ImageBridge thread michael@0: nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[i].mTextureClient); michael@0: mSlots[i].mTextureClient = NULL; michael@0: ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task); michael@0: } michael@0: mSlots[i].mGraphicBuffer = NULL; michael@0: mSlots[i].mBufferState = BufferSlot::FREE; michael@0: mSlots[i].mFrameNumber = 0; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: status_t GonkNativeWindow::setBufferCount(int bufferCount) michael@0: { michael@0: CNW_LOGD("setBufferCount: count=%d", bufferCount); michael@0: Mutex::Autolock lock(mMutex); michael@0: michael@0: if (mAbandoned) { michael@0: CNW_LOGE("setBufferCount: GonkNativeWindow has been abandoned!"); michael@0: return NO_INIT; michael@0: } michael@0: michael@0: if (bufferCount > NUM_BUFFER_SLOTS) { michael@0: CNW_LOGE("setBufferCount: bufferCount larger than slots available"); michael@0: return BAD_VALUE; michael@0: } michael@0: michael@0: if (bufferCount < MIN_BUFFER_SLOTS) { michael@0: CNW_LOGE("setBufferCount: requested buffer count (%d) is less than " michael@0: "minimum (%d)", bufferCount, MIN_BUFFER_SLOTS); michael@0: return BAD_VALUE; michael@0: } michael@0: michael@0: // Error out if the user has dequeued buffers. michael@0: for (int i=0 ; i= mBufferCount) { michael@0: mBufferCount = bufferCount; michael@0: //clear only buffers in RENDERING state. michael@0: clearRenderingStateBuffersLocked(); michael@0: mQueue.clear(); michael@0: mDequeueCondition.signal(); michael@0: return OK; michael@0: } michael@0: michael@0: // here we're guaranteed that the client doesn't have dequeued buffers michael@0: // and will release all of its buffer references. michael@0: freeAllBuffersLocked(); michael@0: mBufferCount = bufferCount; michael@0: mQueue.clear(); michael@0: mDequeueCondition.signal(); michael@0: return OK; michael@0: } michael@0: michael@0: status_t GonkNativeWindow::setDefaultBufferSize(uint32_t w, uint32_t h) michael@0: { michael@0: CNW_LOGD("setDefaultBufferSize: w=%d, h=%d", w, h); michael@0: if (!w || !h) { michael@0: CNW_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", michael@0: w, h); michael@0: return BAD_VALUE; michael@0: } michael@0: michael@0: Mutex::Autolock lock(mMutex); michael@0: mDefaultWidth = w; michael@0: mDefaultHeight = h; michael@0: return OK; michael@0: } michael@0: michael@0: status_t GonkNativeWindow::requestBuffer(int slot, sp* buf) michael@0: { michael@0: CNW_LOGD("requestBuffer: slot=%d", slot); michael@0: Mutex::Autolock lock(mMutex); michael@0: if (mAbandoned) { michael@0: CNW_LOGE("requestBuffer: GonkNativeWindow has been abandoned!"); michael@0: return NO_INIT; michael@0: } michael@0: if (slot < 0 || mBufferCount <= slot) { michael@0: CNW_LOGE("requestBuffer: slot index out of range [0, %d]: %d", michael@0: mBufferCount, slot); michael@0: return BAD_VALUE; michael@0: } michael@0: mSlots[slot].mRequestBufferCalled = true; michael@0: *buf = mSlots[slot].mGraphicBuffer; michael@0: return NO_ERROR; michael@0: } michael@0: michael@0: status_t GonkNativeWindow::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, michael@0: uint32_t format, uint32_t usage) michael@0: { michael@0: if ((w && !h) || (!w && h)) { michael@0: CNW_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); michael@0: return BAD_VALUE; michael@0: } michael@0: michael@0: status_t returnFlags(OK); michael@0: bool updateFormat = false; michael@0: bool alloc = false; michael@0: int buf = INVALID_BUFFER_SLOT; michael@0: michael@0: { michael@0: Mutex::Autolock lock(mMutex); michael@0: michael@0: int found = -1; michael@0: int dequeuedCount = 0; michael@0: int renderingCount = 0; michael@0: bool tryAgain = true; michael@0: michael@0: CNW_LOGD("dequeueBuffer: E"); michael@0: while (tryAgain) { michael@0: if (mAbandoned) { michael@0: CNW_LOGE("dequeueBuffer: GonkNativeWindow has been abandoned!"); michael@0: return NO_INIT; michael@0: } michael@0: // look for a free buffer to give to the client michael@0: found = INVALID_BUFFER_SLOT; michael@0: dequeuedCount = 0; michael@0: renderingCount = 0; michael@0: for (int i = 0; i < mBufferCount; i++) { michael@0: const int state = mSlots[i].mBufferState; michael@0: switch (state) { michael@0: case BufferSlot::DEQUEUED: michael@0: CNW_LOGD("dequeueBuffer: slot %d is DEQUEUED\n", i); michael@0: dequeuedCount++; michael@0: break; michael@0: michael@0: case BufferSlot::RENDERING: michael@0: CNW_LOGD("dequeueBuffer: slot %d is RENDERING\n", i); michael@0: renderingCount++; michael@0: break; michael@0: michael@0: case BufferSlot::FREE: michael@0: CNW_LOGD("dequeueBuffer: slot %d is FREE\n", i); michael@0: /* We return the oldest of the free buffers to avoid michael@0: * stalling the producer if possible. This is because michael@0: * the consumer may still have pending reads of the michael@0: * buffers in flight. michael@0: */ michael@0: if (found < 0 || michael@0: mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) { michael@0: found = i; michael@0: } michael@0: break; michael@0: michael@0: default: michael@0: CNW_LOGD("dequeueBuffer: slot %d is %d\n", i, state); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: // See whether a buffer has been in RENDERING state since the last michael@0: // setBufferCount so we know whether to perform the michael@0: // MIN_UNDEQUEUED_BUFFERS check below. michael@0: if (renderingCount > 0) { michael@0: // make sure the client is not trying to dequeue more buffers michael@0: // than allowed. michael@0: const int avail = mBufferCount - (dequeuedCount + 1); michael@0: if (avail < MIN_UNDEQUEUED_BUFFERS) { michael@0: CNW_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded " michael@0: "(dequeued=%d)", michael@0: MIN_UNDEQUEUED_BUFFERS, michael@0: dequeuedCount); michael@0: return -EBUSY; michael@0: } michael@0: } michael@0: michael@0: // we're in synchronous mode and didn't find a buffer, we need to michael@0: // wait for some buffers to be consumed michael@0: tryAgain = (found == INVALID_BUFFER_SLOT); michael@0: if (tryAgain) { michael@0: CNW_LOGD("dequeueBuffer: Try again"); michael@0: mDequeueCondition.wait(mMutex); michael@0: CNW_LOGD("dequeueBuffer: Now"); michael@0: } michael@0: } michael@0: michael@0: if (found == INVALID_BUFFER_SLOT) { michael@0: // This should not happen. michael@0: CNW_LOGE("dequeueBuffer: no available buffer slots"); michael@0: return -EBUSY; michael@0: } michael@0: michael@0: buf = found; michael@0: *outBuf = found; michael@0: michael@0: const bool useDefaultSize = !w && !h; michael@0: if (useDefaultSize) { michael@0: // use the default size michael@0: w = mDefaultWidth; michael@0: h = mDefaultHeight; michael@0: } michael@0: michael@0: updateFormat = (format != 0); michael@0: if (!updateFormat) { michael@0: // keep the current (or default) format michael@0: format = mPixelFormat; michael@0: } michael@0: michael@0: mSlots[buf].mBufferState = BufferSlot::DEQUEUED; michael@0: michael@0: const sp& gbuf(mSlots[buf].mGraphicBuffer); michael@0: if ((gbuf == NULL) || michael@0: ((uint32_t(gbuf->width) != w) || michael@0: (uint32_t(gbuf->height) != h) || michael@0: (uint32_t(gbuf->format) != format) || michael@0: ((uint32_t(gbuf->usage) & usage) != usage))) { michael@0: mSlots[buf].mGraphicBuffer = NULL; michael@0: mSlots[buf].mRequestBufferCalled = false; michael@0: if (mSlots[buf].mTextureClient) { michael@0: mSlots[buf].mTextureClient->ClearRecycleCallback(); michael@0: // release TextureClient in ImageBridge thread michael@0: nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[buf].mTextureClient); michael@0: mSlots[buf].mTextureClient = NULL; michael@0: ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task); michael@0: } michael@0: alloc = true; michael@0: } michael@0: } // end lock scope michael@0: michael@0: sp graphicBuffer; michael@0: if (alloc) { michael@0: RefPtr textureClient = michael@0: new GrallocTextureClientOGL(ImageBridgeChild::GetSingleton(), michael@0: gfx::SurfaceFormat::UNKNOWN, michael@0: gfx::BackendType::NONE, michael@0: TEXTURE_DEALLOCATE_CLIENT); michael@0: usage |= GraphicBuffer::USAGE_HW_TEXTURE; michael@0: bool result = textureClient->AllocateGralloc(IntSize(w, h), format, usage); michael@0: sp graphicBuffer = textureClient->GetGraphicBuffer(); michael@0: if (!result || !graphicBuffer.get()) { michael@0: CNW_LOGE("dequeueBuffer: failed to alloc gralloc buffer"); michael@0: return -ENOMEM; michael@0: } michael@0: michael@0: { // Scope for the lock michael@0: Mutex::Autolock lock(mMutex); michael@0: michael@0: if (mAbandoned) { michael@0: CNW_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); michael@0: return NO_INIT; michael@0: } michael@0: michael@0: if (updateFormat) { michael@0: mPixelFormat = format; michael@0: } michael@0: mSlots[buf].mGraphicBuffer = graphicBuffer; michael@0: mSlots[buf].mTextureClient = textureClient; michael@0: michael@0: returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; michael@0: michael@0: CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf, michael@0: mSlots[buf].mGraphicBuffer->handle); michael@0: } michael@0: } michael@0: michael@0: CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf, michael@0: mSlots[buf].mGraphicBuffer->handle ); michael@0: michael@0: CNW_LOGD("dequeueBuffer: X"); michael@0: return returnFlags; michael@0: } michael@0: michael@0: status_t GonkNativeWindow::setSynchronousMode(bool enabled) michael@0: { michael@0: return NO_ERROR; michael@0: } michael@0: michael@0: int GonkNativeWindow::getSlotFromBufferLocked( michael@0: android_native_buffer_t* buffer) const michael@0: { michael@0: if (buffer == NULL) { michael@0: CNW_LOGE("getSlotFromBufferLocked: encountered NULL buffer"); michael@0: return BAD_VALUE; michael@0: } michael@0: michael@0: for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { michael@0: if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) { michael@0: return i; michael@0: } michael@0: } michael@0: CNW_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); michael@0: return BAD_VALUE; michael@0: } michael@0: michael@0: int GonkNativeWindow::getSlotFromTextureClientLocked( michael@0: TextureClient* client) const michael@0: { michael@0: if (client == NULL) { michael@0: CNW_LOGE("getSlotFromBufferLocked: encountered NULL buffer"); michael@0: return BAD_VALUE; michael@0: } michael@0: michael@0: for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { michael@0: if (mSlots[i].mTextureClient == client) { michael@0: return i; michael@0: } michael@0: } michael@0: CNW_LOGE("getSlotFromBufferLocked: unknown TextureClient: %p", client); michael@0: return BAD_VALUE; michael@0: } michael@0: michael@0: TemporaryRef michael@0: GonkNativeWindow::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) michael@0: { michael@0: int buf = getSlotFromBufferLocked(buffer); michael@0: if (buf < 0 || buf >= mBufferCount || michael@0: mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { michael@0: return nullptr; michael@0: } michael@0: michael@0: return mSlots[buf].mTextureClient; michael@0: } michael@0: michael@0: status_t GonkNativeWindow::queueBuffer(int buf, int64_t timestamp, michael@0: uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) michael@0: { michael@0: { michael@0: Mutex::Autolock lock(mMutex); michael@0: CNW_LOGD("queueBuffer: E"); michael@0: CNW_LOGD("queueBuffer: buf=%d", buf); michael@0: michael@0: if (mAbandoned) { michael@0: CNW_LOGE("queueBuffer: GonkNativeWindow has been abandoned!"); michael@0: return NO_INIT; michael@0: } michael@0: if (buf < 0 || buf >= mBufferCount) { michael@0: CNW_LOGE("queueBuffer: slot index out of range [0, %d]: %d", michael@0: mBufferCount, buf); michael@0: return -EINVAL; michael@0: } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { michael@0: CNW_LOGE("queueBuffer: slot %d is not owned by the client " michael@0: "(state=%d)", buf, mSlots[buf].mBufferState); michael@0: return -EINVAL; michael@0: } else if (!mSlots[buf].mRequestBufferCalled) { michael@0: CNW_LOGE("queueBuffer: slot %d was enqueued without requesting a " michael@0: "buffer", buf); michael@0: return -EINVAL; michael@0: } michael@0: michael@0: mQueue.push_back(buf); michael@0: michael@0: mSlots[buf].mBufferState = BufferSlot::QUEUED; michael@0: mSlots[buf].mTimestamp = timestamp; michael@0: mFrameCounter++; michael@0: mSlots[buf].mFrameNumber = mFrameCounter; michael@0: michael@0: mDequeueCondition.signal(); michael@0: michael@0: *outWidth = mDefaultWidth; michael@0: *outHeight = mDefaultHeight; michael@0: *outTransform = 0; michael@0: } michael@0: michael@0: // OnNewFrame might call lockCurrentBuffer so we must release the michael@0: // mutex first. michael@0: if (mNewFrameCallback) { michael@0: mNewFrameCallback->OnNewFrame(); michael@0: } michael@0: CNW_LOGD("queueBuffer: X"); michael@0: return OK; michael@0: } michael@0: michael@0: michael@0: TemporaryRef michael@0: GonkNativeWindow::getCurrentBuffer() { michael@0: CNW_LOGD("GonkNativeWindow::getCurrentBuffer"); michael@0: Mutex::Autolock lock(mMutex); michael@0: michael@0: if (mAbandoned) { michael@0: CNW_LOGE("getCurrentBuffer: GonkNativeWindow has been abandoned!"); michael@0: return NULL; michael@0: } michael@0: michael@0: if(mQueue.empty()) { michael@0: mDequeueCondition.signal(); michael@0: return nullptr; michael@0: } michael@0: michael@0: Fifo::iterator front(mQueue.begin()); michael@0: int buf = *front; michael@0: CNW_LOGD("getCurrentBuffer: buf=%d", buf); michael@0: michael@0: mSlots[buf].mBufferState = BufferSlot::RENDERING; michael@0: michael@0: mQueue.erase(front); michael@0: mDequeueCondition.signal(); michael@0: michael@0: mSlots[buf].mTextureClient->SetRecycleCallback(GonkNativeWindow::RecycleCallback, this); michael@0: return mSlots[buf].mTextureClient; michael@0: } michael@0: michael@0: michael@0: /* static */ void michael@0: GonkNativeWindow::RecycleCallback(TextureClient* client, void* closure) { michael@0: GonkNativeWindow* nativeWindow = michael@0: static_cast(closure); michael@0: michael@0: client->ClearRecycleCallback(); michael@0: nativeWindow->returnBuffer(client); michael@0: } michael@0: michael@0: void GonkNativeWindow::returnBuffer(TextureClient* client) { michael@0: CNW_LOGD("GonkNativeWindow::returnBuffer"); michael@0: Mutex::Autolock lock(mMutex); michael@0: michael@0: if (mAbandoned) { michael@0: CNW_LOGD("returnBuffer: GonkNativeWindow has been abandoned!"); michael@0: return; michael@0: } michael@0: michael@0: int index = getSlotFromTextureClientLocked(client); michael@0: if (index < 0 || index >= mBufferCount) { michael@0: CNW_LOGE("returnBuffer: slot index out of range [0, %d]: %d", michael@0: mBufferCount, index); michael@0: return; michael@0: } michael@0: michael@0: if (mSlots[index].mBufferState != BufferSlot::RENDERING) { michael@0: CNW_LOGE("returnBuffer: slot %d is not owned by the compositor (state=%d)", michael@0: index, mSlots[index].mBufferState); michael@0: return; michael@0: } michael@0: michael@0: mSlots[index].mBufferState = BufferSlot::FREE; michael@0: mDequeueCondition.signal(); michael@0: return; michael@0: } michael@0: michael@0: void GonkNativeWindow::cancelBuffer(int buf) { michael@0: CNW_LOGD("cancelBuffer: slot=%d", buf); michael@0: Mutex::Autolock lock(mMutex); michael@0: michael@0: if (mAbandoned) { michael@0: CNW_LOGD("cancelBuffer: GonkNativeWindow has been abandoned!"); michael@0: return; michael@0: } michael@0: michael@0: if (buf < 0 || buf >= mBufferCount) { michael@0: CNW_LOGE("cancelBuffer: slot index out of range [0, %d]: %d", michael@0: mBufferCount, buf); michael@0: return; michael@0: } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { michael@0: CNW_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", michael@0: buf, mSlots[buf].mBufferState); michael@0: return; michael@0: } michael@0: mSlots[buf].mBufferState = BufferSlot::FREE; michael@0: mSlots[buf].mFrameNumber = 0; michael@0: mDequeueCondition.signal(); michael@0: } michael@0: michael@0: status_t GonkNativeWindow::setCrop(const Rect& crop) { michael@0: return OK; michael@0: } michael@0: michael@0: status_t GonkNativeWindow::setTransform(uint32_t transform) { michael@0: return OK; michael@0: } michael@0: michael@0: status_t GonkNativeWindow::connect(int api, michael@0: uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { michael@0: CNW_LOGD("connect: api=%d", api); michael@0: Mutex::Autolock lock(mMutex); michael@0: michael@0: if (mAbandoned) { michael@0: CNW_LOGE("connect: GonkNativeWindow has been abandoned!"); michael@0: return NO_INIT; michael@0: } michael@0: michael@0: int err = NO_ERROR; michael@0: switch (api) { michael@0: case NATIVE_WINDOW_API_EGL: michael@0: case NATIVE_WINDOW_API_CPU: michael@0: case NATIVE_WINDOW_API_MEDIA: michael@0: case NATIVE_WINDOW_API_CAMERA: michael@0: if (mConnectedApi != NO_CONNECTED_API) { michael@0: CNW_LOGE("connect: already connected (cur=%d, req=%d)", michael@0: mConnectedApi, api); michael@0: err = -EINVAL; michael@0: } else { michael@0: mConnectedApi = api; michael@0: *outWidth = mDefaultWidth; michael@0: *outHeight = mDefaultHeight; michael@0: *outTransform = 0; michael@0: } michael@0: break; michael@0: default: michael@0: err = -EINVAL; michael@0: break; michael@0: } michael@0: return err; michael@0: } michael@0: michael@0: status_t GonkNativeWindow::disconnect(int api) { michael@0: CNW_LOGD("disconnect: api=%d", api); michael@0: michael@0: int err = NO_ERROR; michael@0: Mutex::Autolock lock(mMutex); michael@0: michael@0: if (mAbandoned) { michael@0: // it is not really an error to disconnect after the surface michael@0: // has been abandoned, it should just be a no-op. michael@0: return NO_ERROR; michael@0: } michael@0: michael@0: switch (api) { michael@0: case NATIVE_WINDOW_API_EGL: michael@0: case NATIVE_WINDOW_API_CPU: michael@0: case NATIVE_WINDOW_API_MEDIA: michael@0: case NATIVE_WINDOW_API_CAMERA: michael@0: if (mConnectedApi == api) { michael@0: mQueue.clear(); michael@0: freeAllBuffersLocked(); michael@0: mConnectedApi = NO_CONNECTED_API; michael@0: mDequeueCondition.signal(); michael@0: } else { michael@0: CNW_LOGE("disconnect: connected to another api (cur=%d, req=%d)", michael@0: mConnectedApi, api); michael@0: err = -EINVAL; michael@0: } michael@0: break; michael@0: default: michael@0: CNW_LOGE("disconnect: unknown API %d", api); michael@0: err = -EINVAL; michael@0: break; michael@0: } michael@0: return err; michael@0: } michael@0: michael@0: status_t GonkNativeWindow::setScalingMode(int mode) { michael@0: return OK; michael@0: } michael@0: michael@0: void GonkNativeWindow::setNewFrameCallback( michael@0: GonkNativeWindowNewFrameCallback* aCallback) { michael@0: CNW_LOGD("setNewFrameCallback"); michael@0: Mutex::Autolock lock(mMutex); michael@0: mNewFrameCallback = aCallback; michael@0: } michael@0: michael@0: int GonkNativeWindow::query(int what, int* outValue) michael@0: { michael@0: Mutex::Autolock lock(mMutex); michael@0: michael@0: if (mAbandoned) { michael@0: CNW_LOGE("query: GonkNativeWindow has been abandoned!"); michael@0: return NO_INIT; michael@0: } michael@0: michael@0: int value; michael@0: switch (what) { michael@0: case NATIVE_WINDOW_WIDTH: michael@0: value = mDefaultWidth; michael@0: break; michael@0: case NATIVE_WINDOW_HEIGHT: michael@0: value = mDefaultHeight; michael@0: break; michael@0: case NATIVE_WINDOW_FORMAT: michael@0: value = mPixelFormat; michael@0: break; michael@0: case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: michael@0: value = MIN_UNDEQUEUED_BUFFERS; michael@0: break; michael@0: default: michael@0: return BAD_VALUE; michael@0: } michael@0: outValue[0] = value; michael@0: return NO_ERROR; michael@0: }