widget/gonk/libui/SpriteController.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /*
     2  * Copyright (C) 2011 The Android Open Source Project
     3  *
     4  * Licensed under the Apache License, Version 2.0 (the "License");
     5  * you may not use this file except in compliance with the License.
     6  * You may obtain a copy of the License at
     7  *
     8  *      http://www.apache.org/licenses/LICENSE-2.0
     9  *
    10  * Unless required by applicable law or agreed to in writing, software
    11  * distributed under the License is distributed on an "AS IS" BASIS,
    12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  * See the License for the specific language governing permissions and
    14  * limitations under the License.
    15  */
    17 #define LOG_TAG "Sprites"
    19 //#define LOG_NDEBUG 0
    21 #include "SpriteController.h"
    23 #include "cutils_log.h"
    24 #include <utils/String8.h>
    25 #ifdef HAVE_ANDROID_OS
    26 #include <gui/Surface.h>
    27 #endif
    29 #include <SkBitmap.h>
    30 #include <SkCanvas.h>
    31 #include <SkColor.h>
    32 #include <SkPaint.h>
    33 #include <SkXfermode.h>
    34 #include <android/native_window.h>
    36 namespace android {
    38 // --- SpriteController ---
    40 SpriteController::SpriteController(const sp<Looper>& looper, int32_t overlayLayer) :
    41         mLooper(looper), mOverlayLayer(overlayLayer) {
    42 #ifdef HAVE_ANDROID_OS
    43     mHandler = new WeakMessageHandler(this);
    44 #endif
    46     mLocked.transactionNestingCount = 0;
    47     mLocked.deferredSpriteUpdate = false;
    48 }
    50 SpriteController::~SpriteController() {
    51 #ifdef HAVE_ANDROID_OS
    52     mLooper->removeMessages(mHandler);
    54     if (mSurfaceComposerClient != NULL) {
    55         mSurfaceComposerClient->dispose();
    56         mSurfaceComposerClient.clear();
    57     }
    58 #endif
    59 }
    61 sp<Sprite> SpriteController::createSprite() {
    62     return new SpriteImpl(this);
    63 }
    65 void SpriteController::openTransaction() {
    66     AutoMutex _l(mLock);
    68     mLocked.transactionNestingCount += 1;
    69 }
    71 void SpriteController::closeTransaction() {
    72     AutoMutex _l(mLock);
    74     LOG_ALWAYS_FATAL_IF(mLocked.transactionNestingCount == 0,
    75             "Sprite closeTransaction() called but there is no open sprite transaction");
    77     mLocked.transactionNestingCount -= 1;
    78     if (mLocked.transactionNestingCount == 0 && mLocked.deferredSpriteUpdate) {
    79         mLocked.deferredSpriteUpdate = false;
    80 #ifdef HAVE_ANDROID_OS
    81         mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES));
    82 #endif
    83     }
    84 }
    86 void SpriteController::invalidateSpriteLocked(const sp<SpriteImpl>& sprite) {
    87     bool wasEmpty = mLocked.invalidatedSprites.isEmpty();
    88     mLocked.invalidatedSprites.push(sprite);
    89     if (wasEmpty) {
    90         if (mLocked.transactionNestingCount != 0) {
    91             mLocked.deferredSpriteUpdate = true;
    92         } else {
    93 #ifdef HAVE_ANDROID_OS
    94             mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES));
    95 #endif
    96         }
    97     }
    98 }
   100 #ifdef HAVE_ANDROID_OS
   101 void SpriteController::disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl) {
   102     bool wasEmpty = mLocked.disposedSurfaces.isEmpty();
   103     mLocked.disposedSurfaces.push(surfaceControl);
   104     if (wasEmpty) {
   105         mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES));
   106     }
   107 }
   109 void SpriteController::handleMessage(const Message& message) {
   110     switch (message.what) {
   111     case MSG_UPDATE_SPRITES:
   112         doUpdateSprites();
   113         break;
   114     case MSG_DISPOSE_SURFACES:
   115         doDisposeSurfaces();
   116         break;
   117     }
   118 }
   119 #endif
   121 void SpriteController::doUpdateSprites() {
   122     // Collect information about sprite updates.
   123     // Each sprite update record includes a reference to its associated sprite so we can
   124     // be certain the sprites will not be deleted while this function runs.  Sprites
   125     // may invalidate themselves again during this time but we will handle those changes
   126     // in the next iteration.
   127     Vector<SpriteUpdate> updates;
   128     size_t numSprites;
   129     { // acquire lock
   130         AutoMutex _l(mLock);
   132         numSprites = mLocked.invalidatedSprites.size();
   133         for (size_t i = 0; i < numSprites; i++) {
   134             const sp<SpriteImpl>& sprite = mLocked.invalidatedSprites.itemAt(i);
   136             updates.push(SpriteUpdate(sprite, sprite->getStateLocked()));
   137             sprite->resetDirtyLocked();
   138         }
   139         mLocked.invalidatedSprites.clear();
   140     } // release lock
   142     // Create missing surfaces.
   143     bool surfaceChanged = false;
   144     for (size_t i = 0; i < numSprites; i++) {
   145         SpriteUpdate& update = updates.editItemAt(i);
   147 #ifdef HAVE_ANDROID_OS
   148         if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) {
   149             update.state.surfaceWidth = update.state.icon.bitmap.width();
   150             update.state.surfaceHeight = update.state.icon.bitmap.height();
   151             update.state.surfaceDrawn = false;
   152             update.state.surfaceVisible = false;
   153             update.state.surfaceControl = obtainSurface(
   154                     update.state.surfaceWidth, update.state.surfaceHeight);
   155             if (update.state.surfaceControl != NULL) {
   156                 update.surfaceChanged = surfaceChanged = true;
   157             }
   158         }
   159 #endif
   160     }
   162     // Resize sprites if needed, inside a global transaction.
   163     bool haveGlobalTransaction = false;
   164     for (size_t i = 0; i < numSprites; i++) {
   165         SpriteUpdate& update = updates.editItemAt(i);
   167 #ifdef HAVE_ANDROID_OS
   168         if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) {
   169             int32_t desiredWidth = update.state.icon.bitmap.width();
   170             int32_t desiredHeight = update.state.icon.bitmap.height();
   171             if (update.state.surfaceWidth < desiredWidth
   172                     || update.state.surfaceHeight < desiredHeight) {
   173                 if (!haveGlobalTransaction) {
   174                     SurfaceComposerClient::openGlobalTransaction();
   175                     haveGlobalTransaction = true;
   176                 }
   178                 status_t status = update.state.surfaceControl->setSize(desiredWidth, desiredHeight);
   179                 if (status) {
   180                     ALOGE("Error %d resizing sprite surface from %dx%d to %dx%d",
   181                             status, update.state.surfaceWidth, update.state.surfaceHeight,
   182                             desiredWidth, desiredHeight);
   183                 } else {
   184                     update.state.surfaceWidth = desiredWidth;
   185                     update.state.surfaceHeight = desiredHeight;
   186                     update.state.surfaceDrawn = false;
   187                     update.surfaceChanged = surfaceChanged = true;
   189                     if (update.state.surfaceVisible) {
   190                         status = update.state.surfaceControl->hide();
   191                         if (status) {
   192                             ALOGE("Error %d hiding sprite surface after resize.", status);
   193                         } else {
   194                             update.state.surfaceVisible = false;
   195                         }
   196                     }
   197                 }
   198             }
   199         }
   200 #endif
   201     }
   202 #ifdef HAVE_ANDROID_OS
   203     if (haveGlobalTransaction) {
   204         SurfaceComposerClient::closeGlobalTransaction();
   205     }
   206 #endif
   208     // Redraw sprites if needed.
   209     for (size_t i = 0; i < numSprites; i++) {
   210         SpriteUpdate& update = updates.editItemAt(i);
   212         if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) {
   213             update.state.surfaceDrawn = false;
   214             update.surfaceChanged = surfaceChanged = true;
   215         }
   217 #ifdef HAVE_ANDROID_OS
   218         if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn
   219                 && update.state.wantSurfaceVisible()) {
   220             sp<Surface> surface = update.state.surfaceControl->getSurface();
   221             ANativeWindow_Buffer outBuffer;
   222             status_t status = surface->lock(&outBuffer, NULL);
   223             if (status) {
   224                 ALOGE("Error %d locking sprite surface before drawing.", status);
   225             } else {
   226                 SkBitmap surfaceBitmap;
   227                 ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
   228                 surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config,
   229                         outBuffer.width, outBuffer.height, bpr);
   230                 surfaceBitmap.setPixels(outBuffer.bits);
   232                 SkCanvas surfaceCanvas(surfaceBitmap);
   234                 SkPaint paint;
   235                 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
   236                 surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint);
   238                 if (outBuffer.width > uint32_t(update.state.icon.bitmap.width())) {
   239                     paint.setColor(0); // transparent fill color
   240                     surfaceCanvas.drawRectCoords(update.state.icon.bitmap.width(), 0,
   241                             outBuffer.width, update.state.icon.bitmap.height(), paint);
   242                 }
   243                 if (outBuffer.height > uint32_t(update.state.icon.bitmap.height())) {
   244                     paint.setColor(0); // transparent fill color
   245                     surfaceCanvas.drawRectCoords(0, update.state.icon.bitmap.height(),
   246                             outBuffer.width, outBuffer.height, paint);
   247                 }
   249                 status = surface->unlockAndPost();
   250                 if (status) {
   251                     ALOGE("Error %d unlocking and posting sprite surface after drawing.", status);
   252                 } else {
   253                     update.state.surfaceDrawn = true;
   254                     update.surfaceChanged = surfaceChanged = true;
   255                 }
   256             }
   257         }
   258 #endif
   259     }
   261     // Set sprite surface properties and make them visible.
   262     bool haveTransaction = false;
   263     for (size_t i = 0; i < numSprites; i++) {
   264         SpriteUpdate& update = updates.editItemAt(i);
   266         bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible()
   267                 && update.state.surfaceDrawn;
   268         bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible;
   269         bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible;
   270 #ifdef HAVE_ANDROID_OS
   271         if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden
   272                 || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA
   273                         | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER
   274                         | DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) {
   275             status_t status;
   276             if (!haveTransaction) {
   277                 SurfaceComposerClient::openGlobalTransaction();
   278                 haveTransaction = true;
   279             }
   281             if (wantSurfaceVisibleAndDrawn
   282                     && (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) {
   283                 status = update.state.surfaceControl->setAlpha(update.state.alpha);
   284                 if (status) {
   285                     ALOGE("Error %d setting sprite surface alpha.", status);
   286                 }
   287             }
   289             if (wantSurfaceVisibleAndDrawn
   290                     && (becomingVisible || (update.state.dirty & (DIRTY_POSITION
   291                             | DIRTY_HOTSPOT)))) {
   292                 status = update.state.surfaceControl->setPosition(
   293                         update.state.positionX - update.state.icon.hotSpotX,
   294                         update.state.positionY - update.state.icon.hotSpotY);
   295                 if (status) {
   296                     ALOGE("Error %d setting sprite surface position.", status);
   297                 }
   298             }
   300             if (wantSurfaceVisibleAndDrawn
   301                     && (becomingVisible
   302                             || (update.state.dirty & DIRTY_TRANSFORMATION_MATRIX))) {
   303                 status = update.state.surfaceControl->setMatrix(
   304                         update.state.transformationMatrix.dsdx,
   305                         update.state.transformationMatrix.dtdx,
   306                         update.state.transformationMatrix.dsdy,
   307                         update.state.transformationMatrix.dtdy);
   308                 if (status) {
   309                     ALOGE("Error %d setting sprite surface transformation matrix.", status);
   310                 }
   311             }
   313             int32_t surfaceLayer = mOverlayLayer + update.state.layer;
   314             if (wantSurfaceVisibleAndDrawn
   315                     && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) {
   316                 status = update.state.surfaceControl->setLayer(surfaceLayer);
   317                 if (status) {
   318                     ALOGE("Error %d setting sprite surface layer.", status);
   319                 }
   320             }
   322             if (becomingVisible) {
   323                 status = update.state.surfaceControl->show();
   324                 if (status) {
   325                     ALOGE("Error %d showing sprite surface.", status);
   326                 } else {
   327                     update.state.surfaceVisible = true;
   328                     update.surfaceChanged = surfaceChanged = true;
   329                 }
   330             } else if (becomingHidden) {
   331                 status = update.state.surfaceControl->hide();
   332                 if (status) {
   333                     ALOGE("Error %d hiding sprite surface.", status);
   334                 } else {
   335                     update.state.surfaceVisible = false;
   336                     update.surfaceChanged = surfaceChanged = true;
   337                 }
   338             }
   339         }
   340 #endif
   341     }
   343 #ifdef HAVE_ANDROID_OS
   344     if (haveTransaction) {
   345         SurfaceComposerClient::closeGlobalTransaction();
   346     }
   347 #endif
   349     // If any surfaces were changed, write back the new surface properties to the sprites.
   350     if (surfaceChanged) { // acquire lock
   351         AutoMutex _l(mLock);
   353         for (size_t i = 0; i < numSprites; i++) {
   354             const SpriteUpdate& update = updates.itemAt(i);
   356 #ifdef HAVE_ANDROID_OS
   357             if (update.surfaceChanged) {
   358                 update.sprite->setSurfaceLocked(update.state.surfaceControl,
   359                         update.state.surfaceWidth, update.state.surfaceHeight,
   360                         update.state.surfaceDrawn, update.state.surfaceVisible);
   361             }
   362 #endif
   363         }
   364     } // release lock
   366     // Clear the sprite update vector outside the lock.  It is very important that
   367     // we do not clear sprite references inside the lock since we could be releasing
   368     // the last remaining reference to the sprite here which would result in the
   369     // sprite being deleted and the lock being reacquired by the sprite destructor
   370     // while already held.
   371     updates.clear();
   372 }
   374 void SpriteController::doDisposeSurfaces() {
   375 #ifdef HAVE_ANDROID_OS
   376     // Collect disposed surfaces.
   377     Vector<sp<SurfaceControl> > disposedSurfaces;
   378     { // acquire lock
   379         AutoMutex _l(mLock);
   381         disposedSurfaces = mLocked.disposedSurfaces;
   382         mLocked.disposedSurfaces.clear();
   383     } // release lock
   385     // Release the last reference to each surface outside of the lock.
   386     // We don't want the surfaces to be deleted while we are holding our lock.
   387     disposedSurfaces.clear();
   388 #endif
   389 }
   391 void SpriteController::ensureSurfaceComposerClient() {
   392 #ifdef HAVE_ANDROID_OS
   393     if (mSurfaceComposerClient == NULL) {
   394         mSurfaceComposerClient = new SurfaceComposerClient();
   395     }
   396 #endif
   397 }
   399 #ifdef HAVE_ANDROID_OS
   400 sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height) {
   401     ensureSurfaceComposerClient();
   403     sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface(
   404             String8("Sprite"), width, height, PIXEL_FORMAT_RGBA_8888,
   405             ISurfaceComposerClient::eHidden);
   406     if (surfaceControl == NULL || !surfaceControl->isValid()) {
   407         ALOGE("Error creating sprite surface.");
   408         return NULL;
   409     }
   410     return surfaceControl;
   411 }
   412 #endif
   415 // --- SpriteController::SpriteImpl ---
   417 SpriteController::SpriteImpl::SpriteImpl(const sp<SpriteController> controller) :
   418         mController(controller) {
   419 }
   421 SpriteController::SpriteImpl::~SpriteImpl() {
   422     AutoMutex _m(mController->mLock);
   424 #ifdef HAVE_ANDROID_OS
   425     // Let the controller take care of deleting the last reference to sprite
   426     // surfaces so that we do not block the caller on an IPC here.
   427     if (mLocked.state.surfaceControl != NULL) {
   428         mController->disposeSurfaceLocked(mLocked.state.surfaceControl);
   429         mLocked.state.surfaceControl.clear();
   430     }
   431 #endif
   432 }
   434 void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) {
   435     AutoMutex _l(mController->mLock);
   437 #ifdef HAVE_ANDROID_OS
   438     uint32_t dirty;
   439     if (icon.isValid()) {
   440         icon.bitmap.copyTo(&mLocked.state.icon.bitmap, SkBitmap::kARGB_8888_Config);
   442         if (!mLocked.state.icon.isValid()
   443                 || mLocked.state.icon.hotSpotX != icon.hotSpotX
   444                 || mLocked.state.icon.hotSpotY != icon.hotSpotY) {
   445             mLocked.state.icon.hotSpotX = icon.hotSpotX;
   446             mLocked.state.icon.hotSpotY = icon.hotSpotY;
   447             dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
   448         } else {
   449             dirty = DIRTY_BITMAP;
   450         }
   451     } else if (mLocked.state.icon.isValid()) {
   452         mLocked.state.icon.bitmap.reset();
   453         dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
   454     } else {
   455         return; // setting to invalid icon and already invalid so nothing to do
   456     }
   458     invalidateLocked(dirty);
   459 #endif
   460 }
   462 void SpriteController::SpriteImpl::setVisible(bool visible) {
   463     AutoMutex _l(mController->mLock);
   465     if (mLocked.state.visible != visible) {
   466         mLocked.state.visible = visible;
   467         invalidateLocked(DIRTY_VISIBILITY);
   468     }
   469 }
   471 void SpriteController::SpriteImpl::setPosition(float x, float y) {
   472     AutoMutex _l(mController->mLock);
   474     if (mLocked.state.positionX != x || mLocked.state.positionY != y) {
   475         mLocked.state.positionX = x;
   476         mLocked.state.positionY = y;
   477         invalidateLocked(DIRTY_POSITION);
   478     }
   479 }
   481 void SpriteController::SpriteImpl::setLayer(int32_t layer) {
   482     AutoMutex _l(mController->mLock);
   484     if (mLocked.state.layer != layer) {
   485         mLocked.state.layer = layer;
   486         invalidateLocked(DIRTY_LAYER);
   487     }
   488 }
   490 void SpriteController::SpriteImpl::setAlpha(float alpha) {
   491     AutoMutex _l(mController->mLock);
   493     if (mLocked.state.alpha != alpha) {
   494         mLocked.state.alpha = alpha;
   495         invalidateLocked(DIRTY_ALPHA);
   496     }
   497 }
   499 void SpriteController::SpriteImpl::setTransformationMatrix(
   500         const SpriteTransformationMatrix& matrix) {
   501     AutoMutex _l(mController->mLock);
   503     if (mLocked.state.transformationMatrix != matrix) {
   504         mLocked.state.transformationMatrix = matrix;
   505         invalidateLocked(DIRTY_TRANSFORMATION_MATRIX);
   506     }
   507 }
   509 void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) {
   510     bool wasDirty = mLocked.state.dirty;
   511     mLocked.state.dirty |= dirty;
   513     if (!wasDirty) {
   514         mController->invalidateSpriteLocked(this);
   515     }
   516 }
   518 } // namespace android

mercurial