Home | History | Annotate | Download | only in input
      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  */
     16 
     17 #define LOG_TAG "Sprites"
     18 //#define LOG_NDEBUG 0
     19 
     20 #include "SpriteController.h"
     21 
     22 #include <log/log.h>
     23 #include <utils/String8.h>
     24 #include <gui/Surface.h>
     25 
     26 #include <SkBitmap.h>
     27 #include <SkCanvas.h>
     28 #include <SkColor.h>
     29 #include <SkPaint.h>
     30 
     31 #include <android/native_window.h>
     32 
     33 namespace android {
     34 
     35 // --- SpriteController ---
     36 
     37 SpriteController::SpriteController(const sp<Looper>& looper, int32_t overlayLayer) :
     38         mLooper(looper), mOverlayLayer(overlayLayer) {
     39     mHandler = new WeakMessageHandler(this);
     40 
     41     mLocked.transactionNestingCount = 0;
     42     mLocked.deferredSpriteUpdate = false;
     43 }
     44 
     45 SpriteController::~SpriteController() {
     46     mLooper->removeMessages(mHandler);
     47 
     48     if (mSurfaceComposerClient != NULL) {
     49         mSurfaceComposerClient->dispose();
     50         mSurfaceComposerClient.clear();
     51     }
     52 }
     53 
     54 sp<Sprite> SpriteController::createSprite() {
     55     return new SpriteImpl(this);
     56 }
     57 
     58 void SpriteController::openTransaction() {
     59     AutoMutex _l(mLock);
     60 
     61     mLocked.transactionNestingCount += 1;
     62 }
     63 
     64 void SpriteController::closeTransaction() {
     65     AutoMutex _l(mLock);
     66 
     67     LOG_ALWAYS_FATAL_IF(mLocked.transactionNestingCount == 0,
     68             "Sprite closeTransaction() called but there is no open sprite transaction");
     69 
     70     mLocked.transactionNestingCount -= 1;
     71     if (mLocked.transactionNestingCount == 0 && mLocked.deferredSpriteUpdate) {
     72         mLocked.deferredSpriteUpdate = false;
     73         mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES));
     74     }
     75 }
     76 
     77 void SpriteController::invalidateSpriteLocked(const sp<SpriteImpl>& sprite) {
     78     bool wasEmpty = mLocked.invalidatedSprites.isEmpty();
     79     mLocked.invalidatedSprites.push(sprite);
     80     if (wasEmpty) {
     81         if (mLocked.transactionNestingCount != 0) {
     82             mLocked.deferredSpriteUpdate = true;
     83         } else {
     84             mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES));
     85         }
     86     }
     87 }
     88 
     89 void SpriteController::disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl) {
     90     bool wasEmpty = mLocked.disposedSurfaces.isEmpty();
     91     mLocked.disposedSurfaces.push(surfaceControl);
     92     if (wasEmpty) {
     93         mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES));
     94     }
     95 }
     96 
     97 void SpriteController::handleMessage(const Message& message) {
     98     switch (message.what) {
     99     case MSG_UPDATE_SPRITES:
    100         doUpdateSprites();
    101         break;
    102     case MSG_DISPOSE_SURFACES:
    103         doDisposeSurfaces();
    104         break;
    105     }
    106 }
    107 
    108 void SpriteController::doUpdateSprites() {
    109     // Collect information about sprite updates.
    110     // Each sprite update record includes a reference to its associated sprite so we can
    111     // be certain the sprites will not be deleted while this function runs.  Sprites
    112     // may invalidate themselves again during this time but we will handle those changes
    113     // in the next iteration.
    114     Vector<SpriteUpdate> updates;
    115     size_t numSprites;
    116     { // acquire lock
    117         AutoMutex _l(mLock);
    118 
    119         numSprites = mLocked.invalidatedSprites.size();
    120         for (size_t i = 0; i < numSprites; i++) {
    121             const sp<SpriteImpl>& sprite = mLocked.invalidatedSprites.itemAt(i);
    122 
    123             updates.push(SpriteUpdate(sprite, sprite->getStateLocked()));
    124             sprite->resetDirtyLocked();
    125         }
    126         mLocked.invalidatedSprites.clear();
    127     } // release lock
    128 
    129     // Create missing surfaces.
    130     bool surfaceChanged = false;
    131     for (size_t i = 0; i < numSprites; i++) {
    132         SpriteUpdate& update = updates.editItemAt(i);
    133 
    134         if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) {
    135             update.state.surfaceWidth = update.state.icon.bitmap.width();
    136             update.state.surfaceHeight = update.state.icon.bitmap.height();
    137             update.state.surfaceDrawn = false;
    138             update.state.surfaceVisible = false;
    139             update.state.surfaceControl = obtainSurface(
    140                     update.state.surfaceWidth, update.state.surfaceHeight);
    141             if (update.state.surfaceControl != NULL) {
    142                 update.surfaceChanged = surfaceChanged = true;
    143             }
    144         }
    145     }
    146 
    147     // Resize and/or reparent sprites if needed.
    148     SurfaceComposerClient::Transaction t;
    149     bool needApplyTransaction = false;
    150     for (size_t i = 0; i < numSprites; i++) {
    151         SpriteUpdate& update = updates.editItemAt(i);
    152         if (update.state.surfaceControl == nullptr) {
    153             continue;
    154         }
    155 
    156         if (update.state.wantSurfaceVisible()) {
    157             int32_t desiredWidth = update.state.icon.bitmap.width();
    158             int32_t desiredHeight = update.state.icon.bitmap.height();
    159             if (update.state.surfaceWidth < desiredWidth
    160                     || update.state.surfaceHeight < desiredHeight) {
    161                 needApplyTransaction = true;
    162 
    163                 t.setSize(update.state.surfaceControl,
    164                         desiredWidth, desiredHeight);
    165                 update.state.surfaceWidth = desiredWidth;
    166                 update.state.surfaceHeight = desiredHeight;
    167                 update.state.surfaceDrawn = false;
    168                 update.surfaceChanged = surfaceChanged = true;
    169 
    170                 if (update.state.surfaceVisible) {
    171                     t.hide(update.state.surfaceControl);
    172                     update.state.surfaceVisible = false;
    173                 }
    174             }
    175         }
    176 
    177         // If surface is a new one, we have to set right layer stack.
    178         if (update.surfaceChanged || update.state.dirty & DIRTY_DISPLAY_ID) {
    179             t.setLayerStack(update.state.surfaceControl, update.state.displayId);
    180             needApplyTransaction = true;
    181         }
    182     }
    183     if (needApplyTransaction) {
    184         t.apply();
    185     }
    186 
    187     // Redraw sprites if needed.
    188     for (size_t i = 0; i < numSprites; i++) {
    189         SpriteUpdate& update = updates.editItemAt(i);
    190 
    191         if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) {
    192             update.state.surfaceDrawn = false;
    193             update.surfaceChanged = surfaceChanged = true;
    194         }
    195 
    196         if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn
    197                 && update.state.wantSurfaceVisible()) {
    198             sp<Surface> surface = update.state.surfaceControl->getSurface();
    199             ANativeWindow_Buffer outBuffer;
    200             status_t status = surface->lock(&outBuffer, NULL);
    201             if (status) {
    202                 ALOGE("Error %d locking sprite surface before drawing.", status);
    203             } else {
    204                 SkBitmap surfaceBitmap;
    205                 ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
    206                 surfaceBitmap.installPixels(SkImageInfo::MakeN32Premul(outBuffer.width, outBuffer.height),
    207                                             outBuffer.bits, bpr);
    208 
    209                 SkCanvas surfaceCanvas(surfaceBitmap);
    210 
    211                 SkPaint paint;
    212                 paint.setBlendMode(SkBlendMode::kSrc);
    213                 surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint);
    214 
    215                 if (outBuffer.width > update.state.icon.bitmap.width()) {
    216                     paint.setColor(0); // transparent fill color
    217                     surfaceCanvas.drawRect(SkRect::MakeLTRB(update.state.icon.bitmap.width(), 0,
    218                             outBuffer.width, update.state.icon.bitmap.height()), paint);
    219                 }
    220                 if (outBuffer.height > update.state.icon.bitmap.height()) {
    221                     paint.setColor(0); // transparent fill color
    222                     surfaceCanvas.drawRect(SkRect::MakeLTRB(0, update.state.icon.bitmap.height(),
    223                             outBuffer.width, outBuffer.height), paint);
    224                 }
    225 
    226                 status = surface->unlockAndPost();
    227                 if (status) {
    228                     ALOGE("Error %d unlocking and posting sprite surface after drawing.", status);
    229                 } else {
    230                     update.state.surfaceDrawn = true;
    231                     update.surfaceChanged = surfaceChanged = true;
    232                 }
    233             }
    234         }
    235     }
    236 
    237     needApplyTransaction = false;
    238     for (size_t i = 0; i < numSprites; i++) {
    239         SpriteUpdate& update = updates.editItemAt(i);
    240 
    241         bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible()
    242                 && update.state.surfaceDrawn;
    243         bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible;
    244         bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible;
    245         if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden
    246                 || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA
    247                         | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER
    248                         | DIRTY_VISIBILITY | DIRTY_HOTSPOT | DIRTY_DISPLAY_ID))))) {
    249             needApplyTransaction = true;
    250 
    251             if (wantSurfaceVisibleAndDrawn
    252                     && (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) {
    253                 t.setAlpha(update.state.surfaceControl,
    254                         update.state.alpha);
    255             }
    256 
    257             if (wantSurfaceVisibleAndDrawn
    258                     && (becomingVisible || (update.state.dirty & (DIRTY_POSITION
    259                             | DIRTY_HOTSPOT)))) {
    260                 t.setPosition(
    261                         update.state.surfaceControl,
    262                         update.state.positionX - update.state.icon.hotSpotX,
    263                         update.state.positionY - update.state.icon.hotSpotY);
    264             }
    265 
    266             if (wantSurfaceVisibleAndDrawn
    267                     && (becomingVisible
    268                             || (update.state.dirty & DIRTY_TRANSFORMATION_MATRIX))) {
    269                 t.setMatrix(
    270                         update.state.surfaceControl,
    271                         update.state.transformationMatrix.dsdx,
    272                         update.state.transformationMatrix.dtdx,
    273                         update.state.transformationMatrix.dsdy,
    274                         update.state.transformationMatrix.dtdy);
    275             }
    276 
    277             int32_t surfaceLayer = mOverlayLayer + update.state.layer;
    278             if (wantSurfaceVisibleAndDrawn
    279                     && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) {
    280                 t.setLayer(update.state.surfaceControl, surfaceLayer);
    281             }
    282 
    283             if (becomingVisible) {
    284                 t.show(update.state.surfaceControl);
    285 
    286                 update.state.surfaceVisible = true;
    287                 update.surfaceChanged = surfaceChanged = true;
    288             } else if (becomingHidden) {
    289                 t.hide(update.state.surfaceControl);
    290 
    291                 update.state.surfaceVisible = false;
    292                 update.surfaceChanged = surfaceChanged = true;
    293             }
    294         }
    295     }
    296 
    297     if (needApplyTransaction) {
    298         status_t status = t.apply();
    299         if (status) {
    300             ALOGE("Error applying Surface transaction");
    301         }
    302     }
    303 
    304     // If any surfaces were changed, write back the new surface properties to the sprites.
    305     if (surfaceChanged) { // acquire lock
    306         AutoMutex _l(mLock);
    307 
    308         for (size_t i = 0; i < numSprites; i++) {
    309             const SpriteUpdate& update = updates.itemAt(i);
    310 
    311             if (update.surfaceChanged) {
    312                 update.sprite->setSurfaceLocked(update.state.surfaceControl,
    313                         update.state.surfaceWidth, update.state.surfaceHeight,
    314                         update.state.surfaceDrawn, update.state.surfaceVisible);
    315             }
    316         }
    317     } // release lock
    318 
    319     // Clear the sprite update vector outside the lock.  It is very important that
    320     // we do not clear sprite references inside the lock since we could be releasing
    321     // the last remaining reference to the sprite here which would result in the
    322     // sprite being deleted and the lock being reacquired by the sprite destructor
    323     // while already held.
    324     updates.clear();
    325 }
    326 
    327 void SpriteController::doDisposeSurfaces() {
    328     // Collect disposed surfaces.
    329     Vector<sp<SurfaceControl> > disposedSurfaces;
    330     { // acquire lock
    331         AutoMutex _l(mLock);
    332 
    333         disposedSurfaces = mLocked.disposedSurfaces;
    334         mLocked.disposedSurfaces.clear();
    335     } // release lock
    336 
    337     // Release the last reference to each surface outside of the lock.
    338     // We don't want the surfaces to be deleted while we are holding our lock.
    339     disposedSurfaces.clear();
    340 }
    341 
    342 void SpriteController::ensureSurfaceComposerClient() {
    343     if (mSurfaceComposerClient == NULL) {
    344         mSurfaceComposerClient = new SurfaceComposerClient();
    345     }
    346 }
    347 
    348 sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height) {
    349     ensureSurfaceComposerClient();
    350 
    351     sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface(
    352             String8("Sprite"), width, height, PIXEL_FORMAT_RGBA_8888,
    353             ISurfaceComposerClient::eHidden |
    354             ISurfaceComposerClient::eCursorWindow);
    355     if (surfaceControl == NULL || !surfaceControl->isValid()) {
    356         ALOGE("Error creating sprite surface.");
    357         return NULL;
    358     }
    359     return surfaceControl;
    360 }
    361 
    362 
    363 // --- SpriteController::SpriteImpl ---
    364 
    365 SpriteController::SpriteImpl::SpriteImpl(const sp<SpriteController> controller) :
    366         mController(controller) {
    367 }
    368 
    369 SpriteController::SpriteImpl::~SpriteImpl() {
    370     AutoMutex _m(mController->mLock);
    371 
    372     // Let the controller take care of deleting the last reference to sprite
    373     // surfaces so that we do not block the caller on an IPC here.
    374     if (mLocked.state.surfaceControl != NULL) {
    375         mController->disposeSurfaceLocked(mLocked.state.surfaceControl);
    376         mLocked.state.surfaceControl.clear();
    377     }
    378 }
    379 
    380 void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) {
    381     AutoMutex _l(mController->mLock);
    382 
    383     uint32_t dirty;
    384     if (icon.isValid()) {
    385         SkBitmap* bitmapCopy = &mLocked.state.icon.bitmap;
    386         if (bitmapCopy->tryAllocPixels(icon.bitmap.info().makeColorType(kN32_SkColorType))) {
    387             icon.bitmap.readPixels(bitmapCopy->info(), bitmapCopy->getPixels(),
    388                     bitmapCopy->rowBytes(), 0, 0);
    389         }
    390 
    391         if (!mLocked.state.icon.isValid()
    392                 || mLocked.state.icon.hotSpotX != icon.hotSpotX
    393                 || mLocked.state.icon.hotSpotY != icon.hotSpotY) {
    394             mLocked.state.icon.hotSpotX = icon.hotSpotX;
    395             mLocked.state.icon.hotSpotY = icon.hotSpotY;
    396             dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
    397         } else {
    398             dirty = DIRTY_BITMAP;
    399         }
    400     } else if (mLocked.state.icon.isValid()) {
    401         mLocked.state.icon.bitmap.reset();
    402         dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
    403     } else {
    404         return; // setting to invalid icon and already invalid so nothing to do
    405     }
    406 
    407     invalidateLocked(dirty);
    408 }
    409 
    410 void SpriteController::SpriteImpl::setVisible(bool visible) {
    411     AutoMutex _l(mController->mLock);
    412 
    413     if (mLocked.state.visible != visible) {
    414         mLocked.state.visible = visible;
    415         invalidateLocked(DIRTY_VISIBILITY);
    416     }
    417 }
    418 
    419 void SpriteController::SpriteImpl::setPosition(float x, float y) {
    420     AutoMutex _l(mController->mLock);
    421 
    422     if (mLocked.state.positionX != x || mLocked.state.positionY != y) {
    423         mLocked.state.positionX = x;
    424         mLocked.state.positionY = y;
    425         invalidateLocked(DIRTY_POSITION);
    426     }
    427 }
    428 
    429 void SpriteController::SpriteImpl::setLayer(int32_t layer) {
    430     AutoMutex _l(mController->mLock);
    431 
    432     if (mLocked.state.layer != layer) {
    433         mLocked.state.layer = layer;
    434         invalidateLocked(DIRTY_LAYER);
    435     }
    436 }
    437 
    438 void SpriteController::SpriteImpl::setAlpha(float alpha) {
    439     AutoMutex _l(mController->mLock);
    440 
    441     if (mLocked.state.alpha != alpha) {
    442         mLocked.state.alpha = alpha;
    443         invalidateLocked(DIRTY_ALPHA);
    444     }
    445 }
    446 
    447 void SpriteController::SpriteImpl::setTransformationMatrix(
    448         const SpriteTransformationMatrix& matrix) {
    449     AutoMutex _l(mController->mLock);
    450 
    451     if (mLocked.state.transformationMatrix != matrix) {
    452         mLocked.state.transformationMatrix = matrix;
    453         invalidateLocked(DIRTY_TRANSFORMATION_MATRIX);
    454     }
    455 }
    456 
    457 void SpriteController::SpriteImpl::setDisplayId(int32_t displayId) {
    458     AutoMutex _l(mController->mLock);
    459 
    460     if (mLocked.state.displayId != displayId) {
    461         mLocked.state.displayId = displayId;
    462         invalidateLocked(DIRTY_DISPLAY_ID);
    463     }
    464 }
    465 
    466 void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) {
    467     bool wasDirty = mLocked.state.dirty;
    468     mLocked.state.dirty |= dirty;
    469 
    470     if (!wasDirty) {
    471         mController->invalidateSpriteLocked(this);
    472     }
    473 }
    474 
    475 } // namespace android
    476