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