widget/gonk/nativewindow/GonkNativeWindowICS.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /*
michael@0 2 * Copyright (C) 2010 The Android Open Source Project
michael@0 3 * Copyright (C) 2012-2013 Mozilla Foundation
michael@0 4 *
michael@0 5 * Licensed under the Apache License, Version 2.0 (the "License");
michael@0 6 * you may not use this file except in compliance with the License.
michael@0 7 * You may obtain a copy of the License at
michael@0 8 *
michael@0 9 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 10 *
michael@0 11 * Unless required by applicable law or agreed to in writing, software
michael@0 12 * distributed under the License is distributed on an "AS IS" BASIS,
michael@0 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 14 * See the License for the specific language governing permissions and
michael@0 15 * limitations under the License.
michael@0 16 */
michael@0 17
michael@0 18 #include "base/basictypes.h"
michael@0 19 #include "mozilla/layers/GrallocTextureClient.h"
michael@0 20 #include "mozilla/layers/ImageBridgeChild.h"
michael@0 21 #include "mozilla/layers/ShadowLayers.h"
michael@0 22 #include "mozilla/layers/ShadowLayerUtilsGralloc.h"
michael@0 23 #include "GonkNativeWindow.h"
michael@0 24 #include "nsDebug.h"
michael@0 25
michael@0 26 /**
michael@0 27 * DOM_CAMERA_LOGI() is enabled in debug builds, and turned on by setting
michael@0 28 * NSPR_LOG_MODULES=Camera:N environment variable, where N >= 3.
michael@0 29 *
michael@0 30 * CNW_LOGE() is always enabled.
michael@0 31 */
michael@0 32 #define CNW_LOGD(...) DOM_CAMERA_LOGI(__VA_ARGS__)
michael@0 33 #define CNW_LOGE(...) {(void)printf_stderr(__VA_ARGS__);}
michael@0 34
michael@0 35 using namespace android;
michael@0 36 using namespace mozilla;
michael@0 37 using namespace mozilla::gfx;
michael@0 38 using namespace mozilla::layers;
michael@0 39
michael@0 40 class nsProxyReleaseTask : public CancelableTask
michael@0 41 {
michael@0 42 public:
michael@0 43 nsProxyReleaseTask(TextureClient* aClient)
michael@0 44 : mTextureClient(aClient) {
michael@0 45 }
michael@0 46
michael@0 47 virtual void Run() MOZ_OVERRIDE
michael@0 48 {
michael@0 49 mTextureClient = nullptr;
michael@0 50 }
michael@0 51
michael@0 52 virtual void Cancel() MOZ_OVERRIDE {}
michael@0 53
michael@0 54 private:
michael@0 55 mozilla::RefPtr<TextureClient> mTextureClient;
michael@0 56 };
michael@0 57
michael@0 58 GonkNativeWindow::GonkNativeWindow() :
michael@0 59 mAbandoned(false),
michael@0 60 mDefaultWidth(1),
michael@0 61 mDefaultHeight(1),
michael@0 62 mPixelFormat(PIXEL_FORMAT_RGBA_8888),
michael@0 63 mBufferCount(MIN_BUFFER_SLOTS + 1),
michael@0 64 mConnectedApi(NO_CONNECTED_API),
michael@0 65 mFrameCounter(0),
michael@0 66 mNewFrameCallback(nullptr) {
michael@0 67 }
michael@0 68
michael@0 69 GonkNativeWindow::~GonkNativeWindow() {
michael@0 70 freeAllBuffersLocked();
michael@0 71 }
michael@0 72
michael@0 73 void GonkNativeWindow::abandon()
michael@0 74 {
michael@0 75 CNW_LOGD("abandon");
michael@0 76 Mutex::Autolock lock(mMutex);
michael@0 77 mQueue.clear();
michael@0 78 mAbandoned = true;
michael@0 79 freeAllBuffersLocked();
michael@0 80 mDequeueCondition.signal();
michael@0 81 }
michael@0 82
michael@0 83 void GonkNativeWindow::freeAllBuffersLocked()
michael@0 84 {
michael@0 85 CNW_LOGD("freeAllBuffersLocked");
michael@0 86
michael@0 87 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
michael@0 88 if (mSlots[i].mGraphicBuffer != NULL) {
michael@0 89 if (mSlots[i].mTextureClient) {
michael@0 90 mSlots[i].mTextureClient->ClearRecycleCallback();
michael@0 91 // release TextureClient in ImageBridge thread
michael@0 92 nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[i].mTextureClient);
michael@0 93 mSlots[i].mTextureClient = NULL;
michael@0 94 ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
michael@0 95 }
michael@0 96 mSlots[i].mGraphicBuffer = NULL;
michael@0 97 mSlots[i].mBufferState = BufferSlot::FREE;
michael@0 98 mSlots[i].mFrameNumber = 0;
michael@0 99 }
michael@0 100 }
michael@0 101 }
michael@0 102
michael@0 103 void GonkNativeWindow::clearRenderingStateBuffersLocked()
michael@0 104 {
michael@0 105 CNW_LOGD("clearRenderingStateBuffersLocked");
michael@0 106
michael@0 107 for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
michael@0 108 if (mSlots[i].mGraphicBuffer != NULL) {
michael@0 109 // Clear RENDERING state buffer
michael@0 110 if (mSlots[i].mBufferState == BufferSlot::RENDERING) {
michael@0 111 if (mSlots[i].mTextureClient) {
michael@0 112 mSlots[i].mTextureClient->ClearRecycleCallback();
michael@0 113 // release TextureClient in ImageBridge thread
michael@0 114 nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[i].mTextureClient);
michael@0 115 mSlots[i].mTextureClient = NULL;
michael@0 116 ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
michael@0 117 }
michael@0 118 mSlots[i].mGraphicBuffer = NULL;
michael@0 119 mSlots[i].mBufferState = BufferSlot::FREE;
michael@0 120 mSlots[i].mFrameNumber = 0;
michael@0 121 }
michael@0 122 }
michael@0 123 }
michael@0 124 }
michael@0 125
michael@0 126 status_t GonkNativeWindow::setBufferCount(int bufferCount)
michael@0 127 {
michael@0 128 CNW_LOGD("setBufferCount: count=%d", bufferCount);
michael@0 129 Mutex::Autolock lock(mMutex);
michael@0 130
michael@0 131 if (mAbandoned) {
michael@0 132 CNW_LOGE("setBufferCount: GonkNativeWindow has been abandoned!");
michael@0 133 return NO_INIT;
michael@0 134 }
michael@0 135
michael@0 136 if (bufferCount > NUM_BUFFER_SLOTS) {
michael@0 137 CNW_LOGE("setBufferCount: bufferCount larger than slots available");
michael@0 138 return BAD_VALUE;
michael@0 139 }
michael@0 140
michael@0 141 if (bufferCount < MIN_BUFFER_SLOTS) {
michael@0 142 CNW_LOGE("setBufferCount: requested buffer count (%d) is less than "
michael@0 143 "minimum (%d)", bufferCount, MIN_BUFFER_SLOTS);
michael@0 144 return BAD_VALUE;
michael@0 145 }
michael@0 146
michael@0 147 // Error out if the user has dequeued buffers.
michael@0 148 for (int i=0 ; i<mBufferCount ; i++) {
michael@0 149 if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
michael@0 150 CNW_LOGE("setBufferCount: client owns some buffers");
michael@0 151 return -EINVAL;
michael@0 152 }
michael@0 153 }
michael@0 154
michael@0 155 if (bufferCount >= mBufferCount) {
michael@0 156 mBufferCount = bufferCount;
michael@0 157 //clear only buffers in RENDERING state.
michael@0 158 clearRenderingStateBuffersLocked();
michael@0 159 mQueue.clear();
michael@0 160 mDequeueCondition.signal();
michael@0 161 return OK;
michael@0 162 }
michael@0 163
michael@0 164 // here we're guaranteed that the client doesn't have dequeued buffers
michael@0 165 // and will release all of its buffer references.
michael@0 166 freeAllBuffersLocked();
michael@0 167 mBufferCount = bufferCount;
michael@0 168 mQueue.clear();
michael@0 169 mDequeueCondition.signal();
michael@0 170 return OK;
michael@0 171 }
michael@0 172
michael@0 173 status_t GonkNativeWindow::setDefaultBufferSize(uint32_t w, uint32_t h)
michael@0 174 {
michael@0 175 CNW_LOGD("setDefaultBufferSize: w=%d, h=%d", w, h);
michael@0 176 if (!w || !h) {
michael@0 177 CNW_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
michael@0 178 w, h);
michael@0 179 return BAD_VALUE;
michael@0 180 }
michael@0 181
michael@0 182 Mutex::Autolock lock(mMutex);
michael@0 183 mDefaultWidth = w;
michael@0 184 mDefaultHeight = h;
michael@0 185 return OK;
michael@0 186 }
michael@0 187
michael@0 188 status_t GonkNativeWindow::requestBuffer(int slot, sp<GraphicBuffer>* buf)
michael@0 189 {
michael@0 190 CNW_LOGD("requestBuffer: slot=%d", slot);
michael@0 191 Mutex::Autolock lock(mMutex);
michael@0 192 if (mAbandoned) {
michael@0 193 CNW_LOGE("requestBuffer: GonkNativeWindow has been abandoned!");
michael@0 194 return NO_INIT;
michael@0 195 }
michael@0 196 if (slot < 0 || mBufferCount <= slot) {
michael@0 197 CNW_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
michael@0 198 mBufferCount, slot);
michael@0 199 return BAD_VALUE;
michael@0 200 }
michael@0 201 mSlots[slot].mRequestBufferCalled = true;
michael@0 202 *buf = mSlots[slot].mGraphicBuffer;
michael@0 203 return NO_ERROR;
michael@0 204 }
michael@0 205
michael@0 206 status_t GonkNativeWindow::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
michael@0 207 uint32_t format, uint32_t usage)
michael@0 208 {
michael@0 209 if ((w && !h) || (!w && h)) {
michael@0 210 CNW_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
michael@0 211 return BAD_VALUE;
michael@0 212 }
michael@0 213
michael@0 214 status_t returnFlags(OK);
michael@0 215 bool updateFormat = false;
michael@0 216 bool alloc = false;
michael@0 217 int buf = INVALID_BUFFER_SLOT;
michael@0 218
michael@0 219 {
michael@0 220 Mutex::Autolock lock(mMutex);
michael@0 221
michael@0 222 int found = -1;
michael@0 223 int dequeuedCount = 0;
michael@0 224 int renderingCount = 0;
michael@0 225 bool tryAgain = true;
michael@0 226
michael@0 227 CNW_LOGD("dequeueBuffer: E");
michael@0 228 while (tryAgain) {
michael@0 229 if (mAbandoned) {
michael@0 230 CNW_LOGE("dequeueBuffer: GonkNativeWindow has been abandoned!");
michael@0 231 return NO_INIT;
michael@0 232 }
michael@0 233 // look for a free buffer to give to the client
michael@0 234 found = INVALID_BUFFER_SLOT;
michael@0 235 dequeuedCount = 0;
michael@0 236 renderingCount = 0;
michael@0 237 for (int i = 0; i < mBufferCount; i++) {
michael@0 238 const int state = mSlots[i].mBufferState;
michael@0 239 switch (state) {
michael@0 240 case BufferSlot::DEQUEUED:
michael@0 241 CNW_LOGD("dequeueBuffer: slot %d is DEQUEUED\n", i);
michael@0 242 dequeuedCount++;
michael@0 243 break;
michael@0 244
michael@0 245 case BufferSlot::RENDERING:
michael@0 246 CNW_LOGD("dequeueBuffer: slot %d is RENDERING\n", i);
michael@0 247 renderingCount++;
michael@0 248 break;
michael@0 249
michael@0 250 case BufferSlot::FREE:
michael@0 251 CNW_LOGD("dequeueBuffer: slot %d is FREE\n", i);
michael@0 252 /* We return the oldest of the free buffers to avoid
michael@0 253 * stalling the producer if possible. This is because
michael@0 254 * the consumer may still have pending reads of the
michael@0 255 * buffers in flight.
michael@0 256 */
michael@0 257 if (found < 0 ||
michael@0 258 mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
michael@0 259 found = i;
michael@0 260 }
michael@0 261 break;
michael@0 262
michael@0 263 default:
michael@0 264 CNW_LOGD("dequeueBuffer: slot %d is %d\n", i, state);
michael@0 265 break;
michael@0 266 }
michael@0 267 }
michael@0 268
michael@0 269 // See whether a buffer has been in RENDERING state since the last
michael@0 270 // setBufferCount so we know whether to perform the
michael@0 271 // MIN_UNDEQUEUED_BUFFERS check below.
michael@0 272 if (renderingCount > 0) {
michael@0 273 // make sure the client is not trying to dequeue more buffers
michael@0 274 // than allowed.
michael@0 275 const int avail = mBufferCount - (dequeuedCount + 1);
michael@0 276 if (avail < MIN_UNDEQUEUED_BUFFERS) {
michael@0 277 CNW_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
michael@0 278 "(dequeued=%d)",
michael@0 279 MIN_UNDEQUEUED_BUFFERS,
michael@0 280 dequeuedCount);
michael@0 281 return -EBUSY;
michael@0 282 }
michael@0 283 }
michael@0 284
michael@0 285 // we're in synchronous mode and didn't find a buffer, we need to
michael@0 286 // wait for some buffers to be consumed
michael@0 287 tryAgain = (found == INVALID_BUFFER_SLOT);
michael@0 288 if (tryAgain) {
michael@0 289 CNW_LOGD("dequeueBuffer: Try again");
michael@0 290 mDequeueCondition.wait(mMutex);
michael@0 291 CNW_LOGD("dequeueBuffer: Now");
michael@0 292 }
michael@0 293 }
michael@0 294
michael@0 295 if (found == INVALID_BUFFER_SLOT) {
michael@0 296 // This should not happen.
michael@0 297 CNW_LOGE("dequeueBuffer: no available buffer slots");
michael@0 298 return -EBUSY;
michael@0 299 }
michael@0 300
michael@0 301 buf = found;
michael@0 302 *outBuf = found;
michael@0 303
michael@0 304 const bool useDefaultSize = !w && !h;
michael@0 305 if (useDefaultSize) {
michael@0 306 // use the default size
michael@0 307 w = mDefaultWidth;
michael@0 308 h = mDefaultHeight;
michael@0 309 }
michael@0 310
michael@0 311 updateFormat = (format != 0);
michael@0 312 if (!updateFormat) {
michael@0 313 // keep the current (or default) format
michael@0 314 format = mPixelFormat;
michael@0 315 }
michael@0 316
michael@0 317 mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
michael@0 318
michael@0 319 const sp<GraphicBuffer>& gbuf(mSlots[buf].mGraphicBuffer);
michael@0 320 if ((gbuf == NULL) ||
michael@0 321 ((uint32_t(gbuf->width) != w) ||
michael@0 322 (uint32_t(gbuf->height) != h) ||
michael@0 323 (uint32_t(gbuf->format) != format) ||
michael@0 324 ((uint32_t(gbuf->usage) & usage) != usage))) {
michael@0 325 mSlots[buf].mGraphicBuffer = NULL;
michael@0 326 mSlots[buf].mRequestBufferCalled = false;
michael@0 327 if (mSlots[buf].mTextureClient) {
michael@0 328 mSlots[buf].mTextureClient->ClearRecycleCallback();
michael@0 329 // release TextureClient in ImageBridge thread
michael@0 330 nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[buf].mTextureClient);
michael@0 331 mSlots[buf].mTextureClient = NULL;
michael@0 332 ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
michael@0 333 }
michael@0 334 alloc = true;
michael@0 335 }
michael@0 336 } // end lock scope
michael@0 337
michael@0 338 sp<GraphicBuffer> graphicBuffer;
michael@0 339 if (alloc) {
michael@0 340 RefPtr<GrallocTextureClientOGL> textureClient =
michael@0 341 new GrallocTextureClientOGL(ImageBridgeChild::GetSingleton(),
michael@0 342 gfx::SurfaceFormat::UNKNOWN,
michael@0 343 gfx::BackendType::NONE,
michael@0 344 TEXTURE_DEALLOCATE_CLIENT);
michael@0 345 usage |= GraphicBuffer::USAGE_HW_TEXTURE;
michael@0 346 bool result = textureClient->AllocateGralloc(IntSize(w, h), format, usage);
michael@0 347 sp<GraphicBuffer> graphicBuffer = textureClient->GetGraphicBuffer();
michael@0 348 if (!result || !graphicBuffer.get()) {
michael@0 349 CNW_LOGE("dequeueBuffer: failed to alloc gralloc buffer");
michael@0 350 return -ENOMEM;
michael@0 351 }
michael@0 352
michael@0 353 { // Scope for the lock
michael@0 354 Mutex::Autolock lock(mMutex);
michael@0 355
michael@0 356 if (mAbandoned) {
michael@0 357 CNW_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
michael@0 358 return NO_INIT;
michael@0 359 }
michael@0 360
michael@0 361 if (updateFormat) {
michael@0 362 mPixelFormat = format;
michael@0 363 }
michael@0 364 mSlots[buf].mGraphicBuffer = graphicBuffer;
michael@0 365 mSlots[buf].mTextureClient = textureClient;
michael@0 366
michael@0 367 returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
michael@0 368
michael@0 369 CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
michael@0 370 mSlots[buf].mGraphicBuffer->handle);
michael@0 371 }
michael@0 372 }
michael@0 373
michael@0 374 CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
michael@0 375 mSlots[buf].mGraphicBuffer->handle );
michael@0 376
michael@0 377 CNW_LOGD("dequeueBuffer: X");
michael@0 378 return returnFlags;
michael@0 379 }
michael@0 380
michael@0 381 status_t GonkNativeWindow::setSynchronousMode(bool enabled)
michael@0 382 {
michael@0 383 return NO_ERROR;
michael@0 384 }
michael@0 385
michael@0 386 int GonkNativeWindow::getSlotFromBufferLocked(
michael@0 387 android_native_buffer_t* buffer) const
michael@0 388 {
michael@0 389 if (buffer == NULL) {
michael@0 390 CNW_LOGE("getSlotFromBufferLocked: encountered NULL buffer");
michael@0 391 return BAD_VALUE;
michael@0 392 }
michael@0 393
michael@0 394 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
michael@0 395 if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) {
michael@0 396 return i;
michael@0 397 }
michael@0 398 }
michael@0 399 CNW_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
michael@0 400 return BAD_VALUE;
michael@0 401 }
michael@0 402
michael@0 403 int GonkNativeWindow::getSlotFromTextureClientLocked(
michael@0 404 TextureClient* client) const
michael@0 405 {
michael@0 406 if (client == NULL) {
michael@0 407 CNW_LOGE("getSlotFromBufferLocked: encountered NULL buffer");
michael@0 408 return BAD_VALUE;
michael@0 409 }
michael@0 410
michael@0 411 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
michael@0 412 if (mSlots[i].mTextureClient == client) {
michael@0 413 return i;
michael@0 414 }
michael@0 415 }
michael@0 416 CNW_LOGE("getSlotFromBufferLocked: unknown TextureClient: %p", client);
michael@0 417 return BAD_VALUE;
michael@0 418 }
michael@0 419
michael@0 420 TemporaryRef<TextureClient>
michael@0 421 GonkNativeWindow::getTextureClientFromBuffer(ANativeWindowBuffer* buffer)
michael@0 422 {
michael@0 423 int buf = getSlotFromBufferLocked(buffer);
michael@0 424 if (buf < 0 || buf >= mBufferCount ||
michael@0 425 mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
michael@0 426 return nullptr;
michael@0 427 }
michael@0 428
michael@0 429 return mSlots[buf].mTextureClient;
michael@0 430 }
michael@0 431
michael@0 432 status_t GonkNativeWindow::queueBuffer(int buf, int64_t timestamp,
michael@0 433 uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform)
michael@0 434 {
michael@0 435 {
michael@0 436 Mutex::Autolock lock(mMutex);
michael@0 437 CNW_LOGD("queueBuffer: E");
michael@0 438 CNW_LOGD("queueBuffer: buf=%d", buf);
michael@0 439
michael@0 440 if (mAbandoned) {
michael@0 441 CNW_LOGE("queueBuffer: GonkNativeWindow has been abandoned!");
michael@0 442 return NO_INIT;
michael@0 443 }
michael@0 444 if (buf < 0 || buf >= mBufferCount) {
michael@0 445 CNW_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
michael@0 446 mBufferCount, buf);
michael@0 447 return -EINVAL;
michael@0 448 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
michael@0 449 CNW_LOGE("queueBuffer: slot %d is not owned by the client "
michael@0 450 "(state=%d)", buf, mSlots[buf].mBufferState);
michael@0 451 return -EINVAL;
michael@0 452 } else if (!mSlots[buf].mRequestBufferCalled) {
michael@0 453 CNW_LOGE("queueBuffer: slot %d was enqueued without requesting a "
michael@0 454 "buffer", buf);
michael@0 455 return -EINVAL;
michael@0 456 }
michael@0 457
michael@0 458 mQueue.push_back(buf);
michael@0 459
michael@0 460 mSlots[buf].mBufferState = BufferSlot::QUEUED;
michael@0 461 mSlots[buf].mTimestamp = timestamp;
michael@0 462 mFrameCounter++;
michael@0 463 mSlots[buf].mFrameNumber = mFrameCounter;
michael@0 464
michael@0 465 mDequeueCondition.signal();
michael@0 466
michael@0 467 *outWidth = mDefaultWidth;
michael@0 468 *outHeight = mDefaultHeight;
michael@0 469 *outTransform = 0;
michael@0 470 }
michael@0 471
michael@0 472 // OnNewFrame might call lockCurrentBuffer so we must release the
michael@0 473 // mutex first.
michael@0 474 if (mNewFrameCallback) {
michael@0 475 mNewFrameCallback->OnNewFrame();
michael@0 476 }
michael@0 477 CNW_LOGD("queueBuffer: X");
michael@0 478 return OK;
michael@0 479 }
michael@0 480
michael@0 481
michael@0 482 TemporaryRef<TextureClient>
michael@0 483 GonkNativeWindow::getCurrentBuffer() {
michael@0 484 CNW_LOGD("GonkNativeWindow::getCurrentBuffer");
michael@0 485 Mutex::Autolock lock(mMutex);
michael@0 486
michael@0 487 if (mAbandoned) {
michael@0 488 CNW_LOGE("getCurrentBuffer: GonkNativeWindow has been abandoned!");
michael@0 489 return NULL;
michael@0 490 }
michael@0 491
michael@0 492 if(mQueue.empty()) {
michael@0 493 mDequeueCondition.signal();
michael@0 494 return nullptr;
michael@0 495 }
michael@0 496
michael@0 497 Fifo::iterator front(mQueue.begin());
michael@0 498 int buf = *front;
michael@0 499 CNW_LOGD("getCurrentBuffer: buf=%d", buf);
michael@0 500
michael@0 501 mSlots[buf].mBufferState = BufferSlot::RENDERING;
michael@0 502
michael@0 503 mQueue.erase(front);
michael@0 504 mDequeueCondition.signal();
michael@0 505
michael@0 506 mSlots[buf].mTextureClient->SetRecycleCallback(GonkNativeWindow::RecycleCallback, this);
michael@0 507 return mSlots[buf].mTextureClient;
michael@0 508 }
michael@0 509
michael@0 510
michael@0 511 /* static */ void
michael@0 512 GonkNativeWindow::RecycleCallback(TextureClient* client, void* closure) {
michael@0 513 GonkNativeWindow* nativeWindow =
michael@0 514 static_cast<GonkNativeWindow*>(closure);
michael@0 515
michael@0 516 client->ClearRecycleCallback();
michael@0 517 nativeWindow->returnBuffer(client);
michael@0 518 }
michael@0 519
michael@0 520 void GonkNativeWindow::returnBuffer(TextureClient* client) {
michael@0 521 CNW_LOGD("GonkNativeWindow::returnBuffer");
michael@0 522 Mutex::Autolock lock(mMutex);
michael@0 523
michael@0 524 if (mAbandoned) {
michael@0 525 CNW_LOGD("returnBuffer: GonkNativeWindow has been abandoned!");
michael@0 526 return;
michael@0 527 }
michael@0 528
michael@0 529 int index = getSlotFromTextureClientLocked(client);
michael@0 530 if (index < 0 || index >= mBufferCount) {
michael@0 531 CNW_LOGE("returnBuffer: slot index out of range [0, %d]: %d",
michael@0 532 mBufferCount, index);
michael@0 533 return;
michael@0 534 }
michael@0 535
michael@0 536 if (mSlots[index].mBufferState != BufferSlot::RENDERING) {
michael@0 537 CNW_LOGE("returnBuffer: slot %d is not owned by the compositor (state=%d)",
michael@0 538 index, mSlots[index].mBufferState);
michael@0 539 return;
michael@0 540 }
michael@0 541
michael@0 542 mSlots[index].mBufferState = BufferSlot::FREE;
michael@0 543 mDequeueCondition.signal();
michael@0 544 return;
michael@0 545 }
michael@0 546
michael@0 547 void GonkNativeWindow::cancelBuffer(int buf) {
michael@0 548 CNW_LOGD("cancelBuffer: slot=%d", buf);
michael@0 549 Mutex::Autolock lock(mMutex);
michael@0 550
michael@0 551 if (mAbandoned) {
michael@0 552 CNW_LOGD("cancelBuffer: GonkNativeWindow has been abandoned!");
michael@0 553 return;
michael@0 554 }
michael@0 555
michael@0 556 if (buf < 0 || buf >= mBufferCount) {
michael@0 557 CNW_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
michael@0 558 mBufferCount, buf);
michael@0 559 return;
michael@0 560 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
michael@0 561 CNW_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
michael@0 562 buf, mSlots[buf].mBufferState);
michael@0 563 return;
michael@0 564 }
michael@0 565 mSlots[buf].mBufferState = BufferSlot::FREE;
michael@0 566 mSlots[buf].mFrameNumber = 0;
michael@0 567 mDequeueCondition.signal();
michael@0 568 }
michael@0 569
michael@0 570 status_t GonkNativeWindow::setCrop(const Rect& crop) {
michael@0 571 return OK;
michael@0 572 }
michael@0 573
michael@0 574 status_t GonkNativeWindow::setTransform(uint32_t transform) {
michael@0 575 return OK;
michael@0 576 }
michael@0 577
michael@0 578 status_t GonkNativeWindow::connect(int api,
michael@0 579 uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
michael@0 580 CNW_LOGD("connect: api=%d", api);
michael@0 581 Mutex::Autolock lock(mMutex);
michael@0 582
michael@0 583 if (mAbandoned) {
michael@0 584 CNW_LOGE("connect: GonkNativeWindow has been abandoned!");
michael@0 585 return NO_INIT;
michael@0 586 }
michael@0 587
michael@0 588 int err = NO_ERROR;
michael@0 589 switch (api) {
michael@0 590 case NATIVE_WINDOW_API_EGL:
michael@0 591 case NATIVE_WINDOW_API_CPU:
michael@0 592 case NATIVE_WINDOW_API_MEDIA:
michael@0 593 case NATIVE_WINDOW_API_CAMERA:
michael@0 594 if (mConnectedApi != NO_CONNECTED_API) {
michael@0 595 CNW_LOGE("connect: already connected (cur=%d, req=%d)",
michael@0 596 mConnectedApi, api);
michael@0 597 err = -EINVAL;
michael@0 598 } else {
michael@0 599 mConnectedApi = api;
michael@0 600 *outWidth = mDefaultWidth;
michael@0 601 *outHeight = mDefaultHeight;
michael@0 602 *outTransform = 0;
michael@0 603 }
michael@0 604 break;
michael@0 605 default:
michael@0 606 err = -EINVAL;
michael@0 607 break;
michael@0 608 }
michael@0 609 return err;
michael@0 610 }
michael@0 611
michael@0 612 status_t GonkNativeWindow::disconnect(int api) {
michael@0 613 CNW_LOGD("disconnect: api=%d", api);
michael@0 614
michael@0 615 int err = NO_ERROR;
michael@0 616 Mutex::Autolock lock(mMutex);
michael@0 617
michael@0 618 if (mAbandoned) {
michael@0 619 // it is not really an error to disconnect after the surface
michael@0 620 // has been abandoned, it should just be a no-op.
michael@0 621 return NO_ERROR;
michael@0 622 }
michael@0 623
michael@0 624 switch (api) {
michael@0 625 case NATIVE_WINDOW_API_EGL:
michael@0 626 case NATIVE_WINDOW_API_CPU:
michael@0 627 case NATIVE_WINDOW_API_MEDIA:
michael@0 628 case NATIVE_WINDOW_API_CAMERA:
michael@0 629 if (mConnectedApi == api) {
michael@0 630 mQueue.clear();
michael@0 631 freeAllBuffersLocked();
michael@0 632 mConnectedApi = NO_CONNECTED_API;
michael@0 633 mDequeueCondition.signal();
michael@0 634 } else {
michael@0 635 CNW_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
michael@0 636 mConnectedApi, api);
michael@0 637 err = -EINVAL;
michael@0 638 }
michael@0 639 break;
michael@0 640 default:
michael@0 641 CNW_LOGE("disconnect: unknown API %d", api);
michael@0 642 err = -EINVAL;
michael@0 643 break;
michael@0 644 }
michael@0 645 return err;
michael@0 646 }
michael@0 647
michael@0 648 status_t GonkNativeWindow::setScalingMode(int mode) {
michael@0 649 return OK;
michael@0 650 }
michael@0 651
michael@0 652 void GonkNativeWindow::setNewFrameCallback(
michael@0 653 GonkNativeWindowNewFrameCallback* aCallback) {
michael@0 654 CNW_LOGD("setNewFrameCallback");
michael@0 655 Mutex::Autolock lock(mMutex);
michael@0 656 mNewFrameCallback = aCallback;
michael@0 657 }
michael@0 658
michael@0 659 int GonkNativeWindow::query(int what, int* outValue)
michael@0 660 {
michael@0 661 Mutex::Autolock lock(mMutex);
michael@0 662
michael@0 663 if (mAbandoned) {
michael@0 664 CNW_LOGE("query: GonkNativeWindow has been abandoned!");
michael@0 665 return NO_INIT;
michael@0 666 }
michael@0 667
michael@0 668 int value;
michael@0 669 switch (what) {
michael@0 670 case NATIVE_WINDOW_WIDTH:
michael@0 671 value = mDefaultWidth;
michael@0 672 break;
michael@0 673 case NATIVE_WINDOW_HEIGHT:
michael@0 674 value = mDefaultHeight;
michael@0 675 break;
michael@0 676 case NATIVE_WINDOW_FORMAT:
michael@0 677 value = mPixelFormat;
michael@0 678 break;
michael@0 679 case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
michael@0 680 value = MIN_UNDEQUEUED_BUFFERS;
michael@0 681 break;
michael@0 682 default:
michael@0 683 return BAD_VALUE;
michael@0 684 }
michael@0 685 outValue[0] = value;
michael@0 686 return NO_ERROR;
michael@0 687 }

mercurial