From 667b57834d261dab9eea25ad68d214a4022af725 Mon Sep 17 00:00:00 2001 From: Thomas Perl Date: Thu, 29 May 2014 13:33:55 +0200 Subject: [PATCH 1/2] [v11] Support for external displays (WIP) --- hwcomposer/hwcomposer_backend.cpp | 1 + hwcomposer/hwcomposer_backend_v11.cpp | 508 ++++++++++++++++++++------ hwcomposer/hwcomposer_backend_v11.h | 43 ++- 3 files changed, 439 insertions(+), 113 deletions(-) diff --git a/hwcomposer/hwcomposer_backend.cpp b/hwcomposer/hwcomposer_backend.cpp index 3b7864a..af684a6 100644 --- a/hwcomposer/hwcomposer_backend.cpp +++ b/hwcomposer/hwcomposer_backend.cpp @@ -120,6 +120,7 @@ HwComposerBackend::create() #endif /* HWC_DEVICE_API_VERSION_1_0 */ #ifdef HWC_PLUGIN_HAVE_HWCOMPOSER1_API case HWC_DEVICE_API_VERSION_1_1: + // "For HWC 1.1, numDisplays will always be HWC_NUM_PHYSICAL_DISPLAY_TYPES" return new HwComposerBackend_v11(hwc_module, hwc_device, HWC_NUM_DISPLAY_TYPES); break; #ifdef HWC_DEVICE_API_VERSION_1_2 diff --git a/hwcomposer/hwcomposer_backend_v11.cpp b/hwcomposer/hwcomposer_backend_v11.cpp index 6edcb02..093ea47 100644 --- a/hwcomposer/hwcomposer_backend_v11.cpp +++ b/hwcomposer/hwcomposer_backend_v11.cpp @@ -43,69 +43,373 @@ #ifdef HWC_PLUGIN_HAVE_HWCOMPOSER1_API -class HWComposer : public HWComposerNativeWindow +static int g_external_connected = 0; +static int g_unblanked_displays[HWC_NUM_DISPLAY_TYPES] = { 0 }; + +class HwComposerBackendWindow_v11 : public HWComposerNativeWindow { - private: - hwc_layer_1_t *fblayer; - hwc_composer_device_1_t *hwcdevice; - hwc_display_contents_1_t **mlist; - int num_displays; - protected: - void present(HWComposerNativeWindowBuffer *buffer); - - public: - - HWComposer(unsigned int width, unsigned int height, unsigned int format, - hwc_composer_device_1_t *device, hwc_display_contents_1_t **mList, - hwc_layer_1_t *layer, int num_displays); - void set(); +public: + HwComposerBackendWindow_v11(unsigned int width, unsigned int height, + unsigned int format, HwComposerBackend_v11 *backend) + : HWComposerNativeWindow(width, height, format) + , backend(backend) + { + } + +protected: + void present(HWComposerNativeWindowBuffer *buffer) + { + RetireFencePool pool; + + // Obtain a new acquire fence to be used, then also + // set the new release fence with the return value + int fence = getFenceBufferFd(buffer); + fence = backend->present(&pool, buffer->handle, fence); + setFenceBufferFd(buffer, fence); + + // Retire fence pool will wait on and close all FDs consumed here + } + +private: + HwComposerBackend_v11 *backend; }; -HWComposer::HWComposer(unsigned int width, unsigned int height, unsigned int format, - hwc_composer_device_1_t *device, hwc_display_contents_1_t **mList, - hwc_layer_1_t *layer, int num_displays) - : HWComposerNativeWindow(width, height, format) - , fblayer(layer) - , hwcdevice(device) - , mlist(mList) - , num_displays(num_displays) + +static void +hwcv11_proc_invalidate(const struct hwc_procs* procs) { + fprintf(stderr, "%s: procs=%x\n", __func__, procs); } -void HWComposer::present(HWComposerNativeWindowBuffer *buffer) +static void +hwcv11_proc_vsync(const struct hwc_procs* procs, int disp, int64_t timestamp) { - int oldretire = mlist[0]->retireFenceFd; - mlist[0]->retireFenceFd = -1; - fblayer->handle = buffer->handle; - fblayer->acquireFenceFd = getFenceBufferFd(buffer); - fblayer->releaseFenceFd = -1; + fprintf(stderr, "%s: procs=%x, disp=%d, timestamp=%.0f\n", __func__, procs, disp, (float)timestamp); +} - int err = hwcdevice->prepare(hwcdevice, num_displays, mlist); - HWC_PLUGIN_EXPECT_ZERO(err); +static void +hwcv11_proc_hotplug(const struct hwc_procs* procs, int disp, int connected) +{ + fprintf(stderr, "%s: procs=%x, disp=%d, connected=%d\n", __func__, procs, disp, connected); + if (disp == HWC_DISPLAY_EXTERNAL) { + g_external_connected = connected; + // TODO: Force re-run of sleep display so that the external display is + // powered on immediately (and not only after blank/unblank cycle) + } +} - err = hwcdevice->set(hwcdevice, num_displays, mlist); - HWC_PLUGIN_EXPECT_ZERO(err); +static hwc_procs_t hwcv11_procs = { + hwcv11_proc_invalidate, + hwcv11_proc_vsync, + hwcv11_proc_hotplug, +}; - setFenceBufferFd(buffer, fblayer->releaseFenceFd); +static void +get_screen_size(hwc_composer_device_1_t *hwc_device, int id, int *width, int *height) +{ + size_t count = 1; + uint32_t config = 0; + if (hwc_device->getDisplayConfigs(hwc_device, id, &config, &count) == 0) { + uint32_t attrs[] = { + HWC_DISPLAY_WIDTH, + HWC_DISPLAY_HEIGHT, + HWC_DISPLAY_NO_ATTRIBUTE, + }; + int32_t values[] = { + 0, + 0, + 0, + }; + + hwc_device->getDisplayAttributes(hwc_device, id, config, attrs, values); + //fprintf(stderr, "Display %d size: %dx%d\n", id, values[0], values[1]); + *width = values[0]; + *height = values[1]; + } else { + //fprintf(stderr, "No size for display %d (not connected)\n", id); + } +} + +static void +dump_attributes(hwc_composer_device_1_t *hwc_device, int num_displays) +{ + // Get display configs + for (int dpy=0; dpygetDisplayConfigs(hwc_device, dpy, configs, &numConfigs) != 0) { + fprintf(stderr, "Display %d not connected, no configs\n", dpy); + continue; + } - if (oldretire != -1) - { - sync_wait(oldretire, -1); - close(oldretire); + fprintf(stderr, "%d configs found for display %d\n", numConfigs, dpy); + + for (int i=0; igetDisplayAttributes(hwc_device, dpy, configs[i], + attributes, values); + + fprintf(stderr, "Dpy %d Cfg %d (%d) VSYNC_PERIOD=%d, SIZE=(%d, %d), DPY=(%d, %d)\n", + dpy, i, configs[i], values[0], values[1], values[2], values[3], values[4]); + } } } +// contents for a single screen +class HwComposerScreen_v11 { +public: + enum Layer { + // Layers we use for composition + HWC_SCREEN_FRAMEBUFFER_LAYER = 0, + HWC_SCREEN_FRAMEBUFFER_TARGET_LAYER = 1, + + // Number of layers we need to allocate space for + HWC_SCREEN_REQUIRED_LAYERS = 2, + }; + + HwComposerScreen_v11(hwc_composer_device_1_t *hwc_device, int id) + : hwc_device(hwc_device) + , id(id) + , hwc_list(nullptr) + { + size_t needed_size = sizeof(hwc_display_contents_1_t) + + HWC_SCREEN_REQUIRED_LAYERS * sizeof(hwc_layer_1_t); + + hwc_list = (hwc_display_contents_1_t *) calloc(1, needed_size); + + // Need to set this here, and not every time in relayout + hwc_list->numHwLayers = 2; + hwc_list->retireFenceFd = -1; + } + + bool relayout(int width, int height) + { + // Source rectangle of the desktop + const hwc_rect_t source_rect = { + 0, 0, width, height + }; + + int ww = width, hh = height; + get_screen_size(hwc_device, id, &ww, &hh); + + // Destination rectangle on the actual screen + const hwc_rect_t dest_rect = { + 0, 0, ww, hh + }; + + hwc_layer_1_t *layer = NULL; + + layer = getLayer(HWC_SCREEN_FRAMEBUFFER_LAYER); + resetLayer(layer); + + layer->compositionType = HWC_FRAMEBUFFER; + layer->sourceCrop = source_rect; + layer->displayFrame = dest_rect; + layer->visibleRegionScreen.numRects = 1; + layer->visibleRegionScreen.rects = &layer->displayFrame; + + layer = getLayer(HWC_SCREEN_FRAMEBUFFER_TARGET_LAYER); + resetLayer(layer); + + layer->compositionType = HWC_FRAMEBUFFER_TARGET; + layer->transform = (ww > hh) ? HWC_TRANSFORM_ROT_270 : 0; // FIXME: be more intelligent than "ww > hh" + layer->sourceCrop = source_rect; + layer->displayFrame = dest_rect; + layer->visibleRegionScreen.numRects = 1; + layer->visibleRegionScreen.rects = &layer->displayFrame; + layer->acquireFenceFd = -1; + layer->releaseFenceFd = -1; + + // For now, we always return true (=geometry has changed) + return true; + } + + ~HwComposerScreen_v11() + { + free(hwc_list); + } + + hwc_display_contents_1_t *get() + { + return hwc_list; + } + + void prepare(buffer_handle_t handle, int acquireFenceFd, bool geometryChanged) + { + trace_fds(__func__); + + hwc_layer_1_t *fblayer = getLayer(HWC_SCREEN_FRAMEBUFFER_TARGET_LAYER); + + fblayer->handle = handle; + + if (g_unblanked_displays[id]) { + fprintf(stderr, "%s: dup'ing acquire fence (%d) for display %d\n", __func__, + acquireFenceFd, id); + fblayer->acquireFenceFd = dup(acquireFenceFd); + } else { + fblayer->acquireFenceFd = -1; + } + + fblayer->releaseFenceFd = -1; + + if (geometryChanged) { + hwc_list->flags |= HWC_GEOMETRY_CHANGED; + } + } + + int release(int result) + { + trace_fds(__func__); + + // We assume the non-FB-target layer has its releaseFenceFd set to -1 + HWC_PLUGIN_EXPECT_ZERO(getLayer(HWC_SCREEN_FRAMEBUFFER_LAYER)->releaseFenceFd != -1); + + hwc_layer_1_t *fblayer = getLayer(HWC_SCREEN_FRAMEBUFFER_TARGET_LAYER); + + if (result == -1) { + // we have found a fence to return + result = fblayer->releaseFenceFd; + } else { + // additional fences need to be closed here + if (fblayer->releaseFenceFd != -1) { +#if 0 + fprintf(stderr, "Merging release fences\n"); + result = sync_merge("qpa-hwc-merged", result, fblayer->releaseFenceFd); +#endif + fprintf(stderr, "Closing release fence\n"); + //sync_wait(fblayer->releaseFenceFd, -1); // Need to wait, too? + close(fblayer->releaseFenceFd); + } + + } + + fblayer->releaseFenceFd = -1; + + return result; + } + +private: // functions + void resetLayer(hwc_layer_1_t *layer) + { + layer->hints = 0; + layer->flags = 0; + layer->handle = 0; + layer->transform = 0; + + layer->blending = HWC_BLENDING_NONE; + + layer->acquireFenceFd = -1; + layer->releaseFenceFd = -1; + } + + hwc_layer_1_t *getLayer(enum Layer layer) + { + return &hwc_list->hwLayers[layer]; + } + + void trace_fds(const char *func) + { + fprintf(stderr, "[%s] fds for dpy %d: FTa %d FTr %d FBa %d FBr %d\n", + func, id, + getLayer(HWC_SCREEN_FRAMEBUFFER_TARGET_LAYER)->acquireFenceFd, + getLayer(HWC_SCREEN_FRAMEBUFFER_TARGET_LAYER)->releaseFenceFd, + getLayer(HWC_SCREEN_FRAMEBUFFER_LAYER)->acquireFenceFd, + getLayer(HWC_SCREEN_FRAMEBUFFER_LAYER)->releaseFenceFd); + } + +private: // members + hwc_composer_device_1_t *hwc_device; + int id; + hwc_display_contents_1_t *hwc_list; +}; + + +// collection of screens +class HwComposerContent_v11 { +public: + HwComposerContent_v11(hwc_composer_device_1_t *hwc_device, int num_displays) + : hwc_device(hwc_device) + , num_displays(num_displays) + , screens() + , contents((hwc_display_contents_1_t **)calloc(num_displays, + sizeof(hwc_display_contents_1_t *))) + { + for (int i=0; irelayout(width, height)) { + geometryChanged = true; + } + + screen->prepare(handle, acquireFenceFd, geometryChanged); + } + + // We can close the acquire fence here, as we've dup'ed it for all displays here already + //sync_wait(acquireFenceFd, -1); + close(acquireFenceFd); + } + + int release() { + int result = -1; + + for (auto &screen: screens) { + result = screen->release(result); + } + + return result; + } + + hwc_display_contents_1_t **get() + { + // Assemble content for all screens + for (int i=0; iget(); + } + + return contents; + } + +private: + hwc_composer_device_1_t *hwc_device; + int num_displays; + std::vector screens; + hwc_display_contents_1_t **contents; +}; + + HwComposerBackend_v11::HwComposerBackend_v11(hw_module_t *hwc_module, hw_device_t *hw_device, int num_displays) : HwComposerBackend(hwc_module) , hwc_device((hwc_composer_device_1_t *)hw_device) , hwc_win(NULL) - , hwc_list(NULL) - , hwc_mList(NULL) - , oldretire(-1) - , oldrelease(-1) - , oldrelease2(-1) , num_displays(num_displays) + , width(0) + , height(0) + , content(new HwComposerContent_v11(hwc_device, num_displays)) { + fprintf(stderr, "Registering hwc procs\n"); + hwc_device->registerProcs(hwc_device, &hwcv11_procs); sleepDisplay(false); } @@ -116,16 +420,11 @@ HwComposerBackend_v11::~HwComposerBackend_v11() delete hwc_win; } + // Destroy the content layout + delete content; + // Close the hwcomposer handle HWC_PLUGIN_EXPECT_ZERO(hwc_close_1(hwc_device)); - - if (hwc_mList != NULL) { - free(hwc_mList); - } - - if (hwc_list != NULL) { - free(hwc_list); - } } EGLNativeDisplayType @@ -140,57 +439,11 @@ HwComposerBackend_v11::createWindow(int width, int height) // We expect that we haven't created a window already, if we had, we // would leak stuff, and we want to avoid that for obvious reasons. HWC_PLUGIN_EXPECT_NULL(hwc_win); - HWC_PLUGIN_EXPECT_NULL(hwc_list); - HWC_PLUGIN_EXPECT_NULL(hwc_mList); - - - size_t neededsize = sizeof(hwc_display_contents_1_t) + 2 * sizeof(hwc_layer_1_t); - hwc_list = (hwc_display_contents_1_t *) malloc(neededsize); - hwc_mList = (hwc_display_contents_1_t **) malloc(num_displays * sizeof(hwc_display_contents_1_t *)); - const hwc_rect_t r = { 0, 0, width, height }; - - for (int i = 0; i < num_displays; i++) { - hwc_mList[i] = hwc_list; - } - - hwc_layer_1_t *layer = NULL; - - layer = &hwc_list->hwLayers[0]; - memset(layer, 0, sizeof(hwc_layer_1_t)); - layer->compositionType = HWC_FRAMEBUFFER; - layer->hints = 0; - layer->flags = 0; - layer->handle = 0; - layer->transform = 0; - layer->blending = HWC_BLENDING_NONE; - layer->sourceCrop = r; - layer->displayFrame = r; - layer->visibleRegionScreen.numRects = 1; - layer->visibleRegionScreen.rects = &layer->displayFrame; - layer->acquireFenceFd = -1; - layer->releaseFenceFd = -1; - - layer = &hwc_list->hwLayers[1]; - memset(layer, 0, sizeof(hwc_layer_1_t)); - layer->compositionType = HWC_FRAMEBUFFER_TARGET; - layer->hints = 0; - layer->flags = 0; - layer->handle = 0; - layer->transform = 0; - layer->blending = HWC_BLENDING_NONE; - layer->sourceCrop = r; - layer->displayFrame = r; - layer->visibleRegionScreen.numRects = 1; - layer->visibleRegionScreen.rects = &layer->displayFrame; - layer->acquireFenceFd = -1; - layer->releaseFenceFd = -1; - - hwc_list->retireFenceFd = -1; - hwc_list->flags = HWC_GEOMETRY_CHANGED; - hwc_list->numHwLayers = 2; - - hwc_win = new HWComposer(width, height, HAL_PIXEL_FORMAT_RGBA_8888, - hwc_device, hwc_mList, &hwc_list->hwLayers[1], num_displays); + + this->width = width; + this->height = height; + + hwc_win = new HwComposerBackendWindow_v11(width, height, HAL_PIXEL_FORMAT_RGBA_8888, this); return (EGLNativeWindowType) static_cast(hwc_win); } @@ -199,7 +452,7 @@ HwComposerBackend_v11::destroyWindow(EGLNativeWindowType window) { Q_UNUSED(window); - // FIXME: Implement (delete hwc_win + set it to NULL?) + // FIXME: Implement (delete hwc_win + set it to NULL?, also set size to 0x0) } void @@ -212,17 +465,56 @@ HwComposerBackend_v11::swap(EGLNativeDisplayType display, EGLSurface surface) eglSwapBuffers(display, surface); } +int +HwComposerBackend_v11::present(RetireFencePool *pool, buffer_handle_t handle, int acquireFenceFd) +{ + // Always force geometry change for now, later on + // only do that on unblank/blank and attach/detach + bool geometryChanged = true; + + content->prepare(handle, acquireFenceFd, width, height, geometryChanged); + + auto display_list = content->get(); + + // Collect and reset all retire fence fds + for (int i=0; iconsume(display_list[i]->retireFenceFd); + } + + HWC_PLUGIN_EXPECT_ZERO(hwc_device->prepare(hwc_device, num_displays, display_list)); + HWC_PLUGIN_EXPECT_ZERO(hwc_device->set(hwc_device, num_displays, display_list)); + + return content->release(); +} + void HwComposerBackend_v11::sleepDisplay(bool sleep) { + // XXX: For debugging only + //dump_attributes(hwc_device, num_displays); + if (sleep) { - HWC_PLUGIN_EXPECT_ZERO(hwc_device->blank(hwc_device, 0, 1)); + for (int i=0; iblank(hwc_device, i, 1) != 0); + } + } } else { - HWC_PLUGIN_EXPECT_ZERO(hwc_device->blank(hwc_device, 0, 0)); - - if (hwc_list) { - hwc_list->flags |= HWC_GEOMETRY_CHANGED; +#if 0 + for (int i=0; iblank(hwc_device, i, 0) == 0); + } +#endif + + if (g_external_connected) { + fprintf(stderr, "Unblanking external display\n"); + g_unblanked_displays[1] = (hwc_device->blank(hwc_device, 1, 0) == 0); + } else { + fprintf(stderr, "Unblanking internal display\n"); + g_unblanked_displays[0] = (hwc_device->blank(hwc_device, 0, 0) == 0); } + + // TODO: Force geometry change } } diff --git a/hwcomposer/hwcomposer_backend_v11.h b/hwcomposer/hwcomposer_backend_v11.h index 46b34d3..e18994a 100644 --- a/hwcomposer/hwcomposer_backend_v11.h +++ b/hwcomposer/hwcomposer_backend_v11.h @@ -49,6 +49,38 @@ // libhybris access to the native hwcomposer window #include +// Helper class that takes care of waiting on and closing a set +// of file descriptors +class RetireFencePool { +public: + RetireFencePool() + : m_fds() + { + } + + ~RetireFencePool() + { + for (auto fd: m_fds) { + fprintf(stderr, "Waiting and closing retire fence fd: %d\n", fd); + sync_wait(fd, -1); + close(fd); + } + } + + void consume(int &fd) + { + if (fd != -1) { + m_fds.push_back(fd); + fd = -1; + } + } + +private: + std::vector m_fds; +}; + +class HwComposerContent_v11; + class HwComposerBackend_v11 : public HwComposerBackend { public: HwComposerBackend_v11(hw_module_t *hwc_module, hw_device_t *hw_device, int num_displays); @@ -61,15 +93,16 @@ class HwComposerBackend_v11 : public HwComposerBackend { virtual void sleepDisplay(bool sleep); virtual float refreshRate(); + // Present method that does the buffer swapping, returns the releaseFenceFd + int present(RetireFencePool *pool, buffer_handle_t handle, int acquireFenceFd); + private: hwc_composer_device_1_t *hwc_device; HWComposerNativeWindow *hwc_win; - hwc_display_contents_1_t *hwc_list; - hwc_display_contents_1_t **hwc_mList; - int oldretire; - int oldrelease; - int oldrelease2; int num_displays; + int width; + int height; + HwComposerContent_v11 *content; }; #endif /* HWC_PLUGIN_HAVE_HWCOMPOSER1_API */ From fc630c8831fd2f728eea3af6c16b271f71b1bae2 Mon Sep 17 00:00:00 2001 From: Thomas Perl Date: Fri, 6 Jun 2014 14:38:53 +0200 Subject: [PATCH 2/2] [v11] HDMI out: Switch to external display without blanking --- hwcomposer/hwcomposer_backend_v11.cpp | 24 +++++++++++++++++++++--- hwcomposer/hwcomposer_backend_v11.h | 1 + 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/hwcomposer/hwcomposer_backend_v11.cpp b/hwcomposer/hwcomposer_backend_v11.cpp index 093ea47..989984e 100644 --- a/hwcomposer/hwcomposer_backend_v11.cpp +++ b/hwcomposer/hwcomposer_backend_v11.cpp @@ -44,6 +44,7 @@ #ifdef HWC_PLUGIN_HAVE_HWCOMPOSER1_API static int g_external_connected = 0; +static int g_external_connected_next = 0; static int g_unblanked_displays[HWC_NUM_DISPLAY_TYPES] = { 0 }; class HwComposerBackendWindow_v11 : public HWComposerNativeWindow @@ -92,9 +93,7 @@ hwcv11_proc_hotplug(const struct hwc_procs* procs, int disp, int connected) { fprintf(stderr, "%s: procs=%x, disp=%d, connected=%d\n", __func__, procs, disp, connected); if (disp == HWC_DISPLAY_EXTERNAL) { - g_external_connected = connected; - // TODO: Force re-run of sleep display so that the external display is - // powered on immediately (and not only after blank/unblank cycle) + g_external_connected_next = connected; } } @@ -407,6 +406,7 @@ HwComposerBackend_v11::HwComposerBackend_v11(hw_module_t *hwc_module, hw_device_ , width(0) , height(0) , content(new HwComposerContent_v11(hwc_device, num_displays)) + , display_sleeping(false) { fprintf(stderr, "Registering hwc procs\n"); hwc_device->registerProcs(hwc_device, &hwcv11_procs); @@ -461,6 +461,14 @@ HwComposerBackend_v11::swap(EGLNativeDisplayType display, EGLSurface surface) // TODO: Wait for vsync? HWC_PLUGIN_ASSERT_NOT_NULL(hwc_win); + + if (g_external_connected != g_external_connected_next) { + g_external_connected = g_external_connected_next; + + // Force re-run of sleep display so that the external display is + // powered on/off immediately (and not only after blank/unblank cycle) + sleepDisplay(display_sleeping); + } eglSwapBuffers(display, surface); } @@ -507,15 +515,25 @@ HwComposerBackend_v11::sleepDisplay(bool sleep) #endif if (g_external_connected) { + if (g_unblanked_displays[0]) { + fprintf(stderr, "Blanking internal display\n"); + g_unblanked_displays[0] = (hwc_device->blank(hwc_device, 0, 1) != 0); + } fprintf(stderr, "Unblanking external display\n"); g_unblanked_displays[1] = (hwc_device->blank(hwc_device, 1, 0) == 0); } else { + if (g_unblanked_displays[1]) { + fprintf(stderr, "Blanking external display\n"); + g_unblanked_displays[1] = (hwc_device->blank(hwc_device, 1, 1) != 0); + } fprintf(stderr, "Unblanking internal display\n"); g_unblanked_displays[0] = (hwc_device->blank(hwc_device, 0, 0) == 0); } // TODO: Force geometry change } + + display_sleeping = sleep; } float diff --git a/hwcomposer/hwcomposer_backend_v11.h b/hwcomposer/hwcomposer_backend_v11.h index e18994a..eac5ec4 100644 --- a/hwcomposer/hwcomposer_backend_v11.h +++ b/hwcomposer/hwcomposer_backend_v11.h @@ -103,6 +103,7 @@ class HwComposerBackend_v11 : public HwComposerBackend { int width; int height; HwComposerContent_v11 *content; + bool display_sleeping; }; #endif /* HWC_PLUGIN_HAVE_HWCOMPOSER1_API */