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