Display and wfd synchronization during teardown
* Provide a binder interface call for wfd module
to inform display about the start/stop/pause/resume
of wfd session.
* This is needed for wfd-hdmi synchronization in
case of v4l2 wfd solution. If hdmi is plugged
in during v4l2 wfd session, display-hal waits in
uevent thread for wfd teardown notification from
wfd module, before going ahead with configuring
external display.
* For VDS WFD solution, display-hal waits in uevent
thread for wfd-teardown to be signalled from
the composition thread.
Change-Id: I9514cb5bc7ff81de0b5dd4cdf66d8286a64ba094
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 5313795..976b23d 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -157,6 +157,9 @@
}
static void pauseWFD(hwc_context_t *ctx, uint32_t pause) {
+ /* TODO: Will remove pauseWFD once all the clients start using
+ * setWfdStatus to indicate the status of WFD display
+ */
int dpy = HWC_DISPLAY_VIRTUAL;
if(pause) {
//WFD Pause
@@ -167,6 +170,24 @@
}
}
+static void setWfdStatus(hwc_context_t *ctx, uint32_t wfdStatus) {
+
+ ALOGD_IF(HWC_WFDDISPSYNC_LOG,
+ "%s: Received a binder call that WFD state is %s",
+ __FUNCTION__,getExternalDisplayState(wfdStatus));
+ int dpy = HWC_DISPLAY_VIRTUAL;
+
+ if(wfdStatus == EXTERNAL_OFFLINE) {
+ ctx->mWfdSyncLock.lock();
+ ctx->mWfdSyncLock.signal();
+ ctx->mWfdSyncLock.unlock();
+ } else if(wfdStatus == EXTERNAL_PAUSE) {
+ handle_pause(ctx, dpy);
+ } else if(wfdStatus == EXTERNAL_RESUME) {
+ handle_resume(ctx, dpy);
+ }
+}
+
status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
Parcel* outParcel) {
status_t ret = NO_ERROR;
@@ -199,15 +220,17 @@
break;
case IQService::SET_HSIC_DATA:
setHSIC(inParcel);
+ break;
case IQService::PAUSE_WFD:
pauseWFD(mHwcContext, inParcel->readInt32());
break;
+ case IQService::SET_WFD_STATUS:
+ setWfdStatus(mHwcContext,inParcel->readInt32());
+ break;
default:
ret = NO_ERROR;
}
return ret;
}
-
-
}
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index e1f7827..fed6f3c 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -39,14 +39,6 @@
#define HWC_UEVENT_SWITCH_STR "change@/devices/virtual/switch/"
#define HWC_UEVENT_THREAD_NAME "hwcUeventThread"
-/* External Display states */
-enum {
- EXTERNAL_OFFLINE = 0,
- EXTERNAL_ONLINE,
- EXTERNAL_PAUSE,
- EXTERNAL_RESUME
-};
-
static void setup(hwc_context_t* ctx, int dpy)
{
ctx->mFBUpdate[dpy] = IFBUpdate::getObject(ctx, dpy);
@@ -145,9 +137,24 @@
ctx->mVirtualonExtActive = false;
}
}
- /* Wait for few frames for SF to tear down the WFD session. */
- usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
- * 2 / 1000);
+
+ if(ctx->mVDSEnabled) {
+ ctx->mWfdSyncLock.lock();
+ ALOGD_IF(HWC_WFDDISPSYNC_LOG,
+ "%s: Waiting for wfd-teardown to be signalled",__FUNCTION__);
+ ctx->mWfdSyncLock.wait();
+ ALOGD_IF(HWC_WFDDISPSYNC_LOG,
+ "%s: Teardown signalled. Completed waiting in uevent thread",
+ __FUNCTION__);
+ ctx->mWfdSyncLock.unlock();
+ } else {
+ /*TODO: Remove this else block and have wait rather than usleep
+ once wfd module issues binder call on teardown.*/
+
+ /* For now, Wait for few frames for SF to tear down the WFD session.*/
+ usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+ * 2 / 1000);
+ }
}
static void handle_uevent(hwc_context_t* ctx, const char* udata, int len)
@@ -166,7 +173,7 @@
int switch_state = getConnectedState(udata, len);
- ALOGE_IF(UEVENT_DEBUG,"%s: uevent recieved: %s switch state: %d",
+ ALOGE_IF(UEVENT_DEBUG,"%s: uevent received: %s switch state: %d",
__FUNCTION__,udata, switch_state);
switch(switch_state) {
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 3f5d77a..54445aa 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -182,6 +182,7 @@
void initContext(hwc_context_t *ctx)
{
openFramebufferDevice(ctx);
+ char value[PROPERTY_VALUE_MAX];
ctx->mMDP.version = qdutils::MDPVersion::getInstance().getMDPVersion();
ctx->mMDP.hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay();
ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType();
@@ -223,7 +224,14 @@
ctx->mMDPComp[HWC_DISPLAY_PRIMARY] =
MDPComp::getObject(ctx, HWC_DISPLAY_PRIMARY);
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true;
- ctx->mHWCVirtual = HWCVirtualBase::getObject();
+
+ ctx->mVDSEnabled = false;
+ if((property_get("persist.hwc.enable_vds", value, NULL) > 0)) {
+ if(atoi(value) != 0) {
+ ctx->mVDSEnabled = true;
+ }
+ }
+ ctx->mHWCVirtual = HWCVirtualBase::getObject(ctx->mVDSEnabled);
for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
ctx->mHwcDebug[i] = new HwcDebug(i);
@@ -260,7 +268,6 @@
// Read the system property to determine if downscale feature is enabled.
ctx->mMDPDownscaleEnabled = false;
- char value[PROPERTY_VALUE_MAX];
if(property_get("sys.hwc.mdp_downscale_enabled", value, "false")
&& !strcmp(value, "true")) {
ctx->mMDPDownscaleEnabled = true;
@@ -639,6 +646,21 @@
return extOrientation;
}
+/* Get External State names */
+const char* getExternalDisplayState(uint32_t external_state) {
+ static const char* externalStates[EXTERNAL_MAXSTATES] = {0};
+ externalStates[EXTERNAL_OFFLINE] = STR(EXTERNAL_OFFLINE);
+ externalStates[EXTERNAL_ONLINE] = STR(EXTERNAL_ONLINE);
+ externalStates[EXTERNAL_PAUSE] = STR(EXTERNAL_PAUSE);
+ externalStates[EXTERNAL_RESUME] = STR(EXTERNAL_RESUME);
+
+ if(external_state >= EXTERNAL_MAXSTATES) {
+ return "EXTERNAL_INVALID";
+ }
+
+ return externalStates[external_state];
+}
+
bool isDownscaleRequired(hwc_layer_1_t const* layer) {
hwc_rect_t displayFrame = layer->displayFrame;
hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index ed68988..726311b 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -39,6 +39,8 @@
#define MAX_NUM_APP_LAYERS 32
#define MIN_DISPLAY_XRES 200
#define MIN_DISPLAY_YRES 200
+#define HWC_WFDDISPSYNC_LOG 0
+#define STR(f) #f;
//Fwrd decls
struct hwc_context_t;
@@ -154,6 +156,15 @@
HWC_FORMAT_RB_SWAP = 0x00000040,
};
+/* External Display states */
+enum {
+ EXTERNAL_OFFLINE = 0,
+ EXTERNAL_ONLINE,
+ EXTERNAL_PAUSE,
+ EXTERNAL_RESUME,
+ EXTERNAL_MAXSTATES
+};
+
class LayerRotMap {
public:
LayerRotMap() { reset(); }
@@ -280,6 +291,9 @@
// BufferMirrirMode(Sidesync)
int getMirrorModeOrientation(hwc_context_t *ctx);
+/* Get External State names */
+const char* getExternalDisplayState(uint32_t external_state);
+
// Handles wfd Pause and resume events
void handle_pause(hwc_context_t *ctx, int dpy);
void handle_resume(hwc_context_t *ctx, int dpy);
@@ -516,14 +530,21 @@
//Used for SideSync feature
//which overrides the mExtOrientation
bool mBufferMirrorMode;
+ // Used to synchronize between WFD and Display modules
+ mutable Locker mWfdSyncLock;
+
qhwc::LayerRotMap *mLayerRotMap[HWC_NUM_DISPLAY_TYPES];
// Panel reset flag will be set if BTA check fails
bool mPanelResetStatus;
// number of active Displays
int numActiveDisplays;
- // Downscale feature switch, set via system the property
+ // Downscale feature switch, set via system property
// sys.hwc.mdp_downscale_enabled
bool mMDPDownscaleEnabled;
+ // Is WFD enabled through VDS solution ?
+ // This can be set via system property
+ // persist.hwc.enable_vds
+ bool mVDSEnabled;
struct gpu_hint_info mGPUHintInfo;
};
diff --git a/libhwcomposer/hwc_virtual.cpp b/libhwcomposer/hwc_virtual.cpp
index f68d08f..10ed9d1 100644
--- a/libhwcomposer/hwc_virtual.cpp
+++ b/libhwcomposer/hwc_virtual.cpp
@@ -35,19 +35,17 @@
using namespace qhwc;
using namespace overlay;
-HWCVirtualBase* HWCVirtualBase::getObject() {
- char property[PROPERTY_VALUE_MAX];
+HWCVirtualBase* HWCVirtualBase::getObject(bool isVDSEnabled) {
- if((property_get("persist.hwc.enable_vds", property, NULL) > 0)) {
- if(atoi(property) != 0) {
- ALOGD_IF(HWCVIRTUAL_LOG, "%s: VDS is enabled for Virtual display",
- __FUNCTION__);
- return new HWCVirtualVDS();
- }
+ if(isVDSEnabled) {
+ ALOGD_IF(HWCVIRTUAL_LOG, "%s: VDS is enabled for Virtual display",
+ __FUNCTION__);
+ return new HWCVirtualVDS();
+ } else {
+ ALOGD_IF(HWCVIRTUAL_LOG, "%s: V4L2 is enabled for Virtual display",
+ __FUNCTION__);
+ return new HWCVirtualV4L2();
}
- ALOGD_IF(HWCVIRTUAL_LOG, "%s: V4L2 is enabled for Virtual display",
- __FUNCTION__);
- return new HWCVirtualV4L2();
}
void HWCVirtualVDS::init(hwc_context_t *ctx) {
@@ -84,6 +82,9 @@
if(!Writeback::getInstance()->setSecure(false)) {
ALOGE("Failure while attempting to reset WB session.");
}
+ ctx->mWfdSyncLock.lock();
+ ctx->mWfdSyncLock.signal();
+ ctx->mWfdSyncLock.unlock();
}
}
diff --git a/libhwcomposer/hwc_virtual.h b/libhwcomposer/hwc_virtual.h
index 6bc3898..87004c3 100644
--- a/libhwcomposer/hwc_virtual.h
+++ b/libhwcomposer/hwc_virtual.h
@@ -33,7 +33,7 @@
explicit HWCVirtualBase(){};
virtual ~HWCVirtualBase(){};
// instantiates and returns the pointer to VDS or V4L2 object.
- static HWCVirtualBase* getObject();
+ static HWCVirtualBase* getObject(bool isVDSEnabled);
virtual int prepare(hwc_composer_device_1 *dev,
hwc_display_contents_1_t* list) = 0;
virtual int set(hwc_context_t *ctx, hwc_display_contents_1_t *list) = 0;