hwc: Add support for color mode switching

Add a ColorMode class to HWC to manage color modes and expose
them as display attributes to SurfaceFlinger

Change-Id: I1010096120db6aec61163a84390527f5a0a3645e
diff --git a/msm8994/libhwcomposer/Android.mk b/msm8994/libhwcomposer/Android.mk
index df3e464..293eb49 100644
--- a/msm8994/libhwcomposer/Android.mk
+++ b/msm8994/libhwcomposer/Android.mk
@@ -17,7 +17,8 @@
 LOCAL_SHARED_LIBRARIES += libskia
 endif #TARGET_USES_QCOM_BSP
 
-LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdhwcomposer\"
+LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdhwcomposer\" \
+                                 -std=c++11
 #Enable Dynamic FPS if PHASE_OFFSET is not set
 ifeq ($(VSYNC_EVENT_PHASE_OFFSET_NS),)
     LOCAL_CFLAGS += -DDYNAMIC_FPS
diff --git a/msm8994/libhwcomposer/hwc.cpp b/msm8994/libhwcomposer/hwc.cpp
index 662a80e..64a147d 100644
--- a/msm8994/libhwcomposer/hwc.cpp
+++ b/msm8994/libhwcomposer/hwc.cpp
@@ -772,8 +772,15 @@
             if (hotPluggable) {
                 ctx->mHDMIDisplay->getDisplayConfigs(configs, numConfigs);
             } else {
-                configs[0] = 0;
-                *numConfigs = 1;
+                if(ctx->mColorMode->getNumModes() > 0) {
+                    *numConfigs = ctx->mColorMode->getNumModes();
+                    for (size_t i = 0; i < *numConfigs; i++)
+                        configs[i] = (uint32_t) i;
+
+                } else {
+                    configs[0] = 0;
+                    *numConfigs = 1;
+                }
             }
             break;
         case HWC_DISPLAY_EXTERNAL:
@@ -801,22 +808,6 @@
         return -EINVAL;
     }
 
-    //From HWComposer
-    static const uint32_t DISPLAY_ATTRIBUTES[] = {
-        HWC_DISPLAY_VSYNC_PERIOD,
-        HWC_DISPLAY_WIDTH,
-        HWC_DISPLAY_HEIGHT,
-        HWC_DISPLAY_DPI_X,
-        HWC_DISPLAY_DPI_Y,
-#ifdef QCOM_BSP
-        HWC_DISPLAY_SECURE,
-#endif
-        HWC_DISPLAY_NO_ATTRIBUTE,
-    };
-
-    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) {
@@ -828,7 +819,7 @@
         }
     }
 
-    for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) {
+    for (size_t i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
         switch (attributes[i]) {
         case HWC_DISPLAY_VSYNC_PERIOD:
             values[i] =
@@ -857,11 +848,9 @@
         case HWC_DISPLAY_DPI_Y:
             values[i] = (int32_t) (ctx->dpyAttr[disp].ydpi*1000.0);
             break;
-#ifdef QCOM_BSP
-        case HWC_DISPLAY_SECURE:
-            values[i] = (int32_t) (ctx->dpyAttr[disp].secure);
+        case HWC_DISPLAY_COLOR_TRANSFORM:
+            values[i] = ctx->mColorMode->getModeForIndex(config);
             break;
-#endif
         default:
             ALOGE("Unknown display attribute %d",
                     attributes[i]);
@@ -914,7 +903,9 @@
 
     // For use cases when primary panel is the default interface we only have
     // the default config (0th index)
-    if (!hotPluggable) {
+    if (!hotPluggable && HWC_DISPLAY_PRIMARY) {
+        return ctx->mColorMode->getActiveModeIndex();
+    } else if (isVirtualDisplay) {
         return 0;
     }
 
@@ -934,10 +925,12 @@
         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)
+    // For use cases when primary panel is the default interface we only switch
+    // color modes
+    if(!hotPluggable && disp == HWC_DISPLAY_PRIMARY) {
+        return ctx->mColorMode->applyModeByIndex(index);
+    } else if (isVirtualDisplay) {
+        // virtual supports only the default config (0th index)
         return (index == 0) ? index : -EINVAL;
     }
 
diff --git a/msm8994/libhwcomposer/hwc_qclient.cpp b/msm8994/libhwcomposer/hwc_qclient.cpp
index c2c09c6..6d05d38 100644
--- a/msm8994/libhwcomposer/hwc_qclient.cpp
+++ b/msm8994/libhwcomposer/hwc_qclient.cpp
@@ -340,25 +340,11 @@
 }
 
 static void applyModeById(hwc_context_t* ctx, int32_t modeId) {
-    int (*applyMode)(int, int) = NULL;
-    void *modeHandle = NULL;
-
-    modeHandle = dlopen("libmm-qdcm.so", RTLD_NOW);
-    if (modeHandle) {
-        *(void **)&applyMode = dlsym(modeHandle, "applyModeById");
-        if (applyMode) {
-            int err = applyMode(modeId, HWC_DISPLAY_PRIMARY);
-            if (err)
-                ALOGD("%s: Not able to apply mode: %d", __FUNCTION__, modeId);
-            else
-                ctx->proc->invalidate(ctx->proc);
-        } else {
-            ALOGE("%s: No symbol applyModeById found", __FUNCTION__);
-        }
-        dlclose(modeHandle);
-    } else {
-        ALOGE("%s: Not able to load libmm-qdcm.so", __FUNCTION__);
-    }
+    int err = ctx->mColorMode->applyModeByID(modeId);
+    if (err)
+        ALOGD("%s: Not able to apply mode: %d", __FUNCTION__, modeId);
+    else
+        ctx->proc->invalidate(ctx->proc);
 }
 
 status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
diff --git a/msm8994/libhwcomposer/hwc_utils.cpp b/msm8994/libhwcomposer/hwc_utils.cpp
index 35d1f1f..50c1536 100644
--- a/msm8994/libhwcomposer/hwc_utils.cpp
+++ b/msm8994/libhwcomposer/hwc_utils.cpp
@@ -418,6 +418,8 @@
 
     memset(&(ctx->mPtorInfo), 0, sizeof(ctx->mPtorInfo));
     ctx->mHPDEnabled = false;
+    ctx->mColorMode = new ColorMode();
+    ctx->mColorMode->init();
     ALOGI("Initializing Qualcomm Hardware Composer");
     ALOGI("MDP version: %d", ctx->mMDP.version);
 }
@@ -472,7 +474,11 @@
         ctx->mAD = NULL;
     }
 
