hwc: Extend pause/resume functionality to VDS displays
Add support to handle pause/resume for virtual displays connected
either using VDS approach.
Change-Id: Iabd01c5597f2399ccc7f83712bda1a2c1103788d
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index e51a1a4..7bc29bc 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -32,6 +32,7 @@
#include "comptype.h"
#include "external.h"
#include "virtual.h"
+#include "hwc_virtual.h"
#include "mdp_version.h"
using namespace overlay;
namespace qhwc {
@@ -107,53 +108,15 @@
}
void handle_pause(hwc_context_t* ctx, int dpy) {
- {
- Locker::Autolock _l(ctx->mDrawLock);
- ctx->dpyAttr[dpy].isActive = true;
- ctx->dpyAttr[dpy].isPause = true;
- ctx->proc->invalidate(ctx->proc);
- }
- usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
- * 2 / 1000);
- // At this point all the pipes used by External have been
- // marked as UNSET.
- {
- Locker::Autolock _l(ctx->mDrawLock);
- // Perform commit to unstage the pipes.
- if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
- ALOGE("%s: display commit fail! for %d dpy",
- __FUNCTION__, dpy);
- }
+ if(ctx->mHWCVirtual) {
+ ctx->mHWCVirtual->pause(ctx, dpy);
}
return;
}
void handle_resume(hwc_context_t* ctx, int dpy) {
- //Treat Resume as Online event
- //Since external didnt have any pipes, force primary to give up
- //its pipes; we don't allow inter-mixer pipe transfers.
- {
- Locker::Autolock _l(ctx->mDrawLock);
-
- // A dynamic resolution change (DRC) can be made for a WiFi
- // display. In order to support the resolution change, we
- // need to reconfigure the corresponding display attributes.
- // Since DRC is only on WiFi display, we only need to call
- // configure() on the VirtualDisplay device.
- if(dpy == HWC_DISPLAY_VIRTUAL)
- ctx->mVirtualDisplay->configure();
-
- ctx->dpyAttr[dpy].isConfiguring = true;
- ctx->dpyAttr[dpy].isActive = true;
- ctx->proc->invalidate(ctx->proc);
- }
- usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
- * 2 / 1000);
- //At this point external has all the pipes it would need.
- {
- Locker::Autolock _l(ctx->mDrawLock);
- ctx->dpyAttr[dpy].isPause = false;
- ctx->proc->invalidate(ctx->proc);
+ if(ctx->mHWCVirtual) {
+ ctx->mHWCVirtual->resume(ctx, dpy);
}
return;
}
diff --git a/libhwcomposer/hwc_virtual.cpp b/libhwcomposer/hwc_virtual.cpp
index cc29d45..37d87e2 100644
--- a/libhwcomposer/hwc_virtual.cpp
+++ b/libhwcomposer/hwc_virtual.cpp
@@ -69,6 +69,7 @@
//Cleanup virtual display objs, since there is no explicit disconnect
if(ctx->dpyAttr[dpy].connected && (displays[dpy] == NULL)) {
ctx->dpyAttr[dpy].connected = false;
+ ctx->dpyAttr[dpy].isPause = false;
if(ctx->mFBUpdate[dpy]) {
delete ctx->mFBUpdate[dpy];
@@ -104,6 +105,7 @@
if(ctx->dpyAttr[dpy].connected == false) {
ctx->dpyAttr[dpy].connected = true;
+ ctx->dpyAttr[dpy].isPause = false;
// We set the vsync period to the primary refresh rate, leaving
// it up to the consumer to decide how fast to consume frames.
ctx->dpyAttr[dpy].vsync_period
@@ -113,16 +115,27 @@
// allow one padding round to free up resources but this breaks
// certain use cases.
}
+ if(!ctx->dpyAttr[dpy].isPause) {
+ ctx->dpyAttr[dpy].isConfiguring = false;
+ ctx->dpyAttr[dpy].fd = Writeback::getInstance()->getFbFd();
+ private_handle_t *ohnd = (private_handle_t *)list->outbuf;
+ Writeback::getInstance()->configureDpyInfo(ohnd->width,
+ ohnd->height);
+ setListStats(ctx, list, dpy);
- ctx->dpyAttr[dpy].isConfiguring = false;
- ctx->dpyAttr[dpy].fd = Writeback::getInstance()->getFbFd();
- private_handle_t *ohnd = (private_handle_t *)list->outbuf;
- Writeback::getInstance()->configureDpyInfo(ohnd->width, ohnd->height);
- setListStats(ctx, list, dpy);
-
- if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
- const int fbZ = 0;
- ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ);
+ if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
+ const int fbZ = 0;
+ ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ);
+ }
+ } else {
+ /* Virtual Display is in Pause state.
+ * Mark all application layers as OVERLAY so that
+ * GPU will not compose.
+ */
+ for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ layer->compositionType = HWC_OVERLAY;
+ }
}
}
return 0;
@@ -137,7 +150,9 @@
uint32_t last = list->numHwLayers - 1;
hwc_layer_1_t *fbLayer = &list->hwLayers[last];
- if(ctx->dpyAttr[dpy].connected) {
+ if(ctx->dpyAttr[dpy].connected
+ && (!ctx->dpyAttr[dpy].isPause))
+ {
private_handle_t *ohnd = (private_handle_t *)list->outbuf;
int format = ohnd->format;
if (format == HAL_PIXEL_FORMAT_RGBA_8888)
@@ -194,6 +209,36 @@
return ret;
}
+void HWCVirtualVDS::pause(hwc_context_t* ctx, int dpy) {
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ ctx->dpyAttr[dpy].isActive = true;
+ ctx->dpyAttr[dpy].isPause = true;
+ ctx->proc->invalidate(ctx->proc);
+ }
+ usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+ * 2 / 1000);
+ return;
+}
+
+void HWCVirtualVDS::resume(hwc_context_t* ctx, int dpy) {
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ ctx->dpyAttr[dpy].isConfiguring = true;
+ ctx->dpyAttr[dpy].isActive = true;
+ ctx->proc->invalidate(ctx->proc);
+ }
+ usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+ * 2 / 1000);
+ //At this point external has all the pipes it would need.
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ ctx->dpyAttr[dpy].isPause = false;
+ ctx->proc->invalidate(ctx->proc);
+ }
+ return;
+}
+
/* Implementation for HWCVirtualV4L2 class */
int HWCVirtualV4L2::prepare(hwc_composer_device_1 *dev,
@@ -294,3 +339,56 @@
return ret;
}
+
+void HWCVirtualV4L2::pause(hwc_context_t* ctx, int dpy) {
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ ctx->dpyAttr[dpy].isActive = true;
+ ctx->dpyAttr[dpy].isPause = true;
+ ctx->proc->invalidate(ctx->proc);
+ }
+ usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+ * 2 / 1000);
+ // At this point all the pipes used by External have been
+ // marked as UNSET.
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ // Perform commit to unstage the pipes.
+ if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail! for %d dpy",
+ __FUNCTION__, dpy);
+ }
+ }
+ return;
+}
+
+void HWCVirtualV4L2::resume(hwc_context_t* ctx, int dpy){
+ //Treat Resume as Online event
+ //Since external didnt have any pipes, force primary to give up
+ //its pipes; we don't allow inter-mixer pipe transfers.
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+
+ // A dynamic resolution change (DRC) can be made for a WiFi
+ // display. In order to support the resolution change, we
+ // need to reconfigure the corresponding display attributes.
+ // Since DRC is only on WiFi display, we only need to call
+ // configure() on the VirtualDisplay device.
+ //TODO: clean up
+ if(dpy == HWC_DISPLAY_VIRTUAL)
+ ctx->mVirtualDisplay->configure();
+
+ ctx->dpyAttr[dpy].isConfiguring = true;
+ ctx->dpyAttr[dpy].isActive = true;
+ ctx->proc->invalidate(ctx->proc);
+ }
+ usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+ * 2 / 1000);
+ //At this point external has all the pipes it would need.
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ ctx->dpyAttr[dpy].isPause = false;
+ ctx->proc->invalidate(ctx->proc);
+ }
+ return;
+}
diff --git a/libhwcomposer/hwc_virtual.h b/libhwcomposer/hwc_virtual.h
index 26f401f..6bc3898 100644
--- a/libhwcomposer/hwc_virtual.h
+++ b/libhwcomposer/hwc_virtual.h
@@ -22,6 +22,7 @@
#define HWC_VIRTUAL
#include <hwc_utils.h>
+#include <virtual.h>
namespace qhwc {
namespace ovutils = overlay::utils;
@@ -39,6 +40,8 @@
virtual void init(hwc_context_t *ctx) = 0;
virtual void destroy(hwc_context_t *ctx, size_t numDisplays,
hwc_display_contents_1_t** displays) = 0;
+ virtual void pause(hwc_context_t* ctx, int dpy) = 0;
+ virtual void resume(hwc_context_t* ctx, int dpy) = 0;
};
class HWCVirtualVDS : public HWCVirtualBase {
@@ -59,6 +62,8 @@
// during virtual display disconnect.
virtual void destroy(hwc_context_t *ctx, size_t numDisplays,
hwc_display_contents_1_t** displays);
+ virtual void pause(hwc_context_t* ctx, int dpy);
+ virtual void resume(hwc_context_t* ctx, int dpy);
};
class HWCVirtualV4L2 : public HWCVirtualBase {
@@ -80,6 +85,8 @@
// during virtual display disconnect. This function is no-op for V4L2 design
virtual void destroy(hwc_context_t *, size_t ,
hwc_display_contents_1_t** ) {};
+ virtual void pause(hwc_context_t* ctx, int dpy);
+ virtual void resume(hwc_context_t* ctx, int dpy);
};
}; //namespace