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