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