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