widget/gonk/nativewindow/GonkNativeWindowICS.cpp

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

mercurial