-
+    if(ctx->mColorMode) {
+        ctx->mColorMode->destroy();
+        delete ctx->mColorMode;
+        ctx->mColorMode = NULL;
+    }
 }
 
 //Helper to roundoff the refreshrates
@@ -2505,8 +2511,6 @@
 void processBootAnimCompleted(hwc_context_t *ctx) {
     char value[PROPERTY_VALUE_MAX];
     int boot_finished = 0, ret = -1;
-    int (*applyMode)(int) = NULL;
-    void *modeHandle = NULL;
 
     // Reading property set on boot finish in SF
     property_get("service.bootanim.exit", value, "0");
@@ -2514,21 +2518,9 @@
     if (!boot_finished)
         return;
 
-    modeHandle = dlopen("libmm-qdcm.so", RTLD_NOW);
-    if (modeHandle) {
-        *(void **)&applyMode = dlsym(modeHandle, "applyDefaults");
-        if (applyMode) {
-            ret = applyMode(HWC_DISPLAY_PRIMARY);
-            if (ret)
-                ALOGD("%s: Not able to apply default mode", __FUNCTION__);
-        } else {
-            ALOGE("%s: No symbol applyDefaults found", __FUNCTION__);
-        }
-        dlclose(modeHandle);
-    } else {
-        ALOGE("%s: Not able to load libmm-qdcm.so", __FUNCTION__);
-    }
-
+    ret = ctx->mColorMode->applyDefaultMode();
+    if (ret)
+        ALOGD("%s: Not able to apply default mode", __FUNCTION__);
     ctx->mBootAnimCompleted = true;
 }
 
@@ -2851,4 +2843,104 @@
     }
 }
 
