HWComposer.cpp revision 9eb1eb5bb55740982ceae9966fc536824edc302a
1/*
2 * Copyright (C) 2010 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 ATRACE_TAG ATRACE_TAG_GRAPHICS
18
19// Uncomment this to remove support for HWC_DEVICE_API_VERSION_0_3 and older
20#define HWC_REMOVE_DEPRECATED_VERSIONS 1
21
22#include <stdint.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/types.h>
27
28#include <utils/Errors.h>
29#include <utils/String8.h>
30#include <utils/Thread.h>
31#include <utils/Trace.h>
32#include <utils/Vector.h>
33
34#include <ui/GraphicBuffer.h>
35
36#include <hardware/hardware.h>
37#include <hardware/hwcomposer.h>
38
39#include <cutils/log.h>
40#include <cutils/properties.h>
41
42#include "Layer.h"           // needed only for debugging
43#include "LayerBase.h"
44#include "HWComposer.h"
45#include "SurfaceFlinger.h"
46
47namespace android {
48
49#define MIN_HWC_HEADER_VERSION 0
50
51static uint32_t hwcApiVersion(const hwc_composer_device_1_t* hwc) {
52    uint32_t hwcVersion = hwc->common.version;
53    if (MIN_HWC_HEADER_VERSION == 0 &&
54            (hwcVersion & HARDWARE_API_VERSION_2_MAJ_MIN_MASK) == 0) {
55        // legacy version encoding
56        hwcVersion <<= 16;
57    }
58    return hwcVersion & HARDWARE_API_VERSION_2_MAJ_MIN_MASK;
59}
60
61static uint32_t hwcHeaderVersion(const hwc_composer_device_1_t* hwc) {
62    uint32_t hwcVersion = hwc->common.version;
63    if (MIN_HWC_HEADER_VERSION == 0 &&
64            (hwcVersion & HARDWARE_API_VERSION_2_MAJ_MIN_MASK) == 0) {
65        // legacy version encoding
66        hwcVersion <<= 16;
67    }
68    return hwcVersion & HARDWARE_API_VERSION_2_HEADER_MASK;
69}
70
71static bool hwcHasApiVersion(const hwc_composer_device_1_t* hwc,
72        uint32_t version) {
73    return hwcApiVersion(hwc) >= (version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK);
74}
75
76// ---------------------------------------------------------------------------
77
78struct HWComposer::cb_context {
79    struct callbacks : public hwc_procs_t {
80        // these are here to facilitate the transition when adding
81        // new callbacks (an implementation can check for NULL before
82        // calling a new callback).
83        void (*zero[4])(void);
84    };
85    callbacks procs;
86    HWComposer* hwc;
87};
88
89// ---------------------------------------------------------------------------
90
91HWComposer::HWComposer(
92        const sp<SurfaceFlinger>& flinger,
93        EventHandler& handler,
94        framebuffer_device_t const* fbDev)
95    : mFlinger(flinger),
96      mModule(0), mHwc(0), mNumDisplays(1),
97      mCBContext(new cb_context),
98      mEventHandler(handler),
99      mVSyncCount(0), mDebugForceFakeVSync(false)
100{
101    for (size_t i =0 ; i<MAX_DISPLAYS ; i++) {
102        mLists[i] = 0;
103    }
104
105    char value[PROPERTY_VALUE_MAX];
106    property_get("debug.sf.no_hw_vsync", value, "0");
107    mDebugForceFakeVSync = atoi(value);
108
109    bool needVSyncThread = true;
110    int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
111    ALOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID);
112    if (err == 0) {
113        err = hwc_open_1(mModule, &mHwc);
114        ALOGE_IF(err, "%s device failed to initialize (%s)",
115                HWC_HARDWARE_COMPOSER, strerror(-err));
116        if (err == 0) {
117            if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) ||
118                    hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION ||
119                    hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) {
120                ALOGE("%s device version %#x unsupported, will not be used",
121                        HWC_HARDWARE_COMPOSER, mHwc->common.version);
122                hwc_close_1(mHwc);
123                mHwc = NULL;
124            }
125        }
126
127        if (mHwc) {
128            ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
129                    (hwcApiVersion(mHwc) >> 24) & 0xff,
130                    (hwcApiVersion(mHwc) >> 16) & 0xff);
131            if (mHwc->registerProcs) {
132                mCBContext->hwc = this;
133                mCBContext->procs.invalidate = &hook_invalidate;
134                mCBContext->procs.vsync = &hook_vsync;
135                memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
136                mHwc->registerProcs(mHwc, &mCBContext->procs);
137            }
138
139            // always turn vsync off when we start
140            needVSyncThread = false;
141            mHwc->eventControl(mHwc, 0, HWC_EVENT_VSYNC, 0);
142
143            int period;
144            if (mHwc->query(mHwc, HWC_VSYNC_PERIOD, &period) == NO_ERROR) {
145                mDisplayData[HWC_DISPLAY_PRIMARY].refresh = nsecs_t(period);
146            }
147
148            // these IDs are always reserved
149            for (size_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
150                mAllocatedDisplayIDs.markBit(i);
151                // TODO: we query xdpi / ydpi / refresh
152            }
153
154            // the number of displays we actually have depends on the
155            // hw composer version
156            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) {
157                // 1.2 adds support for virtual displays
158                mNumDisplays = MAX_DISPLAYS;
159            } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
160                // 1.1 adds support for multiple displays
161                mNumDisplays = HWC_NUM_DISPLAY_TYPES;
162            } else {
163                mNumDisplays = 1;
164            }
165        }
166    }
167
168    if (fbDev) {
169        // if we're here it means we are on version 1.0
170        DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
171        disp.xdpi = fbDev->xdpi;
172        disp.ydpi = fbDev->ydpi;
173        if (disp.refresh == 0) {
174            disp.refresh = nsecs_t(1e9 / fbDev->fps);
175            ALOGW("getting VSYNC period from fb HAL: %lld", disp.refresh);
176        }
177        if (disp.refresh == 0) {
178            disp.refresh = nsecs_t(1e9 / 60.0);
179            ALOGW("getting VSYNC period thin air: %lld", mDisplayData[HWC_DISPLAY_PRIMARY].refresh);
180        }
181    }
182
183    if (needVSyncThread) {
184        // we don't have VSYNC support, we need to fake it
185        mVSyncThread = new VSyncThread(*this);
186    }
187}
188
189HWComposer::~HWComposer() {
190    mHwc->eventControl(mHwc, 0, EVENT_VSYNC, 0);
191    if (mVSyncThread != NULL) {
192        mVSyncThread->requestExitAndWait();
193    }
194    if (mHwc) {
195        hwc_close_1(mHwc);
196    }
197    delete mCBContext;
198}
199
200status_t HWComposer::initCheck() const {
201    return mHwc ? NO_ERROR : NO_INIT;
202}
203
204void HWComposer::hook_invalidate(const struct hwc_procs* procs) {
205    cb_context* ctx = reinterpret_cast<cb_context*>(
206            const_cast<hwc_procs_t*>(procs));
207    ctx->hwc->invalidate();
208}
209
210void HWComposer::hook_vsync(const struct hwc_procs* procs, int dpy,
211        int64_t timestamp) {
212    cb_context* ctx = reinterpret_cast<cb_context*>(
213            const_cast<hwc_procs_t*>(procs));
214    ctx->hwc->vsync(dpy, timestamp);
215}
216
217void HWComposer::invalidate() {
218    mFlinger->repaintEverything();
219}
220
221void HWComposer::vsync(int dpy, int64_t timestamp) {
222    ATRACE_INT("VSYNC", ++mVSyncCount&1);
223    mEventHandler.onVSyncReceived(dpy, timestamp);
224    Mutex::Autolock _l(mLock);
225    mLastHwVSync = timestamp;
226}
227
228int32_t HWComposer::allocateDisplayId() {
229    if (mAllocatedDisplayIDs.count() >= mNumDisplays) {
230        return NO_MEMORY;
231    }
232    int32_t id = mAllocatedDisplayIDs.firstUnmarkedBit();
233    mAllocatedDisplayIDs.markBit(id);
234    return id;
235}
236
237status_t HWComposer::freeDisplayId(int32_t id) {
238    if (id < HWC_NUM_DISPLAY_TYPES) {
239        // cannot free the reserved IDs
240        return BAD_VALUE;
241    }
242    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
243        return BAD_INDEX;
244    }
245    mAllocatedDisplayIDs.clearBit(id);
246    return NO_ERROR;
247}
248
249nsecs_t HWComposer::getRefreshPeriod() const {
250    return mDisplayData[HWC_DISPLAY_PRIMARY].refresh;
251}
252
253nsecs_t HWComposer::getRefreshTimestamp() const {
254    // this returns the last refresh timestamp.
255    // if the last one is not available, we estimate it based on
256    // the refresh period and whatever closest timestamp we have.
257    Mutex::Autolock _l(mLock);
258    nsecs_t now = systemTime(CLOCK_MONOTONIC);
259    return now - ((now - mLastHwVSync) %  mDisplayData[HWC_DISPLAY_PRIMARY].refresh);
260}
261
262float HWComposer::getDpiX() const {
263    return mDisplayData[HWC_DISPLAY_PRIMARY].xdpi;
264}
265
266float HWComposer::getDpiY() const {
267    return mDisplayData[HWC_DISPLAY_PRIMARY].ydpi;
268}
269
270void HWComposer::eventControl(int event, int enabled) {
271    status_t err = NO_ERROR;
272    if (mHwc) {
273        if (!mDebugForceFakeVSync) {
274            err = mHwc->eventControl(mHwc, 0, event, enabled);
275            // error here should not happen -- not sure what we should
276            // do if it does.
277            ALOGE_IF(err, "eventControl(%d, %d) failed %s",
278                    event, enabled, strerror(-err));
279        }
280    }
281
282    if (err == NO_ERROR && mVSyncThread != NULL) {
283        mVSyncThread->setEnabled(enabled);
284    }
285}
286
287status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
288    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
289        return BAD_INDEX;
290    }
291
292    if (mHwc) {
293        DisplayData& disp(mDisplayData[id]);
294        if (disp.capacity < numLayers || disp.list == NULL) {
295            const size_t size = sizeof(hwc_display_contents_1_t)
296                    + numLayers * sizeof(hwc_layer_1_t);
297            free(disp.list);
298            disp.list = (hwc_display_contents_1_t*)malloc(size);
299            disp.capacity = numLayers;
300        }
301        disp.list->flags = HWC_GEOMETRY_CHANGED;
302        disp.list->numHwLayers = numLayers;
303        disp.list->flipFenceFd = -1;
304    }
305    return NO_ERROR;
306}
307
308status_t HWComposer::prepare() {
309    for (size_t i=0 ; i<mNumDisplays ; i++) {
310        mLists[i] = mDisplayData[i].list;
311        if (mLists[i]) {
312            mLists[i]->dpy = EGL_NO_DISPLAY;
313            mLists[i]->sur = EGL_NO_SURFACE;
314        }
315    }
316    int err = mHwc->prepare(mHwc, mNumDisplays, mLists);
317    if (err == NO_ERROR) {
318        // here we're just making sure that "skip" layers are set
319        // to HWC_FRAMEBUFFER and we're also counting how many layers
320        // we have of each type.
321        for (size_t i=0 ; i<mNumDisplays ; i++) {
322            DisplayData& disp(mDisplayData[i]);
323            disp.hasFbComp = false;
324            disp.hasOvComp = false;
325            if (disp.list) {
326                for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
327                    hwc_layer_1_t& l = disp.list->hwLayers[i];
328                    if (l.flags & HWC_SKIP_LAYER) {
329                        l.compositionType = HWC_FRAMEBUFFER;
330                    }
331                    if (l.compositionType == HWC_FRAMEBUFFER) {
332                        disp.hasFbComp = true;
333                    }
334                    if (l.compositionType == HWC_OVERLAY) {
335                        disp.hasOvComp = true;
336                    }
337                }
338            }
339        }
340    }
341    return (status_t)err;
342}
343
344bool HWComposer::hasHwcComposition(int32_t id) const {
345    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
346        return false;
347    return mDisplayData[id].hasOvComp;
348}
349
350bool HWComposer::hasGlesComposition(int32_t id) const {
351    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
352        return false;
353    return mDisplayData[id].hasFbComp;
354}
355
356status_t HWComposer::commit() {
357    int err = NO_ERROR;
358    if (mHwc) {
359        if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
360            // On version 1.0, the OpenGL ES target surface is communicated
361            // by the (dpy, sur) fields and we are guaranteed to have only
362            // a single display.
363            mLists[0]->dpy = eglGetCurrentDisplay();
364            mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW);
365        }
366
367        err = mHwc->set(mHwc, mNumDisplays, mLists);
368
369        for (size_t i=0 ; i<mNumDisplays ; i++) {
370            DisplayData& disp(mDisplayData[i]);
371            if (disp.list) {
372                if (disp.list->flipFenceFd != -1) {
373                    close(disp.list->flipFenceFd);
374                    disp.list->flipFenceFd = -1;
375                }
376                disp.list->flags &= ~HWC_GEOMETRY_CHANGED;
377            }
378        }
379    }
380    return (status_t)err;
381}
382
383status_t HWComposer::release() const {
384    if (mHwc) {
385        mHwc->eventControl(mHwc, 0, HWC_EVENT_VSYNC, 0);
386        return (status_t)mHwc->blank(mHwc, 0, 1);
387    }
388    return NO_ERROR;
389}
390
391status_t HWComposer::acquire() const {
392    if (mHwc) {
393        return (status_t)mHwc->blank(mHwc, 0, 0);
394    }
395    return NO_ERROR;
396}
397
398size_t HWComposer::getNumLayers(int32_t id) const {
399    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
400        return 0;
401    }
402    return (mHwc && mDisplayData[id].list) ?
403            mDisplayData[id].list->numHwLayers : 0;
404}
405
406/*
407 * Helper template to implement a concrete HWCLayer
408 * This holds the pointer to the concrete hwc layer type
409 * and implements the "iterable" side of HWCLayer.
410 */
411template<typename CONCRETE, typename HWCTYPE>
412class Iterable : public HWComposer::HWCLayer {
413protected:
414    HWCTYPE* const mLayerList;
415    HWCTYPE* mCurrentLayer;
416    Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer) { }
417    inline HWCTYPE const * getLayer() const { return mCurrentLayer; }
418    inline HWCTYPE* getLayer() { return mCurrentLayer; }
419    virtual ~Iterable() { }
420private:
421    // returns a copy of ourselves
422    virtual HWComposer::HWCLayer* dup() {
423        return new CONCRETE( static_cast<const CONCRETE&>(*this) );
424    }
425    virtual status_t setLayer(size_t index) {
426        mCurrentLayer = &mLayerList[index];
427        return NO_ERROR;
428    }
429};
430
431/*
432 * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_1_0.
433 * This implements the HWCLayer side of HWCIterableLayer.
434 */
435class HWCLayerVersion1 : public Iterable<HWCLayerVersion1, hwc_layer_1_t> {
436public:
437    HWCLayerVersion1(hwc_layer_1_t* layer)
438        : Iterable<HWCLayerVersion1, hwc_layer_1_t>(layer) { }
439
440    virtual int32_t getCompositionType() const {
441        return getLayer()->compositionType;
442    }
443    virtual uint32_t getHints() const {
444        return getLayer()->hints;
445    }
446    virtual int getAndResetReleaseFenceFd() {
447        int fd = getLayer()->releaseFenceFd;
448        getLayer()->releaseFenceFd = -1;
449        return fd;
450    }
451    virtual void setAcquireFenceFd(int fenceFd) {
452        getLayer()->acquireFenceFd = fenceFd;
453    }
454
455    virtual void setDefaultState() {
456        getLayer()->compositionType = HWC_FRAMEBUFFER;
457        getLayer()->hints = 0;
458        getLayer()->flags = HWC_SKIP_LAYER;
459        getLayer()->transform = 0;
460        getLayer()->blending = HWC_BLENDING_NONE;
461        getLayer()->visibleRegionScreen.numRects = 0;
462        getLayer()->visibleRegionScreen.rects = NULL;
463        getLayer()->acquireFenceFd = -1;
464        getLayer()->releaseFenceFd = -1;
465    }
466    virtual void setSkip(bool skip) {
467        if (skip) {
468            getLayer()->flags |= HWC_SKIP_LAYER;
469        } else {
470            getLayer()->flags &= ~HWC_SKIP_LAYER;
471        }
472    }
473    virtual void setBlending(uint32_t blending) {
474        getLayer()->blending = blending;
475    }
476    virtual void setTransform(uint32_t transform) {
477        getLayer()->transform = transform;
478    }
479    virtual void setFrame(const Rect& frame) {
480        reinterpret_cast<Rect&>(getLayer()->displayFrame) = frame;
481    }
482    virtual void setCrop(const Rect& crop) {
483        reinterpret_cast<Rect&>(getLayer()->sourceCrop) = crop;
484    }
485    virtual void setVisibleRegionScreen(const Region& reg) {
486        getLayer()->visibleRegionScreen.rects =
487                reinterpret_cast<hwc_rect_t const *>(
488                        reg.getArray(&getLayer()->visibleRegionScreen.numRects));
489    }
490    virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
491        if (buffer == 0 || buffer->handle == 0) {
492            getLayer()->compositionType = HWC_FRAMEBUFFER;
493            getLayer()->flags |= HWC_SKIP_LAYER;
494            getLayer()->handle = 0;
495        } else {
496            getLayer()->handle = buffer->handle;
497        }
498    }
499};
500
501/*
502 * returns an iterator initialized at a given index in the layer list
503 */
504HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) {
505    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
506        return LayerListIterator();
507    }
508    const DisplayData& disp(mDisplayData[id]);
509    if (!mHwc || !disp.list || index > disp.list->numHwLayers) {
510        return LayerListIterator();
511    }
512    return LayerListIterator(new HWCLayerVersion1(disp.list->hwLayers), index);
513}
514
515/*
516 * returns an iterator on the beginning of the layer list
517 */
518HWComposer::LayerListIterator HWComposer::begin(int32_t id) {
519    return getLayerIterator(id, 0);
520}
521
522/*
523 * returns an iterator on the end of the layer list
524 */
525HWComposer::LayerListIterator HWComposer::end(int32_t id) {
526    return getLayerIterator(id, getNumLayers(id));
527}
528
529void HWComposer::dump(String8& result, char* buffer, size_t SIZE,
530        const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const {
531    if (mHwc) {
532        result.append("Hardware Composer state:\n");
533        result.appendFormat("  mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync);
534        for (size_t i=0 ; i<mNumDisplays ; i++) {
535            const DisplayData& disp(mDisplayData[i]);
536            if (disp.list) {
537                result.appendFormat("  id=%d, numHwLayers=%u, flags=%08x\n",
538                        i, disp.list->numHwLayers, disp.list->flags);
539                result.append(
540                        "   type   |  handle  |   hints  |   flags  | tr | blend |  format  |       source crop         |           frame           name \n"
541                        "----------+----------+----------+----------+----+-------+----------+---------------------------+--------------------------------\n");
542                //      " ________ | ________ | ________ | ________ | __ | _____ | ________ | [_____,_____,_____,_____] | [_____,_____,_____,_____]
543                for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
544                    const hwc_layer_1_t&l = disp.list->hwLayers[i];
545                    const sp<LayerBase> layer(visibleLayersSortedByZ[i]);
546                    int32_t format = -1;
547                    if (layer->getLayer() != NULL) {
548                        const sp<GraphicBuffer>& buffer(
549                                layer->getLayer()->getActiveBuffer());
550                        if (buffer != NULL) {
551                            format = buffer->getPixelFormat();
552                        }
553                    }
554                    result.appendFormat(
555                            " %8s | %08x | %08x | %08x | %02x | %05x | %08x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d] %s\n",
556                            l.compositionType ? "OVERLAY" : "FB",
557                                    intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format,
558                                    l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
559                                    l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
560                                    layer->getName().string());
561                }
562            }
563        }
564    }
565
566    if (mHwc && mHwc->dump) {
567        mHwc->dump(mHwc, buffer, SIZE);
568        result.append(buffer);
569    }
570}
571
572// ---------------------------------------------------------------------------
573
574HWComposer::VSyncThread::VSyncThread(HWComposer& hwc)
575    : mHwc(hwc), mEnabled(false),
576      mNextFakeVSync(0),
577      mRefreshPeriod(hwc.getRefreshPeriod())
578{
579}
580
581void HWComposer::VSyncThread::setEnabled(bool enabled) {
582    Mutex::Autolock _l(mLock);
583    mEnabled = enabled;
584    mCondition.signal();
585}
586
587void HWComposer::VSyncThread::onFirstRef() {
588    run("VSyncThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
589}
590
591bool HWComposer::VSyncThread::threadLoop() {
592    { // scope for lock
593        Mutex::Autolock _l(mLock);
594        while (!mEnabled) {
595            mCondition.wait(mLock);
596        }
597    }
598
599    const nsecs_t period = mRefreshPeriod;
600    const nsecs_t now = systemTime(CLOCK_MONOTONIC);
601    nsecs_t next_vsync = mNextFakeVSync;
602    nsecs_t sleep = next_vsync - now;
603    if (sleep < 0) {
604        // we missed, find where the next vsync should be
605        sleep = (period - ((now - next_vsync) % period));
606        next_vsync = now + sleep;
607    }
608    mNextFakeVSync = next_vsync + period;
609
610    struct timespec spec;
611    spec.tv_sec  = next_vsync / 1000000000;
612    spec.tv_nsec = next_vsync % 1000000000;
613
614    int err;
615    do {
616        err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
617    } while (err<0 && errno == EINTR);
618
619    if (err == 0) {
620        mHwc.mEventHandler.onVSyncReceived(0, next_vsync);
621    }
622
623    return true;
624}
625
626// ---------------------------------------------------------------------------
627}; // namespace android
628