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.
152    SurfaceComposerClient::Transaction t;
153    bool needApplyTransaction = false;
154    for (size_t i = 0; i < numSprites; i++) {
155        SpriteUpdate& update = updates.editItemAt(i);
156
157        if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) {
158            int32_t desiredWidth = update.state.icon.bitmap.width();
159            int32_t desiredHeight = update.state.icon.bitmap.height();
160            if (update.state.surfaceWidth < desiredWidth
161                    || update.state.surfaceHeight < desiredHeight) {
162                needApplyTransaction = true;
163
164                t.setSize(update.state.surfaceControl,
165                        desiredWidth, desiredHeight);
166                update.state.surfaceWidth = desiredWidth;
167                update.state.surfaceHeight = desiredHeight;
168                update.state.surfaceDrawn = false;
169                update.surfaceChanged = surfaceChanged = true;
170
171                if (update.state.surfaceVisible) {
172                    t.hide(update.state.surfaceControl);
173                    update.state.surfaceVisible = false;
174                }
175            }
176        }
177    }
178    if (needApplyTransaction) {
179        t.apply();
180    }
181
182    // Redraw sprites if needed.
183    for (size_t i = 0; i < numSprites; i++) {
184        SpriteUpdate& update = updates.editItemAt(i);
185
186        if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) {
187            update.state.surfaceDrawn = false;
188            update.surfaceChanged = surfaceChanged = true;
189        }
190
191        if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn
192                && update.state.wantSurfaceVisible()) {
193            sp<Surface> surface = update.state.surfaceControl->getSurface();
194            ANativeWindow_Buffer outBuffer;
195            status_t status = surface->lock(&outBuffer, NULL);
196            if (status) {
197                ALOGE("Error %d locking sprite surface before drawing.", status);
198            } else {
199                SkBitmap surfaceBitmap;
200                ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
201                surfaceBitmap.installPixels(SkImageInfo::MakeN32Premul(outBuffer.width, outBuffer.height),
202                                            outBuffer.bits, bpr);
203
204                SkCanvas surfaceCanvas(surfaceBitmap);
205
206                SkPaint paint;
207                paint.setBlendMode(SkBlendMode::kSrc);
208                surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint);
209
210                if (outBuffer.width > update.state.icon.bitmap.width()) {
211                    paint.setColor(0); // transparent fill color
212                    surfaceCanvas.drawRect(SkRect::MakeLTRB(update.state.icon.bitmap.width(), 0,
213                            outBuffer.width, update.state.icon.bitmap.height()), paint);
214                }
215                if (outBuffer.height > update.state.icon.bitmap.height()) {
216                    paint.setColor(0); // transparent fill color
217                    surfaceCanvas.drawRect(SkRect::MakeLTRB(0, update.state.icon.bitmap.height(),
218                            outBuffer.width, outBuffer.height), paint);
219                }
220
221                status = surface->unlockAndPost();
222                if (status) {
223                    ALOGE("Error %d unlocking and posting sprite surface after drawing.", status);
224                } else {
225                    update.state.surfaceDrawn = true;
226                    update.surfaceChanged = surfaceChanged = true;
227                }
228            }
229        }
230    }
231
232    needApplyTransaction = false;
233    for (size_t i = 0; i < numSprites; i++) {
234        SpriteUpdate& update = updates.editItemAt(i);
235
236        bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible()
237                && update.state.surfaceDrawn;
238        bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible;
239        bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible;
240        if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden
241                || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA
242                        | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER
243                        | DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) {
244            needApplyTransaction = true;
245
246            if (wantSurfaceVisibleAndDrawn
247                    && (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) {
248                t.setAlpha(update.state.surfaceControl,
249                        update.state.alpha);
250            }
251
252            if (wantSurfaceVisibleAndDrawn
253                    && (becomingVisible || (update.state.dirty & (DIRTY_POSITION
254                            | DIRTY_HOTSPOT)))) {
255                t.setPosition(
256                        update.state.surfaceControl,
257                        update.state.positionX - update.state.icon.hotSpotX,
258                        update.state.positionY - update.state.icon.hotSpotY);
259            }
260
261            if (wantSurfaceVisibleAndDrawn
262                    && (becomingVisible
263                            || (update.state.dirty & DIRTY_TRANSFORMATION_MATRIX))) {
264                t.setMatrix(
265                        update.state.surfaceControl,
266                        update.state.transformationMatrix.dsdx,
267                        update.state.transformationMatrix.dtdx,
268                        update.state.transformationMatrix.dsdy,
269                        update.state.transformationMatrix.dtdy);
270            }
271
272            int32_t surfaceLayer = mOverlayLayer + update.state.layer;
273            if (wantSurfaceVisibleAndDrawn
274                    && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) {
275                t.setLayer(update.state.surfaceControl, surfaceLayer);
276            }
277
278            if (becomingVisible) {
279                t.show(update.state.surfaceControl);
280
281                update.state.surfaceVisible = true;
282                update.surfaceChanged = surfaceChanged = true;
283            } else if (becomingHidden) {
284                t.hide(update.state.surfaceControl);
285
286                update.state.surfaceVisible = false;
287                update.surfaceChanged = surfaceChanged = true;
288            }
289        }
290    }
291
292    if (needApplyTransaction) {
293        status_t status = t.apply();
294        if (status) {
295            ALOGE("Error applying Surface transaction");
296        }
297    }
298
299    // If any surfaces were changed, write back the new surface properties to the sprites.
300    if (surfaceChanged) { // acquire lock
301        AutoMutex _l(mLock);
302
303        for (size_t i = 0; i < numSprites; i++) {
304            const SpriteUpdate& update = updates.itemAt(i);
305
306            if (update.surfaceChanged) {
307                update.sprite->setSurfaceLocked(update.state.surfaceControl,
308                        update.state.surfaceWidth, update.state.surfaceHeight,
309                        update.state.surfaceDrawn, update.state.surfaceVisible);
310            }
311        }
312    } // release lock
313
314    // Clear the sprite update vector outside the lock.  It is very important that
315    // we do not clear sprite references inside the lock since we could be releasing
316    // the last remaining reference to the sprite here which would result in the
317    // sprite being deleted and the lock being reacquired by the sprite destructor
318    // while already held.
319    updates.clear();
320}
321
322void SpriteController::doDisposeSurfaces() {
323    // Collect disposed surfaces.
324    Vector<sp<SurfaceControl> > disposedSurfaces;
325    { // acquire lock
326        AutoMutex _l(mLock);
327
328        disposedSurfaces = mLocked.disposedSurfaces;
329        mLocked.disposedSurfaces.clear();
330    } // release lock
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
337void SpriteController::ensureSurfaceComposerClient() {
338    if (mSurfaceComposerClient == NULL) {
339        mSurfaceComposerClient = new SurfaceComposerClient();
340    }
341}
342
343sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height) {
344    ensureSurfaceComposerClient();
345
346    sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface(
347            String8("Sprite"), width, height, PIXEL_FORMAT_RGBA_8888,
348            ISurfaceComposerClient::eHidden |
349            ISurfaceComposerClient::eCursorWindow);
350    if (surfaceControl == NULL || !surfaceControl->isValid()) {
351        ALOGE("Error creating sprite surface.");
352        return NULL;
353    }
354    return surfaceControl;
355}
356
357
358// --- SpriteController::SpriteImpl ---
359
360SpriteController::SpriteImpl::SpriteImpl(const sp<SpriteController> controller) :
361        mController(controller) {
362}
363
364SpriteController::SpriteImpl::~SpriteImpl() {
365    AutoMutex _m(mController->mLock);
366
367    // Let the controller take care of deleting the last reference to sprite
368    // surfaces so that we do not block the caller on an IPC here.
369    if (mLocked.state.surfaceControl != NULL) {
370        mController->disposeSurfaceLocked(mLocked.state.surfaceControl);
371        mLocked.state.surfaceControl.clear();
372    }
373}
374
375void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) {
376    AutoMutex _l(mController->mLock);
377
378    uint32_t dirty;
379    if (icon.isValid()) {
380        SkBitmap* bitmapCopy = &mLocked.state.icon.bitmap;
381        if (bitmapCopy->tryAllocPixels(icon.bitmap.info().makeColorType(kN32_SkColorType))) {
382            icon.bitmap.readPixels(bitmapCopy->info(), bitmapCopy->getPixels(),
383                    bitmapCopy->rowBytes(), 0, 0);
384        }
385
386        if (!mLocked.state.icon.isValid()
387                || mLocked.state.icon.hotSpotX != icon.hotSpotX
388                || mLocked.state.icon.hotSpotY != icon.hotSpotY) {
389            mLocked.state.icon.hotSpotX = icon.hotSpotX;
390            mLocked.state.icon.hotSpotY = icon.hotSpotY;
391            dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
392        } else {
393            dirty = DIRTY_BITMAP;
394        }
395    } else if (mLocked.state.icon.isValid()) {
396        mLocked.state.icon.bitmap.reset();
397        dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
398    } else {
399        return; // setting to invalid icon and already invalid so nothing to do
400    }
401
402    invalidateLocked(dirty);
403}
404
405void SpriteController::SpriteImpl::setVisible(bool visible) {
406    AutoMutex _l(mController->mLock);
407
408    if (mLocked.state.visible != visible) {
409        mLocked.state.visible = visible;
410        invalidateLocked(DIRTY_VISIBILITY);
411    }
412}
413
414void SpriteController::SpriteImpl::setPosition(float x, float y) {
415    AutoMutex _l(mController->mLock);
416
417    if (mLocked.state.positionX != x || mLocked.state.positionY != y) {
418        mLocked.state.positionX = x;
419        mLocked.state.positionY = y;
420        invalidateLocked(DIRTY_POSITION);
421    }
422}
423
424void SpriteController::SpriteImpl::setLayer(int32_t layer) {
425    AutoMutex _l(mController->mLock);
426
427    if (mLocked.state.layer != layer) {
428        mLocked.state.layer = layer;
429        invalidateLocked(DIRTY_LAYER);
430    }
431}
432
433void SpriteController::SpriteImpl::setAlpha(float alpha) {
434    AutoMutex _l(mController->mLock);
435
436    if (mLocked.state.alpha != alpha) {
437        mLocked.state.alpha = alpha;
438        invalidateLocked(DIRTY_ALPHA);
439    }
440}
441
442void SpriteController::SpriteImpl::setTransformationMatrix(
443        const SpriteTransformationMatrix& matrix) {
444    AutoMutex _l(mController->mLock);
445
446    if (mLocked.state.transformationMatrix != matrix) {
447        mLocked.state.transformationMatrix = matrix;
448        invalidateLocked(DIRTY_TRANSFORMATION_MATRIX);
449    }
450}
451
452void 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