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

     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  */
    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"
    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__);}
    35 using namespace android;
    36 using namespace mozilla;
    37 using namespace mozilla::gfx;
    38 using namespace mozilla::layers;
    40 class nsProxyReleaseTask : public CancelableTask
    41 {
    42 public:
    43     nsProxyReleaseTask(TextureClient* aClient)
    44         : mTextureClient(aClient) {
    45     }
    47     virtual void Run() MOZ_OVERRIDE
    48     {
    49         mTextureClient = nullptr;
    50     }
    52     virtual void Cancel() MOZ_OVERRIDE {}
    54 private:
    55     mozilla::RefPtr<TextureClient> mTextureClient;
    56 };
    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 }
    69 GonkNativeWindow::~GonkNativeWindow() {
    70     freeAllBuffersLocked();
    71 }
    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 }
    83 void GonkNativeWindow::freeAllBuffersLocked()
    84 {
    85     CNW_LOGD("freeAllBuffersLocked");
    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 }
   103 void GonkNativeWindow::clearRenderingStateBuffersLocked()
   104 {
   105     CNW_LOGD("clearRenderingStateBuffersLocked");
   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 }
   126 status_t GonkNativeWindow::setBufferCount(int bufferCount)
   127 {
   128     CNW_LOGD("setBufferCount: count=%d", bufferCount);
   129     Mutex::Autolock lock(mMutex);
   131     if (mAbandoned) {
   132         CNW_LOGE("setBufferCount: GonkNativeWindow has been abandoned!");
   133         return NO_INIT;
   134     }
   136     if (bufferCount > NUM_BUFFER_SLOTS) {
   137         CNW_LOGE("setBufferCount: bufferCount larger than slots available");
   138         return BAD_VALUE;
   139     }
   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     }
   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     }
   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     }
   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 }
   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     }
   182     Mutex::Autolock lock(mMutex);
   183     mDefaultWidth = w;
   184     mDefaultHeight = h;
   185     return OK;
   186 }
   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 }
   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     }
   214     status_t returnFlags(OK);
   215     bool updateFormat = false;
   216     bool alloc = false;
   217     int buf = INVALID_BUFFER_SLOT;
   219     {
   220         Mutex::Autolock lock(mMutex);
   222         int found = -1;
   223         int dequeuedCount = 0;
   224         int renderingCount = 0;
   225         bool tryAgain = true;
   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;
   245                     case BufferSlot::RENDERING:
   246                         CNW_LOGD("dequeueBuffer: slot %d is RENDERING\n", i);
   247                         renderingCount++;
   248                         break;
   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;
   263                     default:
   264                         CNW_LOGD("dequeueBuffer: slot %d is %d\n", i, state);
   265                         break;
   266                 }
   267             }
   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             }
   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         }
   295         if (found == INVALID_BUFFER_SLOT) {
   296             // This should not happen.
   297             CNW_LOGE("dequeueBuffer: no available buffer slots");
   298             return -EBUSY;
   299         }
   301         buf = found;
   302         *outBuf = found;
   304         const bool useDefaultSize = !w && !h;
   305         if (useDefaultSize) {
   306             // use the default size
   307             w = mDefaultWidth;
   308             h = mDefaultHeight;
   309         }
   311         updateFormat = (format != 0);
   312         if (!updateFormat) {
   313             // keep the current (or default) format
   314             format = mPixelFormat;
   315         }
   317         mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
   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
   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         }
   353         { // Scope for the lock
   354             Mutex::Autolock lock(mMutex);
   356             if (mAbandoned) {
   357                 CNW_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
   358                 return NO_INIT;
   359             }
   361             if (updateFormat) {
   362                 mPixelFormat = format;
   363             }
   364             mSlots[buf].mGraphicBuffer = graphicBuffer;
   365             mSlots[buf].mTextureClient = textureClient;
   367             returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
   369             CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
   370                     mSlots[buf].mGraphicBuffer->handle);
   371         }
   372     }
   374     CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
   375             mSlots[buf].mGraphicBuffer->handle );
   377     CNW_LOGD("dequeueBuffer: X");
   378     return returnFlags;
   379 }
   381 status_t GonkNativeWindow::setSynchronousMode(bool enabled)
   382 {
   383     return NO_ERROR;
   384 }
   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     }
   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 }
   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     }
   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 }
   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   }
   429   return mSlots[buf].mTextureClient;
   430 }
   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);
   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         }
   458         mQueue.push_back(buf);
   460         mSlots[buf].mBufferState = BufferSlot::QUEUED;
   461         mSlots[buf].mTimestamp = timestamp;
   462         mFrameCounter++;
   463         mSlots[buf].mFrameNumber = mFrameCounter;
   465         mDequeueCondition.signal();
   467         *outWidth = mDefaultWidth;
   468         *outHeight = mDefaultHeight;
   469         *outTransform = 0;
   470     }
   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 }
   482 TemporaryRef<TextureClient>
   483 GonkNativeWindow::getCurrentBuffer() {
   484   CNW_LOGD("GonkNativeWindow::getCurrentBuffer");
   485   Mutex::Autolock lock(mMutex);
   487   if (mAbandoned) {
   488     CNW_LOGE("getCurrentBuffer: GonkNativeWindow has been abandoned!");
   489     return NULL;
   490   }
   492   if(mQueue.empty()) {
   493     mDequeueCondition.signal();
   494     return nullptr;
   495   }
   497   Fifo::iterator front(mQueue.begin());
   498   int buf = *front;
   499   CNW_LOGD("getCurrentBuffer: buf=%d", buf);
   501   mSlots[buf].mBufferState = BufferSlot::RENDERING;
   503   mQueue.erase(front);
   504   mDequeueCondition.signal();
   506   mSlots[buf].mTextureClient->SetRecycleCallback(GonkNativeWindow::RecycleCallback, this);
   507   return mSlots[buf].mTextureClient;
   508 }
   511 /* static */ void
   512 GonkNativeWindow::RecycleCallback(TextureClient* client, void* closure) {
   513   GonkNativeWindow* nativeWindow =
   514     static_cast<GonkNativeWindow*>(closure);
   516   client->ClearRecycleCallback();
   517   nativeWindow->returnBuffer(client);
   518 }
   520 void GonkNativeWindow::returnBuffer(TextureClient* client) {
   521   CNW_LOGD("GonkNativeWindow::returnBuffer");
   522   Mutex::Autolock lock(mMutex);
   524   if (mAbandoned) {
   525     CNW_LOGD("returnBuffer: GonkNativeWindow has been abandoned!");
   526     return;
   527   }
   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   }
   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   }
   542   mSlots[index].mBufferState = BufferSlot::FREE;
   543   mDequeueCondition.signal();
   544   return;
   545 }
   547 void GonkNativeWindow::cancelBuffer(int buf) {
   548     CNW_LOGD("cancelBuffer: slot=%d", buf);
   549     Mutex::Autolock lock(mMutex);
   551     if (mAbandoned) {
   552         CNW_LOGD("cancelBuffer: GonkNativeWindow has been abandoned!");
   553         return;
   554     }
   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 }
   570 status_t GonkNativeWindow::setCrop(const Rect& crop) {
   571     return OK;
   572 }
   574 status_t GonkNativeWindow::setTransform(uint32_t transform) {
   575     return OK;
   576 }
   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);
   583     if (mAbandoned) {
   584         CNW_LOGE("connect: GonkNativeWindow has been abandoned!");
   585         return NO_INIT;
   586     }
   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 }
   612 status_t GonkNativeWindow::disconnect(int api) {
   613     CNW_LOGD("disconnect: api=%d", api);
   615     int err = NO_ERROR;
   616     Mutex::Autolock lock(mMutex);
   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     }
   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 }
   648 status_t GonkNativeWindow::setScalingMode(int mode) {
   649     return OK;
   650 }
   652 void GonkNativeWindow::setNewFrameCallback(
   653         GonkNativeWindowNewFrameCallback* aCallback) {
   654     CNW_LOGD("setNewFrameCallback");
   655     Mutex::Autolock lock(mMutex);
   656     mNewFrameCallback = aCallback;
   657 }
   659 int GonkNativeWindow::query(int what, int* outValue)
   660 {
   661     Mutex::Autolock lock(mMutex);
   663     if (mAbandoned) {
   664         CNW_LOGE("query: GonkNativeWindow has been abandoned!");
   665         return NO_INIT;
   666     }
   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