+void ColorMode::init() {
+    //Map symbols from libmm-qdcm and get list of modes
+    mModeHandle = dlopen("libmm-qdcm.so", RTLD_NOW);
+    if (mModeHandle) {
+        *(void **)& fnApplyDefaultMode = dlsym(mModeHandle, "applyDefaults");
+        *(void **)& fnApplyModeById = dlsym(mModeHandle, "applyModeById");
+        *(void **)& fnGetNumModes = dlsym(mModeHandle, "getNumDisplayModes");
+        *(void **)& fnGetModeList = dlsym(mModeHandle, "getDisplayModeIdList");
+        *(void **)& fnSetDefaultMode = dlsym(mModeHandle, "setDefaultMode");
+    } else {
+        ALOGW("Unable to load libmm-qdcm");
+    }
+
+    if(fnGetNumModes) {
+        mNumModes = fnGetNumModes(HWC_DISPLAY_PRIMARY);
+        if(mNumModes > MAX_NUM_COLOR_MODES) {
+            ALOGE("Number of modes is above the limit: %d", mNumModes);
+            mNumModes = 0;
+            return;
+        }
+        if(fnGetModeList) {
+            fnGetModeList(mModeList, &mCurMode, HWC_DISPLAY_PRIMARY);
+            mCurModeIndex = getIndexForMode(mCurMode);
+            ALOGI("ColorMode: current mode: %d current mode index: %d number of modes: %d",
+                    mCurMode, mCurModeIndex, mNumModes);
+        }
+    }
+}
+
+//Legacy API
+int ColorMode::applyDefaultMode() {
+    if(fnApplyDefaultMode) {
+        return fnApplyDefaultMode(HWC_DISPLAY_PRIMARY);
+    } else {
+        return -EINVAL;
+    }
+}
+
+int ColorMode::applyModeByID(int modeID) {
+    if(fnApplyModeById) {
+        int ret = fnApplyModeById(modeID, HWC_DISPLAY_PRIMARY);
+        if (!ret)
+            ret = setDefaultMode(modeID);
+        return ret;
+    } else {
+        return -EINVAL;
+    }
+}
+
+//This API is called from setActiveConfig
+//The value here must be set as default
+int ColorMode::applyModeByIndex(int index) {
+    int ret = 0;
+    int mode  = getModeForIndex(index);
+    if(mode < 0) {
+        ALOGE("Invalid mode for index: %d", index);
+        return -EINVAL;
+    }
+    ALOGD("%s: Applying mode index: %d modeID: %d", __FUNCTION__, index, mode);
+    ret = applyModeByID(mode);
+    if(!ret) {
+        mCurModeIndex = index;
+        setDefaultMode(mode);
+    }
+    return ret;
+}
+
+int ColorMode::setDefaultMode(int modeID) {
+    if(fnSetDefaultMode) {
+        ALOGD("Setting default color mode to %d", modeID);
+        return fnSetDefaultMode(modeID, HWC_DISPLAY_PRIMARY);
+    } else {
+        return -EINVAL;
+    }
+}
+
+int ColorMode::getModeForIndex(int index) {
+    if(index < mNumModes) {
+        return mModeList[index];
+    } else {
+        return -EINVAL;
+    }
+}
+
+int ColorMode::getIndexForMode(int mode) {
+    if(mModeList) {
+        for(int32_t i = 0; i < mNumModes; i++)
+            if(mModeList[i] == mode)
+                return i;
+    }
+    return -EINVAL;
+}
+
+void ColorMode::destroy() {
+    if(mModeHandle) {
+        dlclose(mModeHandle);
+        mModeHandle = NULL;
+    }
+}
+
 };//namespace qhwc
diff --git a/msm8994/libhwcomposer/hwc_utils.h b/msm8994/libhwcomposer/hwc_utils.h
index e8c7545..b298a25 100644
--- a/msm8994/libhwcomposer/hwc_utils.h
+++ b/msm8994/libhwcomposer/hwc_utils.h
@@ -48,6 +48,7 @@
 #define STR(f) #f;
 // Max number of PTOR layers handled
 #define MAX_PTOR_LAYERS 2
+#define MAX_NUM_COLOR_MODES 32
 
 //Fwrd decls
 struct hwc_context_t;
@@ -229,6 +230,36 @@
     uint32_t mCount;
 };
 
+//ColorModes for primary displays
+class ColorMode {
+public:
+    void init();
+    void destroy();
+    int32_t getNumModes() { return mNumModes; }
+    const int32_t* getModeList() { return mModeList; }
+    int32_t getModeForIndex(int32_t index);
+    int32_t getIndexForMode(int32_t mode);
+    int applyDefaultMode();
+    int applyModeByID(int modeID);
+    int applyModeByIndex(int index);
+    int setDefaultMode(int modeID);
+    int getActiveModeIndex() { return mCurModeIndex; }
+private:
+    int32_t (*fnGetNumModes)(int /*dispID*/);
+    int32_t (*fnGetModeList)(int32_t* /*mModeList*/, int32_t* /*current default*/,
+            int32_t /*dispID*/);
+    int (*fnApplyDefaultMode)(int /*dispID*/);
+    int (*fnApplyModeById)(int /*modeID*/, int /*dispID*/);
+    int (*fnSetDefaultMode)(int /*modeID*/, int /*dispID*/);
+
+    void*     mModeHandle = NULL;
+    int32_t   mModeList[MAX_NUM_COLOR_MODES];
+    int32_t   mNumModes = 0;
+    int32_t   mCurModeIndex = 0;
+    int32_t   mCurMode = 0;
+
+};
+
 inline uint32_t LayerRotMap::getCount() const {
     return mCount;
 }
@@ -650,6 +681,8 @@
     bool mHPDEnabled;
     //Used to notify that boot has completed
     bool mBootAnimCompleted;
+    //Manages color modes
+    qhwc::ColorMode *mColorMode;
 };
 
 namespace qhwc {