1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/gonk/libui/SpriteController.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,518 @@ 1.4 +/* 1.5 + * Copyright (C) 2011 The Android Open Source Project 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * Unless required by applicable law or agreed to in writing, software 1.14 + * distributed under the License is distributed on an "AS IS" BASIS, 1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.16 + * See the License for the specific language governing permissions and 1.17 + * limitations under the License. 1.18 + */ 1.19 + 1.20 +#define LOG_TAG "Sprites" 1.21 + 1.22 +//#define LOG_NDEBUG 0 1.23 + 1.24 +#include "SpriteController.h" 1.25 + 1.26 +#include "cutils_log.h" 1.27 +#include <utils/String8.h> 1.28 +#ifdef HAVE_ANDROID_OS 1.29 +#include <gui/Surface.h> 1.30 +#endif 1.31 + 1.32 +#include <SkBitmap.h> 1.33 +#include <SkCanvas.h> 1.34 +#include <SkColor.h> 1.35 +#include <SkPaint.h> 1.36 +#include <SkXfermode.h> 1.37 +#include <android/native_window.h> 1.38 + 1.39 +namespace android { 1.40 + 1.41 +// --- SpriteController --- 1.42 + 1.43 +SpriteController::SpriteController(const sp<Looper>& looper, int32_t overlayLayer) : 1.44 + mLooper(looper), mOverlayLayer(overlayLayer) { 1.45 +#ifdef HAVE_ANDROID_OS 1.46 + mHandler = new WeakMessageHandler(this); 1.47 +#endif 1.48 + 1.49 + mLocked.transactionNestingCount = 0; 1.50 + mLocked.deferredSpriteUpdate = false; 1.51 +} 1.52 + 1.53 +SpriteController::~SpriteController() { 1.54 +#ifdef HAVE_ANDROID_OS 1.55 + mLooper->removeMessages(mHandler); 1.56 + 1.57 + if (mSurfaceComposerClient != NULL) { 1.58 + mSurfaceComposerClient->dispose(); 1.59 + mSurfaceComposerClient.clear(); 1.60 + } 1.61 +#endif 1.62 +} 1.63 + 1.64 +sp<Sprite> SpriteController::createSprite() { 1.65 + return new SpriteImpl(this); 1.66 +} 1.67 + 1.68 +void SpriteController::openTransaction() { 1.69 + AutoMutex _l(mLock); 1.70 + 1.71 + mLocked.transactionNestingCount += 1; 1.72 +} 1.73 + 1.74 +void SpriteController::closeTransaction() { 1.75 + AutoMutex _l(mLock); 1.76 + 1.77 + LOG_ALWAYS_FATAL_IF(mLocked.transactionNestingCount == 0, 1.78 + "Sprite closeTransaction() called but there is no open sprite transaction"); 1.79 + 1.80 + mLocked.transactionNestingCount -= 1; 1.81 + if (mLocked.transactionNestingCount == 0 && mLocked.deferredSpriteUpdate) { 1.82 + mLocked.deferredSpriteUpdate = false; 1.83 +#ifdef HAVE_ANDROID_OS 1.84 + mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES)); 1.85 +#endif 1.86 + } 1.87 +} 1.88 + 1.89 +void SpriteController::invalidateSpriteLocked(const sp<SpriteImpl>& sprite) { 1.90 + bool wasEmpty = mLocked.invalidatedSprites.isEmpty(); 1.91 + mLocked.invalidatedSprites.push(sprite); 1.92 + if (wasEmpty) { 1.93 + if (mLocked.transactionNestingCount != 0) { 1.94 + mLocked.deferredSpriteUpdate = true; 1.95 + } else { 1.96 +#ifdef HAVE_ANDROID_OS 1.97 + mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES)); 1.98 +#endif 1.99 + } 1.100 + } 1.101 +} 1.102 + 1.103 +#ifdef HAVE_ANDROID_OS 1.104 +void SpriteController::disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl) { 1.105 + bool wasEmpty = mLocked.disposedSurfaces.isEmpty(); 1.106 + mLocked.disposedSurfaces.push(surfaceControl); 1.107 + if (wasEmpty) { 1.108 + mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES)); 1.109 + } 1.110 +} 1.111 + 1.112 +void SpriteController::handleMessage(const Message& message) { 1.113 + switch (message.what) { 1.114 + case MSG_UPDATE_SPRITES: 1.115 + doUpdateSprites(); 1.116 + break; 1.117 + case MSG_DISPOSE_SURFACES: 1.118 + doDisposeSurfaces(); 1.119 + break; 1.120 + } 1.121 +} 1.122 +#endif 1.123 + 1.124 +void SpriteController::doUpdateSprites() { 1.125 + // Collect information about sprite updates. 1.126 + // Each sprite update record includes a reference to its associated sprite so we can 1.127 + // be certain the sprites will not be deleted while this function runs. Sprites 1.128 + // may invalidate themselves again during this time but we will handle those changes 1.129 + // in the next iteration. 1.130 + Vector<SpriteUpdate> updates; 1.131 + size_t numSprites; 1.132 + { // acquire lock 1.133 + AutoMutex _l(mLock); 1.134 + 1.135 + numSprites = mLocked.invalidatedSprites.size(); 1.136 + for (size_t i = 0; i < numSprites; i++) { 1.137 + const sp<SpriteImpl>& sprite = mLocked.invalidatedSprites.itemAt(i); 1.138 + 1.139 + updates.push(SpriteUpdate(sprite, sprite->getStateLocked())); 1.140 + sprite->resetDirtyLocked(); 1.141 + } 1.142 + mLocked.invalidatedSprites.clear(); 1.143 + } // release lock 1.144 + 1.145 + // Create missing surfaces. 1.146 + bool surfaceChanged = false; 1.147 + for (size_t i = 0; i < numSprites; i++) { 1.148 + SpriteUpdate& update = updates.editItemAt(i); 1.149 + 1.150 +#ifdef HAVE_ANDROID_OS 1.151 + if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) { 1.152 + update.state.surfaceWidth = update.state.icon.bitmap.width(); 1.153 + update.state.surfaceHeight = update.state.icon.bitmap.height(); 1.154 + update.state.surfaceDrawn = false; 1.155 + update.state.surfaceVisible = false; 1.156 + update.state.surfaceControl = obtainSurface( 1.157 + update.state.surfaceWidth, update.state.surfaceHeight); 1.158 + if (update.state.surfaceControl != NULL) { 1.159 + update.surfaceChanged = surfaceChanged = true; 1.160 + } 1.161 + } 1.162 +#endif 1.163 + } 1.164 + 1.165 + // Resize sprites if needed, inside a global transaction. 1.166 + bool haveGlobalTransaction = false; 1.167 + for (size_t i = 0; i < numSprites; i++) { 1.168 + SpriteUpdate& update = updates.editItemAt(i); 1.169 + 1.170 +#ifdef HAVE_ANDROID_OS 1.171 + if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) { 1.172 + int32_t desiredWidth = update.state.icon.bitmap.width(); 1.173 + int32_t desiredHeight = update.state.icon.bitmap.height(); 1.174 + if (update.state.surfaceWidth < desiredWidth 1.175 + || update.state.surfaceHeight < desiredHeight) { 1.176 + if (!haveGlobalTransaction) { 1.177 + SurfaceComposerClient::openGlobalTransaction(); 1.178 + haveGlobalTransaction = true; 1.179 + } 1.180 + 1.181 + status_t status = update.state.surfaceControl->setSize(desiredWidth, desiredHeight); 1.182 + if (status) { 1.183 + ALOGE("Error %d resizing sprite surface from %dx%d to %dx%d", 1.184 + status, update.state.surfaceWidth, update.state.surfaceHeight, 1.185 + desiredWidth, desiredHeight); 1.186 + } else { 1.187 + update.state.surfaceWidth = desiredWidth; 1.188 + update.state.surfaceHeight = desiredHeight; 1.189 + update.state.surfaceDrawn = false; 1.190 + update.surfaceChanged = surfaceChanged = true; 1.191 + 1.192 + if (update.state.surfaceVisible) { 1.193 + status = update.state.surfaceControl->hide(); 1.194 + if (status) { 1.195 + ALOGE("Error %d hiding sprite surface after resize.", status); 1.196 + } else { 1.197 + update.state.surfaceVisible = false; 1.198 + } 1.199 + } 1.200 + } 1.201 + } 1.202 + } 1.203 +#endif 1.204 + } 1.205 +#ifdef HAVE_ANDROID_OS 1.206 + if (haveGlobalTransaction) { 1.207 + SurfaceComposerClient::closeGlobalTransaction(); 1.208 + } 1.209 +#endif 1.210 + 1.211 + // Redraw sprites if needed. 1.212 + for (size_t i = 0; i < numSprites; i++) { 1.213 + SpriteUpdate& update = updates.editItemAt(i); 1.214 + 1.215 + if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) { 1.216 + update.state.surfaceDrawn = false; 1.217 + update.surfaceChanged = surfaceChanged = true; 1.218 + } 1.219 + 1.220 +#ifdef HAVE_ANDROID_OS 1.221 + if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn 1.222 + && update.state.wantSurfaceVisible()) { 1.223 + sp<Surface> surface = update.state.surfaceControl->getSurface(); 1.224 + ANativeWindow_Buffer outBuffer; 1.225 + status_t status = surface->lock(&outBuffer, NULL); 1.226 + if (status) { 1.227 + ALOGE("Error %d locking sprite surface before drawing.", status); 1.228 + } else { 1.229 + SkBitmap surfaceBitmap; 1.230 + ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format); 1.231 + surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config, 1.232 + outBuffer.width, outBuffer.height, bpr); 1.233 + surfaceBitmap.setPixels(outBuffer.bits); 1.234 + 1.235 + SkCanvas surfaceCanvas(surfaceBitmap); 1.236 + 1.237 + SkPaint paint; 1.238 + paint.setXfermodeMode(SkXfermode::kSrc_Mode); 1.239 + surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint); 1.240 + 1.241 + if (outBuffer.width > uint32_t(update.state.icon.bitmap.width())) { 1.242 + paint.setColor(0); // transparent fill color 1.243 + surfaceCanvas.drawRectCoords(update.state.icon.bitmap.width(), 0, 1.244 + outBuffer.width, update.state.icon.bitmap.height(), paint); 1.245 + } 1.246 + if (outBuffer.height > uint32_t(update.state.icon.bitmap.height())) { 1.247 + paint.setColor(0); // transparent fill color 1.248 + surfaceCanvas.drawRectCoords(0, update.state.icon.bitmap.height(), 1.249 + outBuffer.width, outBuffer.height, paint); 1.250 + } 1.251 + 1.252 + status = surface->unlockAndPost(); 1.253 + if (status) { 1.254 + ALOGE("Error %d unlocking and posting sprite surface after drawing.", status); 1.255 + } else { 1.256 + update.state.surfaceDrawn = true; 1.257 + update.surfaceChanged = surfaceChanged = true; 1.258 + } 1.259 + } 1.260 + } 1.261 +#endif 1.262 + } 1.263 + 1.264 + // Set sprite surface properties and make them visible. 1.265 + bool haveTransaction = false; 1.266 + for (size_t i = 0; i < numSprites; i++) { 1.267 + SpriteUpdate& update = updates.editItemAt(i); 1.268 + 1.269 + bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible() 1.270 + && update.state.surfaceDrawn; 1.271 + bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible; 1.272 + bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible; 1.273 +#ifdef HAVE_ANDROID_OS 1.274 + if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden 1.275 + || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA 1.276 + | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER 1.277 + | DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) { 1.278 + status_t status; 1.279 + if (!haveTransaction) { 1.280 + SurfaceComposerClient::openGlobalTransaction(); 1.281 + haveTransaction = true; 1.282 + } 1.283 + 1.284 + if (wantSurfaceVisibleAndDrawn 1.285 + && (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) { 1.286 + status = update.state.surfaceControl->setAlpha(update.state.alpha); 1.287 + if (status) { 1.288 + ALOGE("Error %d setting sprite surface alpha.", status); 1.289 + } 1.290 + } 1.291 + 1.292 + if (wantSurfaceVisibleAndDrawn 1.293 + && (becomingVisible || (update.state.dirty & (DIRTY_POSITION 1.294 + | DIRTY_HOTSPOT)))) { 1.295 + status = update.state.surfaceControl->setPosition( 1.296 + update.state.positionX - update.state.icon.hotSpotX, 1.297 + update.state.positionY - update.state.icon.hotSpotY); 1.298 + if (status) { 1.299 + ALOGE("Error %d setting sprite surface position.", status); 1.300 + } 1.301 + } 1.302 + 1.303 + if (wantSurfaceVisibleAndDrawn 1.304 + && (becomingVisible 1.305 + || (update.state.dirty & DIRTY_TRANSFORMATION_MATRIX))) { 1.306 + status = update.state.surfaceControl->setMatrix( 1.307 + update.state.transformationMatrix.dsdx, 1.308 + update.state.transformationMatrix.dtdx, 1.309 + update.state.transformationMatrix.dsdy, 1.310 + update.state.transformationMatrix.dtdy); 1.311 + if (status) { 1.312 + ALOGE("Error %d setting sprite surface transformation matrix.", status); 1.313 + } 1.314 + } 1.315 + 1.316 + int32_t surfaceLayer = mOverlayLayer + update.state.layer; 1.317 + if (wantSurfaceVisibleAndDrawn 1.318 + && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) { 1.319 + status = update.state.surfaceControl->setLayer(surfaceLayer); 1.320 + if (status) { 1.321 + ALOGE("Error %d setting sprite surface layer.", status); 1.322 + } 1.323 + } 1.324 + 1.325 + if (becomingVisible) { 1.326 + status = update.state.surfaceControl->show(); 1.327 + if (status) { 1.328 + ALOGE("Error %d showing sprite surface.", status); 1.329 + } else { 1.330 + update.state.surfaceVisible = true; 1.331 + update.surfaceChanged = surfaceChanged = true; 1.332 + } 1.333 + } else if (becomingHidden) { 1.334 + status = update.state.surfaceControl->hide(); 1.335 + if (status) { 1.336 + ALOGE("Error %d hiding sprite surface.", status); 1.337 + } else { 1.338 + update.state.surfaceVisible = false; 1.339 + update.surfaceChanged = surfaceChanged = true; 1.340 + } 1.341 + } 1.342 + } 1.343 +#endif 1.344 + } 1.345 + 1.346 +#ifdef HAVE_ANDROID_OS 1.347 + if (haveTransaction) { 1.348 + SurfaceComposerClient::closeGlobalTransaction(); 1.349 + } 1.350 +#endif 1.351 + 1.352 + // If any surfaces were changed, write back the new surface properties to the sprites. 1.353 + if (surfaceChanged) { // acquire lock 1.354 + AutoMutex _l(mLock); 1.355 + 1.356 + for (size_t i = 0; i < numSprites; i++) { 1.357 + const SpriteUpdate& update = updates.itemAt(i); 1.358 + 1.359 +#ifdef HAVE_ANDROID_OS 1.360 + if (update.surfaceChanged) { 1.361 + update.sprite->setSurfaceLocked(update.state.surfaceControl, 1.362 + update.state.surfaceWidth, update.state.surfaceHeight, 1.363 + update.state.surfaceDrawn, update.state.surfaceVisible); 1.364 + } 1.365 +#endif 1.366 + } 1.367 + } // release lock 1.368 + 1.369 + // Clear the sprite update vector outside the lock. It is very important that 1.370 + // we do not clear sprite references inside the lock since we could be releasing 1.371 + // the last remaining reference to the sprite here which would result in the 1.372 + // sprite being deleted and the lock being reacquired by the sprite destructor 1.373 + // while already held. 1.374 + updates.clear(); 1.375 +} 1.376 + 1.377 +void SpriteController::doDisposeSurfaces() { 1.378 +#ifdef HAVE_ANDROID_OS 1.379 + // Collect disposed surfaces. 1.380 + Vector<sp<SurfaceControl> > disposedSurfaces; 1.381 + { // acquire lock 1.382 + AutoMutex _l(mLock); 1.383 + 1.384 + disposedSurfaces = mLocked.disposedSurfaces; 1.385 + mLocked.disposedSurfaces.clear(); 1.386 + } // release lock 1.387 + 1.388 + // Release the last reference to each surface outside of the lock. 1.389 + // We don't want the surfaces to be deleted while we are holding our lock. 1.390 + disposedSurfaces.clear(); 1.391 +#endif 1.392 +} 1.393 + 1.394 +void SpriteController::ensureSurfaceComposerClient() { 1.395 +#ifdef HAVE_ANDROID_OS 1.396 + if (mSurfaceComposerClient == NULL) { 1.397 + mSurfaceComposerClient = new SurfaceComposerClient(); 1.398 + } 1.399 +#endif 1.400 +} 1.401 + 1.402 +#ifdef HAVE_ANDROID_OS 1.403 +sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height) { 1.404 + ensureSurfaceComposerClient(); 1.405 + 1.406 + sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface( 1.407 + String8("Sprite"), width, height, PIXEL_FORMAT_RGBA_8888, 1.408 + ISurfaceComposerClient::eHidden); 1.409 + if (surfaceControl == NULL || !surfaceControl->isValid()) { 1.410 + ALOGE("Error creating sprite surface."); 1.411 + return NULL; 1.412 + } 1.413 + return surfaceControl; 1.414 +} 1.415 +#endif 1.416 + 1.417 + 1.418 +// --- SpriteController::SpriteImpl --- 1.419 + 1.420 +SpriteController::SpriteImpl::SpriteImpl(const sp<SpriteController> controller) : 1.421 + mController(controller) { 1.422 +} 1.423 + 1.424 +SpriteController::SpriteImpl::~SpriteImpl() { 1.425 + AutoMutex _m(mController->mLock); 1.426 + 1.427 +#ifdef HAVE_ANDROID_OS 1.428 + // Let the controller take care of deleting the last reference to sprite 1.429 + // surfaces so that we do not block the caller on an IPC here. 1.430 + if (mLocked.state.surfaceControl != NULL) { 1.431 + mController->disposeSurfaceLocked(mLocked.state.surfaceControl); 1.432 + mLocked.state.surfaceControl.clear(); 1.433 + } 1.434 +#endif 1.435 +} 1.436 + 1.437 +void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) { 1.438 + AutoMutex _l(mController->mLock); 1.439 + 1.440 +#ifdef HAVE_ANDROID_OS 1.441 + uint32_t dirty; 1.442 + if (icon.isValid()) { 1.443 + icon.bitmap.copyTo(&mLocked.state.icon.bitmap, SkBitmap::kARGB_8888_Config); 1.444 + 1.445 + if (!mLocked.state.icon.isValid() 1.446 + || mLocked.state.icon.hotSpotX != icon.hotSpotX 1.447 + || mLocked.state.icon.hotSpotY != icon.hotSpotY) { 1.448 + mLocked.state.icon.hotSpotX = icon.hotSpotX; 1.449 + mLocked.state.icon.hotSpotY = icon.hotSpotY; 1.450 + dirty = DIRTY_BITMAP | DIRTY_HOTSPOT; 1.451 + } else { 1.452 + dirty = DIRTY_BITMAP; 1.453 + } 1.454 + } else if (mLocked.state.icon.isValid()) { 1.455 + mLocked.state.icon.bitmap.reset(); 1.456 + dirty = DIRTY_BITMAP | DIRTY_HOTSPOT; 1.457 + } else { 1.458 + return; // setting to invalid icon and already invalid so nothing to do 1.459 + } 1.460 + 1.461 + invalidateLocked(dirty); 1.462 +#endif 1.463 +} 1.464 + 1.465 +void SpriteController::SpriteImpl::setVisible(bool visible) { 1.466 + AutoMutex _l(mController->mLock); 1.467 + 1.468 + if (mLocked.state.visible != visible) { 1.469 + mLocked.state.visible = visible; 1.470 + invalidateLocked(DIRTY_VISIBILITY); 1.471 + } 1.472 +} 1.473 + 1.474 +void SpriteController::SpriteImpl::setPosition(float x, float y) { 1.475 + AutoMutex _l(mController->mLock); 1.476 + 1.477 + if (mLocked.state.positionX != x || mLocked.state.positionY != y) { 1.478 + mLocked.state.positionX = x; 1.479 + mLocked.state.positionY = y; 1.480 + invalidateLocked(DIRTY_POSITION); 1.481 + } 1.482 +} 1.483 + 1.484 +void SpriteController::SpriteImpl::setLayer(int32_t layer) { 1.485 + AutoMutex _l(mController->mLock); 1.486 + 1.487 + if (mLocked.state.layer != layer) { 1.488 + mLocked.state.layer = layer; 1.489 + invalidateLocked(DIRTY_LAYER); 1.490 + } 1.491 +} 1.492 + 1.493 +void SpriteController::SpriteImpl::setAlpha(float alpha) { 1.494 + AutoMutex _l(mController->mLock); 1.495 + 1.496 + if (mLocked.state.alpha != alpha) { 1.497 + mLocked.state.alpha = alpha; 1.498 + invalidateLocked(DIRTY_ALPHA); 1.499 + } 1.500 +} 1.501 + 1.502 +void SpriteController::SpriteImpl::setTransformationMatrix( 1.503 + const SpriteTransformationMatrix& matrix) { 1.504 + AutoMutex _l(mController->mLock); 1.505 + 1.506 + if (mLocked.state.transformationMatrix != matrix) { 1.507 + mLocked.state.transformationMatrix = matrix; 1.508 + invalidateLocked(DIRTY_TRANSFORMATION_MATRIX); 1.509 + } 1.510 +} 1.511 + 1.512 +void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) { 1.513 + bool wasDirty = mLocked.state.dirty; 1.514 + mLocked.state.dirty |= dirty; 1.515 + 1.516 + if (!wasDirty) { 1.517 + mController->invalidateSpriteLocked(this); 1.518 + } 1.519 +} 1.520 + 1.521 +} // namespace android