Merge "hwc: Query MDP capability for blending stages supported."
diff --git a/libhdmi/hdmi.cpp b/libhdmi/hdmi.cpp
index 4fb7cfa..1aee664 100644
--- a/libhdmi/hdmi.cpp
+++ b/libhdmi/hdmi.cpp
@@ -101,15 +101,16 @@
}
readCEUnderscanInfo();
readResolution();
- // TODO: Move this to activate
/* Used for changing the resolution
- * getUserMode will get the preferred
- * mode set thru adb shell */
- mCurrentMode = getUserMode();
- if (mCurrentMode == -1) {
+ * getUserConfig will get the preferred
+ * config index set thru adb shell */
+ mActiveConfig = getUserConfig();
+ if (mActiveConfig == -1) {
//Get the best mode and set
- mCurrentMode = getBestMode();
+ mActiveConfig = getBestConfig();
}
+ // Set the mode corresponding to the active index
+ mCurrentMode = mEDIDModes[mActiveConfig];
setAttributes();
// set system property
property_set("hw.hdmiON", "1");
@@ -121,6 +122,14 @@
&& !strcmp(value, "true")) {
mMDPDownscaleEnabled = true;
}
+
+ // XXX: A debug property can be used to enable resolution change for
+ // testing purposes: debug.hwc.enable_resolution_change
+ mEnableResolutionChange = false;
+ if(property_get("debug.hwc.enable_resolution_change", value, "false")
+ && !strcmp(value, "true")) {
+ mEnableResolutionChange = true;
+ }
return 0;
}
@@ -425,8 +434,8 @@
return -1;
}
-/// Returns the user mode set(if any) using adb shell
-int HDMIDisplay::getUserMode() {
+/// Returns the index of the user mode set(if any) using adb shell
+int HDMIDisplay::getUserConfig() {
/* Based on the property set the resolution */
char property_value[PROPERTY_VALUE_MAX];
property_get("hw.hdmi.resolution", property_value, "-1");
@@ -434,15 +443,16 @@
// We dont support interlaced modes
if(isValidMode(mode) && !isInterlacedMode(mode)) {
ALOGD_IF(DEBUG, "%s: setting the HDMI mode = %d", __FUNCTION__, mode);
- return mode;
+ return getModeIndex(mode);
}
return -1;
}
-// Get the best mode for the current HD TV
-int HDMIDisplay::getBestMode() {
+// Get the index of the best mode for the current HD TV
+int HDMIDisplay::getBestConfig() {
int bestOrder = 0;
int bestMode = HDMI_VFRMT_640x480p60_4_3;
+ int bestModeIndex = -1;
// for all the edid read, get the best mode
for(int i = 0; i < mModeCount; i++) {
int mode = mEDIDModes[i];
@@ -450,9 +460,19 @@
if (order > bestOrder) {
bestOrder = order;
bestMode = mode;
+ bestModeIndex = i;
}
}
- return bestMode;
+ // If we fail to read from EDID when HDMI is connected, then
+ // mModeCount will be 0 and bestModeIndex will be invalid.
+ // In this case, we populate the mEDIDModes structure with
+ // a default mode at index 0.
+ if (bestModeIndex == -1) {
+ bestModeIndex = 0;
+ mModeCount = 1;
+ mEDIDModes[bestModeIndex] = bestMode;
+ }
+ return bestModeIndex;
}
inline bool HDMIDisplay::isValidMode(int ID)
@@ -696,4 +716,79 @@
mPrimaryWidth = primaryWidth;
}
+int HDMIDisplay::setActiveConfig(int newConfig) {
+ if(newConfig < 0 || newConfig > mModeCount) {
+ ALOGE("%s Invalid configuration %d", __FUNCTION__, newConfig);
+ return -EINVAL;
+ }
+
+ // XXX: Currently, we only support a change in frame rate.
+ // We need to validate the new config before proceeding.
+ if (!isValidConfigChange(newConfig)) {
+ ALOGE("%s Invalid configuration %d", __FUNCTION__, newConfig);
+ return -EINVAL;
+ }
+
+ mCurrentMode = mEDIDModes[newConfig];
+ mActiveConfig = newConfig;
+ activateDisplay();
+ ALOGD("%s config(%d) mode(%d)", __FUNCTION__, mActiveConfig, mCurrentMode);
+ return 0;
+}
+
+// returns false if the xres or yres of the new config do
+// not match the current config
+bool HDMIDisplay::isValidConfigChange(int newConfig) {
+ int newMode = mEDIDModes[newConfig];
+ uint32_t width = 0, height = 0, refresh = 0;
+ getAttrForConfig(newConfig, width, height, refresh);
+ return ((mXres == width) && (mYres == height)) || mEnableResolutionChange;
+}
+
+int HDMIDisplay::getModeIndex(int mode) {
+ int modeIndex = -1;
+ for(int i = 0; i < mModeCount; i++) {
+ if(mode == mEDIDModes[i]) {
+ modeIndex = i;
+ break;
+ }
+ }
+ return modeIndex;
+}
+
+int HDMIDisplay::getAttrForConfig(int config, uint32_t& xres,
+ uint32_t& yres, uint32_t& refresh) const {
+ if(config < 0 || config > mModeCount) {
+ ALOGE("%s Invalid configuration %d", __FUNCTION__, config);
+ return -EINVAL;
+ }
+ int mode = mEDIDModes[config];
+ uint32_t fps = 0;
+ // Retrieve the mode attributes from gEDIDData
+ for (int dataIndex = 0; dataIndex < gEDIDCount; dataIndex++) {
+ if (gEDIDData[dataIndex].mMode == mode) {
+ xres = gEDIDData[dataIndex].mWidth;
+ yres = gEDIDData[dataIndex].mHeight;
+ fps = gEDIDData[dataIndex].mFps;
+ }
+ }
+ refresh = (uint32_t) 1000000000l / fps;
+ ALOGD_IF(DEBUG, "%s xres(%d) yres(%d) fps(%d) refresh(%d)", __FUNCTION__,
+ xres, yres, fps, refresh);
+ return 0;
+}
+
+int HDMIDisplay::getDisplayConfigs(uint32_t* configs,
+ size_t* numConfigs) const {
+ if (*numConfigs <= 0) {
+ ALOGE("%s Invalid number of configs (%d)", __FUNCTION__, *numConfigs);
+ return -EINVAL;
+ }
+ *numConfigs = mModeCount;
+ for (int configIndex = 0; configIndex < mModeCount; configIndex++) {
+ configs[configIndex] = (uint32_t)configIndex;
+ }
+ return 0;
+}
+
};
diff --git a/libhdmi/hdmi.h b/libhdmi/hdmi.h
index 605d9be..d262a63 100644
--- a/libhdmi/hdmi.h
+++ b/libhdmi/hdmi.h
@@ -68,6 +68,11 @@
/* when HDMI is an EXTERNAL display, PRIMARY display attributes are needed
for scaling mode */
void setPrimaryAttributes(uint32_t primaryWidth, uint32_t primaryHeight);
+ int getActiveConfig() const { return mActiveConfig; };
+ int setActiveConfig(int newConfig);
+ int getAttrForConfig(int config, uint32_t& xres,
+ uint32_t& yres, uint32_t& refresh) const;
+ int getDisplayConfigs(uint32_t* configs, size_t* numConfigs) const;
private:
int getModeCount() const;
@@ -80,17 +85,26 @@
bool writeHPDOption(int userOption) const;
bool isValidMode(int mode);
int getModeOrder(int mode);
- int getUserMode();
- int getBestMode();
+ int getUserConfig();
+ int getBestConfig();
bool isInterlacedMode(int mode);
void resetInfo();
void setAttributes();
void getAttrForMode(uint32_t& width, uint32_t& height, uint32_t& fps);
int openDeviceNode(const char* node, int fileMode) const;
+ int getModeIndex(int mode);
+ bool isValidConfigChange(int newConfig);
int mFd;
int mFbNum;
+ // mCurrentMode is the HDMI video format that corresponds to the mEDIDMode
+ // entry referenced by mActiveConfig
int mCurrentMode;
+ // mActiveConfig is the index correponding to the currently active mode for
+ // the HDMI display. It basically indexes the mEDIDMode array
+ int mActiveConfig;
+ // mEDIDModes contains a list of HDMI video formats (modes) supported by the
+ // HDMI display
int mEDIDModes[64];
int mModeCount;
fb_var_screeninfo mVInfo;
@@ -102,6 +116,7 @@
// Downscale feature switch, set via system property
// sys.hwc.mdp_downscale_enabled
bool mMDPDownscaleEnabled;
+ bool mEnableResolutionChange;
int mDisplayId;
};
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index b5ba073..a7eb561 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -187,6 +187,12 @@
}
}
+static bool isHotPluggable(hwc_context_t *ctx, int dpy) {
+ return ((dpy == HWC_DISPLAY_EXTERNAL) ||
+ ((dpy == HWC_DISPLAY_PRIMARY) &&
+ ctx->mHDMIDisplay->isHDMIPrimaryDisplay()));
+}
+
static void reset(hwc_context_t *ctx, int numDisplays,
hwc_display_contents_1_t** displays) {
@@ -735,40 +741,54 @@
int hwc_getDisplayConfigs(struct hwc_composer_device_1* dev, int disp,
uint32_t* configs, size_t* numConfigs) {
- int ret = 0;
hwc_context_t* ctx = (hwc_context_t*)(dev);
- //Currently we allow only 1 config, reported as config id # 0
- //This config is passed in to getDisplayAttributes. Ignored for now.
+
+ Locker::Autolock _l(ctx->mDrawLock);
+ bool hotPluggable = isHotPluggable(ctx, disp);
+ bool isVirtualDisplay = (disp == HWC_DISPLAY_VIRTUAL);
+ // If hotpluggable or virtual displays are inactive return error
+ if ((hotPluggable || isVirtualDisplay) && !ctx->dpyAttr[disp].connected) {
+ ALOGE("%s display (%d) is inactive", __FUNCTION__, disp);
+ return -EINVAL;
+ }
+
+ if (*numConfigs <= 0) {
+ ALOGE("%s Invalid number of configs (%d)", __FUNCTION__, *numConfigs);
+ return -EINVAL;
+ }
+
switch(disp) {
case HWC_DISPLAY_PRIMARY:
- if(*numConfigs > 0) {
+ if (hotPluggable) {
+ ctx->mHDMIDisplay->getDisplayConfigs(configs, numConfigs);
+ } else {
configs[0] = 0;
*numConfigs = 1;
}
- ret = 0; //NO_ERROR
break;
case HWC_DISPLAY_EXTERNAL:
+ ctx->mHDMIDisplay->getDisplayConfigs(configs, numConfigs);
+ break;
case HWC_DISPLAY_VIRTUAL:
- ret = -1; //Not connected
- if(ctx->dpyAttr[disp].connected) {
- ret = 0; //NO_ERROR
- if(*numConfigs > 0) {
- configs[0] = 0;
- *numConfigs = 1;
- }
- }
+ configs[0] = 0;
+ *numConfigs = 1;
break;
}
- return ret;
+ return 0;
}
int hwc_getDisplayAttributes(struct hwc_composer_device_1* dev, int disp,
- uint32_t /*config*/, const uint32_t* attributes, int32_t* values) {
+ uint32_t config, const uint32_t* attributes, int32_t* values) {
hwc_context_t* ctx = (hwc_context_t*)(dev);
- //If hotpluggable displays(i.e, HDMI, WFD) are inactive return error
- if( (disp != HWC_DISPLAY_PRIMARY) && !ctx->dpyAttr[disp].connected) {
- return -1;
+
+ Locker::Autolock _l(ctx->mDrawLock);
+ bool hotPluggable = isHotPluggable(ctx, disp);
+ bool isVirtualDisplay = (disp == HWC_DISPLAY_VIRTUAL);
+ // If hotpluggable or virtual displays are inactive return error
+ if ((hotPluggable || isVirtualDisplay) && !ctx->dpyAttr[disp].connected) {
+ ALOGE("%s display (%d) is inactive", __FUNCTION__, disp);
+ return -EINVAL;
}
//From HWComposer
@@ -784,16 +804,27 @@
const size_t NUM_DISPLAY_ATTRIBUTES = (sizeof(DISPLAY_ATTRIBUTES) /
sizeof(DISPLAY_ATTRIBUTES)[0]);
+ uint32_t xres = 0, yres = 0, refresh = 0;
+ int ret = 0;
+ if (hotPluggable) {
+ ret = ctx->mHDMIDisplay->getAttrForConfig(config, xres, yres, refresh);
+ if(ret < 0) {
+ ALOGE("%s Error getting attributes for config %d", config);
+ return ret;
+ }
+ }
+
for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) {
switch (attributes[i]) {
case HWC_DISPLAY_VSYNC_PERIOD:
- values[i] = ctx->dpyAttr[disp].vsync_period;
+ values[i] =
+ hotPluggable ? refresh : ctx->dpyAttr[disp].vsync_period;
break;
case HWC_DISPLAY_WIDTH:
if (ctx->dpyAttr[disp].customFBSize)
values[i] = ctx->dpyAttr[disp].xres_new;
else
- values[i] = ctx->dpyAttr[disp].xres;
+ values[i] = hotPluggable ? xres : ctx->dpyAttr[disp].xres;
ALOGD("%s disp = %d, width = %d",__FUNCTION__, disp,
values[i]);
@@ -802,7 +833,7 @@
if (ctx->dpyAttr[disp].customFBSize)
values[i] = ctx->dpyAttr[disp].yres_new;
else
- values[i] = ctx->dpyAttr[disp].yres;
+ values[i] = hotPluggable ? yres : ctx->dpyAttr[disp].yres;
ALOGD("%s disp = %d, height = %d",__FUNCTION__, disp,
values[i]);
break;
@@ -849,15 +880,49 @@
strlcpy(buff, aBuf.string(), buff_len);
}
-int hwc_getActiveConfig(struct hwc_composer_device_1* /*dev*/, int /*disp*/) {
- //Supports only the default config (0th index) for now
- return 0;
+int hwc_getActiveConfig(struct hwc_composer_device_1* dev, int disp)
+{
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+
+ Locker::Autolock _l(ctx->mDrawLock);
+ bool hotPluggable = isHotPluggable(ctx, disp);
+ bool isVirtualDisplay = (disp == HWC_DISPLAY_VIRTUAL);
+ // If hotpluggable or virtual displays are inactive return error
+ if ((hotPluggable || isVirtualDisplay) && !ctx->dpyAttr[disp].connected) {
+ ALOGE("%s display (%d) is inactive", __FUNCTION__, disp);
+ return -EINVAL;
+ }
+
+ // For use cases when primary panel is the default interface we only have
+ // the default config (0th index)
+ if (!hotPluggable) {
+ return 0;
+ }
+
+ return ctx->mHDMIDisplay->getActiveConfig();
}
-int hwc_setActiveConfig(struct hwc_composer_device_1* /*dev*/, int /*disp*/,
- int index) {
- //Supports only the default config (0th index) for now
- return (index == 0) ? index : -EINVAL;
+int hwc_setActiveConfig(struct hwc_composer_device_1* dev, int disp, int index)
+{
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+
+ Locker::Autolock _l(ctx->mDrawLock);
+ bool hotPluggable = isHotPluggable(ctx, disp);
+ bool isVirtualDisplay = (disp == HWC_DISPLAY_VIRTUAL);
+ // If hotpluggable or virtual displays are inactive return error
+ if ((hotPluggable || isVirtualDisplay) && !ctx->dpyAttr[disp].connected) {
+ ALOGE("%s display (%d) is inactive", __FUNCTION__, disp);
+ return -EINVAL;
+ }
+
+ // For use cases when primary panel is the default interface we only have
+ // the default config (0th index)
+ if (!hotPluggable) {
+ // Primary and virtual supports only the default config (0th index)
+ return (index == 0) ? index : -EINVAL;
+ }
+
+ return ctx->mHDMIDisplay->setActiveConfig(index);
}
static int hwc_device_close(struct hw_device_t *dev)