1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/gonk/nativewindow/GonkNativeWindowICS.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,687 @@ 1.4 +/* 1.5 + * Copyright (C) 2010 The Android Open Source Project 1.6 + * Copyright (C) 2012-2013 Mozilla Foundation 1.7 + * 1.8 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.9 + * you may not use this file except in compliance with the License. 1.10 + * You may obtain a copy of the License at 1.11 + * 1.12 + * http://www.apache.org/licenses/LICENSE-2.0 1.13 + * 1.14 + * Unless required by applicable law or agreed to in writing, software 1.15 + * distributed under the License is distributed on an "AS IS" BASIS, 1.16 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.17 + * See the License for the specific language governing permissions and 1.18 + * limitations under the License. 1.19 + */ 1.20 + 1.21 +#include "base/basictypes.h" 1.22 +#include "mozilla/layers/GrallocTextureClient.h" 1.23 +#include "mozilla/layers/ImageBridgeChild.h" 1.24 +#include "mozilla/layers/ShadowLayers.h" 1.25 +#include "mozilla/layers/ShadowLayerUtilsGralloc.h" 1.26 +#include "GonkNativeWindow.h" 1.27 +#include "nsDebug.h" 1.28 + 1.29 +/** 1.30 + * DOM_CAMERA_LOGI() is enabled in debug builds, and turned on by setting 1.31 + * NSPR_LOG_MODULES=Camera:N environment variable, where N >= 3. 1.32 + * 1.33 + * CNW_LOGE() is always enabled. 1.34 + */ 1.35 +#define CNW_LOGD(...) DOM_CAMERA_LOGI(__VA_ARGS__) 1.36 +#define CNW_LOGE(...) {(void)printf_stderr(__VA_ARGS__);} 1.37 + 1.38 +using namespace android; 1.39 +using namespace mozilla; 1.40 +using namespace mozilla::gfx; 1.41 +using namespace mozilla::layers; 1.42 + 1.43 +class nsProxyReleaseTask : public CancelableTask 1.44 +{ 1.45 +public: 1.46 + nsProxyReleaseTask(TextureClient* aClient) 1.47 + : mTextureClient(aClient) { 1.48 + } 1.49 + 1.50 + virtual void Run() MOZ_OVERRIDE 1.51 + { 1.52 + mTextureClient = nullptr; 1.53 + } 1.54 + 1.55 + virtual void Cancel() MOZ_OVERRIDE {} 1.56 + 1.57 +private: 1.58 + mozilla::RefPtr<TextureClient> mTextureClient; 1.59 +}; 1.60 + 1.61 +GonkNativeWindow::GonkNativeWindow() : 1.62 + mAbandoned(false), 1.63 + mDefaultWidth(1), 1.64 + mDefaultHeight(1), 1.65 + mPixelFormat(PIXEL_FORMAT_RGBA_8888), 1.66 + mBufferCount(MIN_BUFFER_SLOTS + 1), 1.67 + mConnectedApi(NO_CONNECTED_API), 1.68 + mFrameCounter(0), 1.69 + mNewFrameCallback(nullptr) { 1.70 +} 1.71 + 1.72 +GonkNativeWindow::~GonkNativeWindow() { 1.73 + freeAllBuffersLocked(); 1.74 +} 1.75 + 1.76 +void GonkNativeWindow::abandon() 1.77 +{ 1.78 + CNW_LOGD("abandon"); 1.79 + Mutex::Autolock lock(mMutex); 1.80 + mQueue.clear(); 1.81 + mAbandoned = true; 1.82 + freeAllBuffersLocked(); 1.83 + mDequeueCondition.signal(); 1.84 +} 1.85 + 1.86 +void GonkNativeWindow::freeAllBuffersLocked() 1.87 +{ 1.88 + CNW_LOGD("freeAllBuffersLocked"); 1.89 + 1.90 + for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) { 1.91 + if (mSlots[i].mGraphicBuffer != NULL) { 1.92 + if (mSlots[i].mTextureClient) { 1.93 + mSlots[i].mTextureClient->ClearRecycleCallback(); 1.94 + // release TextureClient in ImageBridge thread 1.95 + nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[i].mTextureClient); 1.96 + mSlots[i].mTextureClient = NULL; 1.97 + ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task); 1.98 + } 1.99 + mSlots[i].mGraphicBuffer = NULL; 1.100 + mSlots[i].mBufferState = BufferSlot::FREE; 1.101 + mSlots[i].mFrameNumber = 0; 1.102 + } 1.103 + } 1.104 +} 1.105 + 1.106 +void GonkNativeWindow::clearRenderingStateBuffersLocked() 1.107 +{ 1.108 + CNW_LOGD("clearRenderingStateBuffersLocked"); 1.109 + 1.110 + for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) { 1.111 + if (mSlots[i].mGraphicBuffer != NULL) { 1.112 + // Clear RENDERING state buffer 1.113 + if (mSlots[i].mBufferState == BufferSlot::RENDERING) { 1.114 + if (mSlots[i].mTextureClient) { 1.115 + mSlots[i].mTextureClient->ClearRecycleCallback(); 1.116 + // release TextureClient in ImageBridge thread 1.117 + nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[i].mTextureClient); 1.118 + mSlots[i].mTextureClient = NULL; 1.119 + ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task); 1.120 + } 1.121 + mSlots[i].mGraphicBuffer = NULL; 1.122 + mSlots[i].mBufferState = BufferSlot::FREE; 1.123 + mSlots[i].mFrameNumber = 0; 1.124 + } 1.125 + } 1.126 + } 1.127 +} 1.128 + 1.129 +status_t GonkNativeWindow::setBufferCount(int bufferCount) 1.130 +{ 1.131 + CNW_LOGD("setBufferCount: count=%d", bufferCount); 1.132 + Mutex::Autolock lock(mMutex); 1.133 + 1.134 + if (mAbandoned) { 1.135 + CNW_LOGE("setBufferCount: GonkNativeWindow has been abandoned!"); 1.136 + return NO_INIT; 1.137 + } 1.138 + 1.139 + if (bufferCount > NUM_BUFFER_SLOTS) { 1.140 + CNW_LOGE("setBufferCount: bufferCount larger than slots available"); 1.141 + return BAD_VALUE; 1.142 + } 1.143 + 1.144 + if (bufferCount < MIN_BUFFER_SLOTS) { 1.145 + CNW_LOGE("setBufferCount: requested buffer count (%d) is less than " 1.146 + "minimum (%d)", bufferCount, MIN_BUFFER_SLOTS); 1.147 + return BAD_VALUE; 1.148 + } 1.149 + 1.150 + // Error out if the user has dequeued buffers. 1.151 + for (int i=0 ; i<mBufferCount ; i++) { 1.152 + if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) { 1.153 + CNW_LOGE("setBufferCount: client owns some buffers"); 1.154 + return -EINVAL; 1.155 + } 1.156 + } 1.157 + 1.158 + if (bufferCount >= mBufferCount) { 1.159 + mBufferCount = bufferCount; 1.160 + //clear only buffers in RENDERING state. 1.161 + clearRenderingStateBuffersLocked(); 1.162 + mQueue.clear(); 1.163 + mDequeueCondition.signal(); 1.164 + return OK; 1.165 + } 1.166 + 1.167 + // here we're guaranteed that the client doesn't have dequeued buffers 1.168 + // and will release all of its buffer references. 1.169 + freeAllBuffersLocked(); 1.170 + mBufferCount = bufferCount; 1.171 + mQueue.clear(); 1.172 + mDequeueCondition.signal(); 1.173 + return OK; 1.174 +} 1.175 + 1.176 +status_t GonkNativeWindow::setDefaultBufferSize(uint32_t w, uint32_t h) 1.177 +{ 1.178 + CNW_LOGD("setDefaultBufferSize: w=%d, h=%d", w, h); 1.179 + if (!w || !h) { 1.180 + CNW_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", 1.181 + w, h); 1.182 + return BAD_VALUE; 1.183 + } 1.184 + 1.185 + Mutex::Autolock lock(mMutex); 1.186 + mDefaultWidth = w; 1.187 + mDefaultHeight = h; 1.188 + return OK; 1.189 +} 1.190 + 1.191 +status_t GonkNativeWindow::requestBuffer(int slot, sp<GraphicBuffer>* buf) 1.192 +{ 1.193 + CNW_LOGD("requestBuffer: slot=%d", slot); 1.194 + Mutex::Autolock lock(mMutex); 1.195 + if (mAbandoned) { 1.196 + CNW_LOGE("requestBuffer: GonkNativeWindow has been abandoned!"); 1.197 + return NO_INIT; 1.198 + } 1.199 + if (slot < 0 || mBufferCount <= slot) { 1.200 + CNW_LOGE("requestBuffer: slot index out of range [0, %d]: %d", 1.201 + mBufferCount, slot); 1.202 + return BAD_VALUE; 1.203 + } 1.204 + mSlots[slot].mRequestBufferCalled = true; 1.205 + *buf = mSlots[slot].mGraphicBuffer; 1.206 + return NO_ERROR; 1.207 +} 1.208 + 1.209 +status_t GonkNativeWindow::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, 1.210 + uint32_t format, uint32_t usage) 1.211 +{ 1.212 + if ((w && !h) || (!w && h)) { 1.213 + CNW_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); 1.214 + return BAD_VALUE; 1.215 + } 1.216 + 1.217 + status_t returnFlags(OK); 1.218 + bool updateFormat = false; 1.219 + bool alloc = false; 1.220 + int buf = INVALID_BUFFER_SLOT; 1.221 + 1.222 + { 1.223 + Mutex::Autolock lock(mMutex); 1.224 + 1.225 + int found = -1; 1.226 + int dequeuedCount = 0; 1.227 + int renderingCount = 0; 1.228 + bool tryAgain = true; 1.229 + 1.230 + CNW_LOGD("dequeueBuffer: E"); 1.231 + while (tryAgain) { 1.232 + if (mAbandoned) { 1.233 + CNW_LOGE("dequeueBuffer: GonkNativeWindow has been abandoned!"); 1.234 + return NO_INIT; 1.235 + } 1.236 + // look for a free buffer to give to the client 1.237 + found = INVALID_BUFFER_SLOT; 1.238 + dequeuedCount = 0; 1.239 + renderingCount = 0; 1.240 + for (int i = 0; i < mBufferCount; i++) { 1.241 + const int state = mSlots[i].mBufferState; 1.242 + switch (state) { 1.243 + case BufferSlot::DEQUEUED: 1.244 + CNW_LOGD("dequeueBuffer: slot %d is DEQUEUED\n", i); 1.245 + dequeuedCount++; 1.246 + break; 1.247 + 1.248 + case BufferSlot::RENDERING: 1.249 + CNW_LOGD("dequeueBuffer: slot %d is RENDERING\n", i); 1.250 + renderingCount++; 1.251 + break; 1.252 + 1.253 + case BufferSlot::FREE: 1.254 + CNW_LOGD("dequeueBuffer: slot %d is FREE\n", i); 1.255 + /* We return the oldest of the free buffers to avoid 1.256 + * stalling the producer if possible. This is because 1.257 + * the consumer may still have pending reads of the 1.258 + * buffers in flight. 1.259 + */ 1.260 + if (found < 0 || 1.261 + mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) { 1.262 + found = i; 1.263 + } 1.264 + break; 1.265 + 1.266 + default: 1.267 + CNW_LOGD("dequeueBuffer: slot %d is %d\n", i, state); 1.268 + break; 1.269 + } 1.270 + } 1.271 + 1.272 + // See whether a buffer has been in RENDERING state since the last 1.273 + // setBufferCount so we know whether to perform the 1.274 + // MIN_UNDEQUEUED_BUFFERS check below. 1.275 + if (renderingCount > 0) { 1.276 + // make sure the client is not trying to dequeue more buffers 1.277 + // than allowed. 1.278 + const int avail = mBufferCount - (dequeuedCount + 1); 1.279 + if (avail < MIN_UNDEQUEUED_BUFFERS) { 1.280 + CNW_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded " 1.281 + "(dequeued=%d)", 1.282 + MIN_UNDEQUEUED_BUFFERS, 1.283 + dequeuedCount); 1.284 + return -EBUSY; 1.285 + } 1.286 + } 1.287 + 1.288 + // we're in synchronous mode and didn't find a buffer, we need to 1.289 + // wait for some buffers to be consumed 1.290 + tryAgain = (found == INVALID_BUFFER_SLOT); 1.291 + if (tryAgain) { 1.292 + CNW_LOGD("dequeueBuffer: Try again"); 1.293 + mDequeueCondition.wait(mMutex); 1.294 + CNW_LOGD("dequeueBuffer: Now"); 1.295 + } 1.296 + } 1.297 + 1.298 + if (found == INVALID_BUFFER_SLOT) { 1.299 + // This should not happen. 1.300 + CNW_LOGE("dequeueBuffer: no available buffer slots"); 1.301 + return -EBUSY; 1.302 + } 1.303 + 1.304 + buf = found; 1.305 + *outBuf = found; 1.306 + 1.307 + const bool useDefaultSize = !w && !h; 1.308 + if (useDefaultSize) { 1.309 + // use the default size 1.310 + w = mDefaultWidth; 1.311 + h = mDefaultHeight; 1.312 + } 1.313 + 1.314 + updateFormat = (format != 0); 1.315 + if (!updateFormat) { 1.316 + // keep the current (or default) format 1.317 + format = mPixelFormat; 1.318 + } 1.319 + 1.320 + mSlots[buf].mBufferState = BufferSlot::DEQUEUED; 1.321 + 1.322 + const sp<GraphicBuffer>& gbuf(mSlots[buf].mGraphicBuffer); 1.323 + if ((gbuf == NULL) || 1.324 + ((uint32_t(gbuf->width) != w) || 1.325 + (uint32_t(gbuf->height) != h) || 1.326 + (uint32_t(gbuf->format) != format) || 1.327 + ((uint32_t(gbuf->usage) & usage) != usage))) { 1.328 + mSlots[buf].mGraphicBuffer = NULL; 1.329 + mSlots[buf].mRequestBufferCalled = false; 1.330 + if (mSlots[buf].mTextureClient) { 1.331 + mSlots[buf].mTextureClient->ClearRecycleCallback(); 1.332 + // release TextureClient in ImageBridge thread 1.333 + nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[buf].mTextureClient); 1.334 + mSlots[buf].mTextureClient = NULL; 1.335 + ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task); 1.336 + } 1.337 + alloc = true; 1.338 + } 1.339 + } // end lock scope 1.340 + 1.341 + sp<GraphicBuffer> graphicBuffer; 1.342 + if (alloc) { 1.343 + RefPtr<GrallocTextureClientOGL> textureClient = 1.344 + new GrallocTextureClientOGL(ImageBridgeChild::GetSingleton(), 1.345 + gfx::SurfaceFormat::UNKNOWN, 1.346 + gfx::BackendType::NONE, 1.347 + TEXTURE_DEALLOCATE_CLIENT); 1.348 + usage |= GraphicBuffer::USAGE_HW_TEXTURE; 1.349 + bool result = textureClient->AllocateGralloc(IntSize(w, h), format, usage); 1.350 + sp<GraphicBuffer> graphicBuffer = textureClient->GetGraphicBuffer(); 1.351 + if (!result || !graphicBuffer.get()) { 1.352 + CNW_LOGE("dequeueBuffer: failed to alloc gralloc buffer"); 1.353 + return -ENOMEM; 1.354 + } 1.355 + 1.356 + { // Scope for the lock 1.357 + Mutex::Autolock lock(mMutex); 1.358 + 1.359 + if (mAbandoned) { 1.360 + CNW_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); 1.361 + return NO_INIT; 1.362 + } 1.363 + 1.364 + if (updateFormat) { 1.365 + mPixelFormat = format; 1.366 + } 1.367 + mSlots[buf].mGraphicBuffer = graphicBuffer; 1.368 + mSlots[buf].mTextureClient = textureClient; 1.369 + 1.370 + returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; 1.371 + 1.372 + CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf, 1.373 + mSlots[buf].mGraphicBuffer->handle); 1.374 + } 1.375 + } 1.376 + 1.377 + CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf, 1.378 + mSlots[buf].mGraphicBuffer->handle ); 1.379 + 1.380 + CNW_LOGD("dequeueBuffer: X"); 1.381 + return returnFlags; 1.382 +} 1.383 + 1.384 +status_t GonkNativeWindow::setSynchronousMode(bool enabled) 1.385 +{ 1.386 + return NO_ERROR; 1.387 +} 1.388 + 1.389 +int GonkNativeWindow::getSlotFromBufferLocked( 1.390 + android_native_buffer_t* buffer) const 1.391 +{ 1.392 + if (buffer == NULL) { 1.393 + CNW_LOGE("getSlotFromBufferLocked: encountered NULL buffer"); 1.394 + return BAD_VALUE; 1.395 + } 1.396 + 1.397 + for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { 1.398 + if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) { 1.399 + return i; 1.400 + } 1.401 + } 1.402 + CNW_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); 1.403 + return BAD_VALUE; 1.404 +} 1.405 + 1.406 +int GonkNativeWindow::getSlotFromTextureClientLocked( 1.407 + TextureClient* client) const 1.408 +{ 1.409 + if (client == NULL) { 1.410 + CNW_LOGE("getSlotFromBufferLocked: encountered NULL buffer"); 1.411 + return BAD_VALUE; 1.412 + } 1.413 + 1.414 + for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { 1.415 + if (mSlots[i].mTextureClient == client) { 1.416 + return i; 1.417 + } 1.418 + } 1.419 + CNW_LOGE("getSlotFromBufferLocked: unknown TextureClient: %p", client); 1.420 + return BAD_VALUE; 1.421 +} 1.422 + 1.423 +TemporaryRef<TextureClient> 1.424 +GonkNativeWindow::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) 1.425 +{ 1.426 + int buf = getSlotFromBufferLocked(buffer); 1.427 + if (buf < 0 || buf >= mBufferCount || 1.428 + mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { 1.429 + return nullptr; 1.430 + } 1.431 + 1.432 + return mSlots[buf].mTextureClient; 1.433 +} 1.434 + 1.435 +status_t GonkNativeWindow::queueBuffer(int buf, int64_t timestamp, 1.436 + uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) 1.437 +{ 1.438 + { 1.439 + Mutex::Autolock lock(mMutex); 1.440 + CNW_LOGD("queueBuffer: E"); 1.441 + CNW_LOGD("queueBuffer: buf=%d", buf); 1.442 + 1.443 + if (mAbandoned) { 1.444 + CNW_LOGE("queueBuffer: GonkNativeWindow has been abandoned!"); 1.445 + return NO_INIT; 1.446 + } 1.447 + if (buf < 0 || buf >= mBufferCount) { 1.448 + CNW_LOGE("queueBuffer: slot index out of range [0, %d]: %d", 1.449 + mBufferCount, buf); 1.450 + return -EINVAL; 1.451 + } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { 1.452 + CNW_LOGE("queueBuffer: slot %d is not owned by the client " 1.453 + "(state=%d)", buf, mSlots[buf].mBufferState); 1.454 + return -EINVAL; 1.455 + } else if (!mSlots[buf].mRequestBufferCalled) { 1.456 + CNW_LOGE("queueBuffer: slot %d was enqueued without requesting a " 1.457 + "buffer", buf); 1.458 + return -EINVAL; 1.459 + } 1.460 + 1.461 + mQueue.push_back(buf); 1.462 + 1.463 + mSlots[buf].mBufferState = BufferSlot::QUEUED; 1.464 + mSlots[buf].mTimestamp = timestamp; 1.465 + mFrameCounter++; 1.466 + mSlots[buf].mFrameNumber = mFrameCounter; 1.467 + 1.468 + mDequeueCondition.signal(); 1.469 + 1.470 + *outWidth = mDefaultWidth; 1.471 + *outHeight = mDefaultHeight; 1.472 + *outTransform = 0; 1.473 + } 1.474 + 1.475 + // OnNewFrame might call lockCurrentBuffer so we must release the 1.476 + // mutex first. 1.477 + if (mNewFrameCallback) { 1.478 + mNewFrameCallback->OnNewFrame(); 1.479 + } 1.480 + CNW_LOGD("queueBuffer: X"); 1.481 + return OK; 1.482 +} 1.483 + 1.484 + 1.485 +TemporaryRef<TextureClient> 1.486 +GonkNativeWindow::getCurrentBuffer() { 1.487 + CNW_LOGD("GonkNativeWindow::getCurrentBuffer"); 1.488 + Mutex::Autolock lock(mMutex); 1.489 + 1.490 + if (mAbandoned) { 1.491 + CNW_LOGE("getCurrentBuffer: GonkNativeWindow has been abandoned!"); 1.492 + return NULL; 1.493 + } 1.494 + 1.495 + if(mQueue.empty()) { 1.496 + mDequeueCondition.signal(); 1.497 + return nullptr; 1.498 + } 1.499 + 1.500 + Fifo::iterator front(mQueue.begin()); 1.501 + int buf = *front; 1.502 + CNW_LOGD("getCurrentBuffer: buf=%d", buf); 1.503 + 1.504 + mSlots[buf].mBufferState = BufferSlot::RENDERING; 1.505 + 1.506 + mQueue.erase(front); 1.507 + mDequeueCondition.signal(); 1.508 + 1.509 + mSlots[buf].mTextureClient->SetRecycleCallback(GonkNativeWindow::RecycleCallback, this); 1.510 + return mSlots[buf].mTextureClient; 1.511 +} 1.512 + 1.513 + 1.514 +/* static */ void 1.515 +GonkNativeWindow::RecycleCallback(TextureClient* client, void* closure) { 1.516 + GonkNativeWindow* nativeWindow = 1.517 + static_cast<GonkNativeWindow*>(closure); 1.518 + 1.519 + client->ClearRecycleCallback(); 1.520 + nativeWindow->returnBuffer(client); 1.521 +} 1.522 + 1.523 +void GonkNativeWindow::returnBuffer(TextureClient* client) { 1.524 + CNW_LOGD("GonkNativeWindow::returnBuffer"); 1.525 + Mutex::Autolock lock(mMutex); 1.526 + 1.527 + if (mAbandoned) { 1.528 + CNW_LOGD("returnBuffer: GonkNativeWindow has been abandoned!"); 1.529 + return; 1.530 + } 1.531 + 1.532 + int index = getSlotFromTextureClientLocked(client); 1.533 + if (index < 0 || index >= mBufferCount) { 1.534 + CNW_LOGE("returnBuffer: slot index out of range [0, %d]: %d", 1.535 + mBufferCount, index); 1.536 + return; 1.537 + } 1.538 + 1.539 + if (mSlots[index].mBufferState != BufferSlot::RENDERING) { 1.540 + CNW_LOGE("returnBuffer: slot %d is not owned by the compositor (state=%d)", 1.541 + index, mSlots[index].mBufferState); 1.542 + return; 1.543 + } 1.544 + 1.545 + mSlots[index].mBufferState = BufferSlot::FREE; 1.546 + mDequeueCondition.signal(); 1.547 + return; 1.548 +} 1.549 + 1.550 +void GonkNativeWindow::cancelBuffer(int buf) { 1.551 + CNW_LOGD("cancelBuffer: slot=%d", buf); 1.552 + Mutex::Autolock lock(mMutex); 1.553 + 1.554 + if (mAbandoned) { 1.555 + CNW_LOGD("cancelBuffer: GonkNativeWindow has been abandoned!"); 1.556 + return; 1.557 + } 1.558 + 1.559 + if (buf < 0 || buf >= mBufferCount) { 1.560 + CNW_LOGE("cancelBuffer: slot index out of range [0, %d]: %d", 1.561 + mBufferCount, buf); 1.562 + return; 1.563 + } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { 1.564 + CNW_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", 1.565 + buf, mSlots[buf].mBufferState); 1.566 + return; 1.567 + } 1.568 + mSlots[buf].mBufferState = BufferSlot::FREE; 1.569 + mSlots[buf].mFrameNumber = 0; 1.570 + mDequeueCondition.signal(); 1.571 +} 1.572 + 1.573 +status_t GonkNativeWindow::setCrop(const Rect& crop) { 1.574 + return OK; 1.575 +} 1.576 + 1.577 +status_t GonkNativeWindow::setTransform(uint32_t transform) { 1.578 + return OK; 1.579 +} 1.580 + 1.581 +status_t GonkNativeWindow::connect(int api, 1.582 + uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { 1.583 + CNW_LOGD("connect: api=%d", api); 1.584 + Mutex::Autolock lock(mMutex); 1.585 + 1.586 + if (mAbandoned) { 1.587 + CNW_LOGE("connect: GonkNativeWindow has been abandoned!"); 1.588 + return NO_INIT; 1.589 + } 1.590 + 1.591 + int err = NO_ERROR; 1.592 + switch (api) { 1.593 + case NATIVE_WINDOW_API_EGL: 1.594 + case NATIVE_WINDOW_API_CPU: 1.595 + case NATIVE_WINDOW_API_MEDIA: 1.596 + case NATIVE_WINDOW_API_CAMERA: 1.597 + if (mConnectedApi != NO_CONNECTED_API) { 1.598 + CNW_LOGE("connect: already connected (cur=%d, req=%d)", 1.599 + mConnectedApi, api); 1.600 + err = -EINVAL; 1.601 + } else { 1.602 + mConnectedApi = api; 1.603 + *outWidth = mDefaultWidth; 1.604 + *outHeight = mDefaultHeight; 1.605 + *outTransform = 0; 1.606 + } 1.607 + break; 1.608 + default: 1.609 + err = -EINVAL; 1.610 + break; 1.611 + } 1.612 + return err; 1.613 +} 1.614 + 1.615 +status_t GonkNativeWindow::disconnect(int api) { 1.616 + CNW_LOGD("disconnect: api=%d", api); 1.617 + 1.618 + int err = NO_ERROR; 1.619 + Mutex::Autolock lock(mMutex); 1.620 + 1.621 + if (mAbandoned) { 1.622 + // it is not really an error to disconnect after the surface 1.623 + // has been abandoned, it should just be a no-op. 1.624 + return NO_ERROR; 1.625 + } 1.626 + 1.627 + switch (api) { 1.628 + case NATIVE_WINDOW_API_EGL: 1.629 + case NATIVE_WINDOW_API_CPU: 1.630 + case NATIVE_WINDOW_API_MEDIA: 1.631 + case NATIVE_WINDOW_API_CAMERA: 1.632 + if (mConnectedApi == api) { 1.633 + mQueue.clear(); 1.634 + freeAllBuffersLocked(); 1.635 + mConnectedApi = NO_CONNECTED_API; 1.636 + mDequeueCondition.signal(); 1.637 + } else { 1.638 + CNW_LOGE("disconnect: connected to another api (cur=%d, req=%d)", 1.639 + mConnectedApi, api); 1.640 + err = -EINVAL; 1.641 + } 1.642 + break; 1.643 + default: 1.644 + CNW_LOGE("disconnect: unknown API %d", api); 1.645 + err = -EINVAL; 1.646 + break; 1.647 + } 1.648 + return err; 1.649 +} 1.650 + 1.651 +status_t GonkNativeWindow::setScalingMode(int mode) { 1.652 + return OK; 1.653 +} 1.654 + 1.655 +void GonkNativeWindow::setNewFrameCallback( 1.656 + GonkNativeWindowNewFrameCallback* aCallback) { 1.657 + CNW_LOGD("setNewFrameCallback"); 1.658 + Mutex::Autolock lock(mMutex); 1.659 + mNewFrameCallback = aCallback; 1.660 +} 1.661 + 1.662 +int GonkNativeWindow::query(int what, int* outValue) 1.663 +{ 1.664 + Mutex::Autolock lock(mMutex); 1.665 + 1.666 + if (mAbandoned) { 1.667 + CNW_LOGE("query: GonkNativeWindow has been abandoned!"); 1.668 + return NO_INIT; 1.669 + } 1.670 + 1.671 + int value; 1.672 + switch (what) { 1.673 + case NATIVE_WINDOW_WIDTH: 1.674 + value = mDefaultWidth; 1.675 + break; 1.676 + case NATIVE_WINDOW_HEIGHT: 1.677 + value = mDefaultHeight; 1.678 + break; 1.679 + case NATIVE_WINDOW_FORMAT: 1.680 + value = mPixelFormat; 1.681 + break; 1.682 + case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: 1.683 + value = MIN_UNDEQUEUED_BUFFERS; 1.684 + break; 1.685 + default: 1.686 + return BAD_VALUE; 1.687 + } 1.688 + outValue[0] = value; 1.689 + return NO_ERROR; 1.690 +}