|
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 #ifdef HAVE_ANDROID_OS |
|
26 #include <gui/Surface.h> |
|
27 #endif |
|
28 |
|
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> |
|
35 |
|
36 namespace android { |
|
37 |
|
38 // --- SpriteController --- |
|
39 |
|
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 |
|
45 |
|
46 mLocked.transactionNestingCount = 0; |
|
47 mLocked.deferredSpriteUpdate = false; |
|
48 } |
|
49 |
|
50 SpriteController::~SpriteController() { |
|
51 #ifdef HAVE_ANDROID_OS |
|
52 mLooper->removeMessages(mHandler); |
|
53 |
|
54 if (mSurfaceComposerClient != NULL) { |
|
55 mSurfaceComposerClient->dispose(); |
|
56 mSurfaceComposerClient.clear(); |
|
57 } |
|
58 #endif |
|
59 } |
|
60 |
|
61 sp<Sprite> SpriteController::createSprite() { |
|
62 return new SpriteImpl(this); |
|
63 } |
|
64 |
|
65 void SpriteController::openTransaction() { |
|
66 AutoMutex _l(mLock); |
|
67 |
|
68 mLocked.transactionNestingCount += 1; |
|
69 } |
|
70 |
|
71 void SpriteController::closeTransaction() { |
|
72 AutoMutex _l(mLock); |
|
73 |
|
74 LOG_ALWAYS_FATAL_IF(mLocked.transactionNestingCount == 0, |
|
75 "Sprite closeTransaction() called but there is no open sprite transaction"); |
|
76 |
|
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 } |
|
85 |
|
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 } |
|
99 |
|
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 } |
|
108 |
|
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 |
|
120 |
|
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); |
|
131 |
|
132 numSprites = mLocked.invalidatedSprites.size(); |
|
133 for (size_t i = 0; i < numSprites; i++) { |
|
134 const sp<SpriteImpl>& sprite = mLocked.invalidatedSprites.itemAt(i); |
|
135 |
|
136 updates.push(SpriteUpdate(sprite, sprite->getStateLocked())); |
|
137 sprite->resetDirtyLocked(); |
|
138 } |
|
139 mLocked.invalidatedSprites.clear(); |
|
140 } // release lock |
|
141 |
|
142 // Create missing surfaces. |
|
143 bool surfaceChanged = false; |
|
144 for (size_t i = 0; i < numSprites; i++) { |
|
145 SpriteUpdate& update = updates.editItemAt(i); |
|
146 |
|
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 } |
|
161 |
|
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); |
|
166 |
|
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 } |
|
177 |
|
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; |
|
188 |
|
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 |
|
207 |
|
208 // Redraw sprites if needed. |
|
209 for (size_t i = 0; i < numSprites; i++) { |
|
210 SpriteUpdate& update = updates.editItemAt(i); |
|
211 |
|
212 if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) { |
|
213 update.state.surfaceDrawn = false; |
|
214 update.surfaceChanged = surfaceChanged = true; |
|
215 } |
|
216 |
|
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); |
|
231 |
|
232 SkCanvas surfaceCanvas(surfaceBitmap); |
|
233 |
|
234 SkPaint paint; |
|
235 paint.setXfermodeMode(SkXfermode::kSrc_Mode); |
|
236 surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint); |
|
237 |
|
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 } |
|
248 |
|
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 } |
|
260 |
|
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); |
|
265 |
|
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 } |
|
280 |
|
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 } |
|
288 |
|
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 } |
|
299 |
|
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 } |
|
312 |
|
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 } |
|
321 |
|
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 } |
|
342 |
|
343 #ifdef HAVE_ANDROID_OS |
|
344 if (haveTransaction) { |
|
345 SurfaceComposerClient::closeGlobalTransaction(); |
|
346 } |
|
347 #endif |
|
348 |
|
349 // If any surfaces were changed, write back the new surface properties to the sprites. |
|
350 if (surfaceChanged) { // acquire lock |
|
351 AutoMutex _l(mLock); |
|
352 |
|
353 for (size_t i = 0; i < numSprites; i++) { |
|
354 const SpriteUpdate& update = updates.itemAt(i); |
|
355 |
|
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 |
|
365 |
|
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 } |
|
373 |
|
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); |
|
380 |
|
381 disposedSurfaces = mLocked.disposedSurfaces; |
|
382 mLocked.disposedSurfaces.clear(); |
|
383 } // release lock |
|
384 |
|
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 } |
|
390 |
|
391 void SpriteController::ensureSurfaceComposerClient() { |
|
392 #ifdef HAVE_ANDROID_OS |
|
393 if (mSurfaceComposerClient == NULL) { |
|
394 mSurfaceComposerClient = new SurfaceComposerClient(); |
|
395 } |
|
396 #endif |
|
397 } |
|
398 |
|
399 #ifdef HAVE_ANDROID_OS |
|
400 sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height) { |
|
401 ensureSurfaceComposerClient(); |
|
402 |
|
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 |
|
413 |
|
414 |
|
415 // --- SpriteController::SpriteImpl --- |
|
416 |
|
417 SpriteController::SpriteImpl::SpriteImpl(const sp<SpriteController> controller) : |
|
418 mController(controller) { |
|
419 } |
|
420 |
|
421 SpriteController::SpriteImpl::~SpriteImpl() { |
|
422 AutoMutex _m(mController->mLock); |
|
423 |
|
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 } |
|
433 |
|
434 void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) { |
|
435 AutoMutex _l(mController->mLock); |
|
436 |
|
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); |
|
441 |
|
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 } |
|
457 |
|
458 invalidateLocked(dirty); |
|
459 #endif |
|
460 } |
|
461 |
|
462 void SpriteController::SpriteImpl::setVisible(bool visible) { |
|
463 AutoMutex _l(mController->mLock); |
|
464 |
|
465 if (mLocked.state.visible != visible) { |
|
466 mLocked.state.visible = visible; |
|
467 invalidateLocked(DIRTY_VISIBILITY); |
|
468 } |
|
469 } |
|
470 |
|
471 void SpriteController::SpriteImpl::setPosition(float x, float y) { |
|
472 AutoMutex _l(mController->mLock); |
|
473 |
|
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 } |
|
480 |
|
481 void SpriteController::SpriteImpl::setLayer(int32_t layer) { |
|
482 AutoMutex _l(mController->mLock); |
|
483 |
|
484 if (mLocked.state.layer != layer) { |
|
485 mLocked.state.layer = layer; |
|
486 invalidateLocked(DIRTY_LAYER); |
|
487 } |
|
488 } |
|
489 |
|
490 void SpriteController::SpriteImpl::setAlpha(float alpha) { |
|
491 AutoMutex _l(mController->mLock); |
|
492 |
|
493 if (mLocked.state.alpha != alpha) { |
|
494 mLocked.state.alpha = alpha; |
|
495 invalidateLocked(DIRTY_ALPHA); |
|
496 } |
|
497 } |
|
498 |
|
499 void SpriteController::SpriteImpl::setTransformationMatrix( |
|
500 const SpriteTransformationMatrix& matrix) { |
|
501 AutoMutex _l(mController->mLock); |
|
502 |
|
503 if (mLocked.state.transformationMatrix != matrix) { |
|
504 mLocked.state.transformationMatrix = matrix; |
|
505 invalidateLocked(DIRTY_TRANSFORMATION_MATRIX); |
|
506 } |
|
507 } |
|
508 |
|
509 void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) { |
|
510 bool wasDirty = mLocked.state.dirty; |
|
511 mLocked.state.dirty |= dirty; |
|
512 |
|
513 if (!wasDirty) { |
|
514 mController->invalidateSpriteLocked(this); |
|
515 } |
|
516 } |
|
517 |
|
518 } // namespace android |