initial GL libraries for msm8960

Change-Id: I16451c70a079894ac326d3564d96f1fbafcd4f1b
Signed-off-by: Iliyan Malchev <malchev@google.com>
diff --git a/libhwcomposer/external_display_only.h b/libhwcomposer/external_display_only.h
new file mode 100644
index 0000000..fa24642
--- /dev/null
+++ b/libhwcomposer/external_display_only.h
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define EXTDEBUG 0
+class ExtDispOnly {
+
+    enum ExternalOnlyMode {
+        EXT_ONLY_MODE_OFF = 0,
+        EXT_ONLY_MODE_ON = 1,
+    };
+
+    enum {
+        MAX_EXT_ONLY_LAYERS = 2,
+    };
+
+public:
+    /* Initialize, allocate data members */
+    static void init();
+
+    /* Deallocate data members */
+    static void destroy();
+
+    /* Closes all the overlay channels */
+    static void close();
+
+    /* Prepare overlay and configures mdp pipes */
+    static int prepare(hwc_context_t *ctx, hwc_layer_t *layer, int index,
+            bool waitForVsync);
+
+    /* Returns status of external-only mode */
+    static bool isModeOn();
+
+    /* Updates stats and pipe config related to external_only and external_block layers
+     * If we are staring or stopping this mode, update default mirroring.
+     */
+    static int update(hwc_context_t* ctx, hwc_layer_list_t* list);
+
+    /* Stores the locked handle for the buffer that was successfully queued */
+    static void storeLockedHandles(hwc_layer_list_t* list);
+
+    /* Queue buffers to mdp for display */
+    static int draw(hwc_context_t *ctx, hwc_layer_list_t *list);
+
+private:
+    /* Locks a buffer and marks it as locked */
+    static void lockBuffer(native_handle_t *hnd);
+
+    /* Unlocks a buffer and clears the locked flag */
+    static void unlockBuffer(native_handle_t *hnd);
+
+    /* Unlocks buffers queued in previous round (and displayed by now)
+     * Clears the handle cache.
+     */
+    static void unlockPreviousBuffers();
+
+    /* Closes the  a range of overlay channels */
+    static void closeRange(int start);
+
+    /* Start default external mirroring */
+    static void startDefaultMirror(hwc_context_t* ctx);
+
+    /* Stop default external mirroring */
+    static void stopDefaultMirror(hwc_context_t* ctx);
+
+    /* Checks if external-only mode is starting */
+    static bool isExtModeStarting(hwc_context_t* ctx, const int&
+        numExtLayers);
+
+    /* Checks if external-only mode is stopping */
+    static bool isExtModeStopping(hwc_context_t* ctx, const int&
+        numExtLayers);
+
+    //Data members
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    static overlay::OverlayUI* sOvExtUI[MAX_EXT_ONLY_LAYERS];
+    static native_handle_t* sPreviousExtHandle[MAX_EXT_ONLY_LAYERS];
+    static ExternalOnlyMode sExtOnlyMode;
+    static int sNumExtOnlyLayers;
+    static bool sSkipLayerPresent;
+    static bool sBlockLayerPresent;
+    static int sBlockLayerIndex;
+#endif
+}; //class ExtDispOnly
+
+void ExtDispOnly::lockBuffer(native_handle_t *hnd) {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    private_handle_t* phnd = (private_handle_t*)hnd;
+
+    //Genlock is reference counted and recursive.
+    //Do not accidently lock a locked buffer.
+    if(phnd && (phnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK)) {
+        LOGE_IF(EXTDEBUG, "%s: handle %p already locked", __func__, phnd);
+        return;
+    }
+    if (GENLOCK_FAILURE == genlock_lock_buffer(hnd, GENLOCK_READ_LOCK,
+            GENLOCK_MAX_TIMEOUT)) {
+        LOGE("%s: genlock_lock_buffer(READ) failed", __func__);
+        return;
+    }
+    phnd->flags |= private_handle_t::PRIV_FLAGS_HWC_LOCK;
+    LOGE_IF(EXTDEBUG, "%s: locked handle = %p", __func__, hnd);
+#endif
+}
+
+void ExtDispOnly::unlockBuffer(native_handle_t *hnd) {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    //Check if buffer is still around
+    if(private_handle_t::validate(hnd) != 0) {
+        LOGE("%s Handle already deallocated", __func__);
+        return;
+    }
+
+    private_handle_t* phnd = (private_handle_t*)hnd;
+
+    //Check if buffer was locked in the first place
+    if((phnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK) == 0) {
+        LOGE("%s Handle not locked, cannot unlock", __func__);
+        return;
+    }
+
+    //Actually try to unlock
+    if (GENLOCK_FAILURE == genlock_unlock_buffer(hnd)) {
+        LOGE("%s: genlock_unlock_buffer failed", __func__);
+        return;
+    }
+
+    //Clear the locked flag
+    phnd->flags &= ~private_handle_t::PRIV_FLAGS_HWC_LOCK;
+    LOGE_IF(EXTDEBUG, "%s: unlocked handle = %p", __func__, hnd);
+#endif
+}
+
+void ExtDispOnly::unlockPreviousBuffers() {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    for(int i = 0; (i < MAX_EXT_ONLY_LAYERS) && sPreviousExtHandle[i]; i++) {
+        LOGE_IF(EXTDEBUG, "%s", __func__);
+        ExtDispOnly::unlockBuffer(sPreviousExtHandle[i]);
+        sPreviousExtHandle[i] = NULL;
+    }
+#endif
+}
+
+void ExtDispOnly::init() {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    for(int i = 0; i < MAX_EXT_ONLY_LAYERS; i++) {
+        sOvExtUI[i] = new overlay::OverlayUI();
+        sPreviousExtHandle[i] = NULL;
+    }
+    sExtOnlyMode = EXT_ONLY_MODE_OFF;
+    sNumExtOnlyLayers = 0;
+    sSkipLayerPresent = false;
+    sBlockLayerPresent = false;
+    sBlockLayerIndex = -1;
+    LOGE_IF(EXTDEBUG, "%s", __func__);
+#endif
+}
+
+void ExtDispOnly::destroy() {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    for(int i = 0; i < MAX_EXT_ONLY_LAYERS; i++) {
+        delete sOvExtUI[i];
+    }
+#endif
+}
+
+void ExtDispOnly::closeRange(int start) {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    for (int index = start; index < MAX_EXT_ONLY_LAYERS; index++) {
+        if(sPreviousExtHandle[index]) {
+            LOGE_IF(EXTDEBUG, "%s", __func__);
+            ExtDispOnly::unlockBuffer(sPreviousExtHandle[index]);
+            sPreviousExtHandle[index] = NULL;
+        }
+        sOvExtUI[index]->closeChannel();
+    }
+#endif
+}
+
+void inline ExtDispOnly::close() {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    closeRange(0);
+#endif
+}
+
+int ExtDispOnly::prepare(hwc_context_t *ctx, hwc_layer_t *layer, int index,
+        bool waitForVsync) {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    if(ctx->mHDMIEnabled == EXT_DISPLAY_OFF ||
+        ctx->pendingHDMI == true)
+        return -1;
+
+    if (ctx && sOvExtUI[index]) {
+        private_hwc_module_t* hwcModule = reinterpret_cast<
+                private_hwc_module_t*>(ctx->device.common.module);
+        if (!hwcModule) {
+            LOGE("%s null module", __func__);
+            return -1;
+        }
+        private_handle_t *hnd = (private_handle_t *)layer->handle;
+        if(!hnd) {
+            LOGE("%s handle null", __func__);
+            return -1;
+        }
+        overlay::OverlayUI *ovUI = sOvExtUI[index];
+        int ret = 0;
+        //int orientation = layer->transform;
+        //Assuming layers will always be source landscape
+        const int orientation = 0;
+        overlay_buffer_info info;
+        hwc_rect_t sourceCrop = layer->sourceCrop;
+        info.width = sourceCrop.right - sourceCrop.left;
+        info.height = sourceCrop.bottom - sourceCrop.top;
+        info.format = hnd->format;
+        info.size = hnd->size;
+
+
+        const int fbnum = ctx->mHDMIEnabled; //HDMI or WFD
+        const bool isFg = false;
+        //Just to differentiate zorders for different layers
+        const int zorder = index;
+        const bool isVGPipe = true;
+        ovUI->setSource(info, orientation);
+        ovUI->setDisplayParams(fbnum, waitForVsync, isFg, zorder, isVGPipe);
+        const int fbWidth = ovUI->getFBWidth();
+        const int fbHeight = ovUI->getFBHeight();
+        ovUI->setPosition(0, 0, fbWidth, fbHeight);
+        if(ovUI->commit() != overlay::NO_ERROR) {
+            LOGE("%s: Overlay Commit failed", __func__);
+            return -1;
+        }
+    }
+    LOGE_IF(EXTDEBUG, "%s", __func__);
+#endif
+    return overlay::NO_ERROR;
+}
+
+inline void ExtDispOnly::startDefaultMirror(hwc_context_t* ctx) {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    hwc_composer_device_t* dev = (hwc_composer_device_t*) ctx;
+    private_hwc_module_t* hwcModule =
+        reinterpret_cast<private_hwc_module_t*>(dev->common.module);
+    framebuffer_device_t *fbDev = hwcModule->fbDevice;
+    if (fbDev) {
+        //mHDMIEnabled could be HDMI/WFD/NO EXTERNAL
+        fbDev->enableHDMIOutput(fbDev, ctx->mHDMIEnabled);
+    }
+#endif
+}
+
+inline void ExtDispOnly::stopDefaultMirror(hwc_context_t* ctx) {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    hwc_composer_device_t* dev = (hwc_composer_device_t*) ctx;
+    private_hwc_module_t* hwcModule =
+        reinterpret_cast<private_hwc_module_t*>(dev->common.module);
+    framebuffer_device_t *fbDev = hwcModule->fbDevice;
+    if (fbDev) {
+        fbDev->enableHDMIOutput(fbDev, EXT_DISPLAY_OFF);
+    }
+#endif
+}
+
+inline bool ExtDispOnly::isExtModeStarting(hwc_context_t* ctx, const int&
+        numExtLayers) {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    return ((sExtOnlyMode == EXT_ONLY_MODE_OFF) && numExtLayers);
+#endif
+    return false;
+}
+
+inline bool ExtDispOnly::isExtModeStopping(hwc_context_t* ctx, const int&
+        numExtLayers) {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    return ((sExtOnlyMode == EXT_ONLY_MODE_ON) && (numExtLayers == 0));
+#endif
+    return false;
+}
+
+inline bool ExtDispOnly::isModeOn() {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    return (sExtOnlyMode == EXT_ONLY_MODE_ON);
+#endif
+    return false;
+}
+
+int ExtDispOnly::update(hwc_context_t* ctx, hwc_layer_list_t* list) {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    int aNumExtLayers = 0;
+    bool aSkipLayerPresent = false;
+    bool aBlockLayerPresent = false;
+    int aBlockLayerIndex = -1;
+
+    //Book-keeping done each cycle
+    for (size_t i = 0; i < list->numHwLayers; i++) {
+        private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
+        // Dont draw in this round
+        if(list->hwLayers[i].flags & HWC_SKIP_LAYER) {
+            aSkipLayerPresent = true;
+        }
+        if(hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY)) {
+            aNumExtLayers++;
+            // No way we can let this be drawn by GPU to fb0
+            if(list->hwLayers[i].flags & HWC_SKIP_LAYER) {
+                list->hwLayers[i].flags &= ~ HWC_SKIP_LAYER;
+            }
+            list->hwLayers[i].flags |= HWC_USE_EXT_ONLY;
+            list->hwLayers[i].compositionType = HWC_USE_OVERLAY;
+            list->hwLayers[i].hints &= ~HWC_HINT_CLEAR_FB;
+            //EXTERNAL_BLOCK is always an add-on
+            if(hnd && (hnd->flags &
+                    private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK)) {
+                aBlockLayerPresent = true;
+                aBlockLayerIndex = i;
+                list->hwLayers[i].flags |= HWC_USE_EXT_BLOCK;
+            }
+        }
+    }
+
+    //Update Default mirroring state
+    if (isExtModeStarting(ctx, aNumExtLayers)) {
+        stopDefaultMirror(ctx);
+    } else if (isExtModeStopping(ctx, aNumExtLayers)) {
+        startDefaultMirror(ctx);
+    }
+
+    //Cache our stats
+    sExtOnlyMode = aNumExtLayers ? EXT_ONLY_MODE_ON : EXT_ONLY_MODE_OFF;
+    sNumExtOnlyLayers = aNumExtLayers;
+    sSkipLayerPresent = aSkipLayerPresent;
+    sBlockLayerPresent = aBlockLayerPresent;
+    sBlockLayerIndex = aBlockLayerIndex;
+
+    LOGE_IF(EXTDEBUG, "%s: numExtLayers = %d skipLayerPresent = %d", __func__,
+            aNumExtLayers, aSkipLayerPresent);
+    //If skip layer present return. Buffers to be unlocked in draw phase.
+    if(aSkipLayerPresent) {
+        return overlay::NO_ERROR;
+    }
+
+    //If External is not connected, dont setup pipes, just return
+    if(ctx->mHDMIEnabled == EXT_DISPLAY_OFF ||
+        ctx->pendingHDMI == true) {
+        ExtDispOnly::close();
+        return -1;
+    }
+
+
+    //Update pipes
+    bool waitForVsync = true;
+    bool index = 0;
+
+    if (aBlockLayerPresent) {
+        ExtDispOnly::closeRange(1);
+        ExtDispOnly::prepare(ctx, &(list->hwLayers[aBlockLayerIndex]),
+            index, waitForVsync);
+    } else if (aNumExtLayers) {
+        ExtDispOnly::closeRange(aNumExtLayers);
+        for (size_t i = 0; i < list->numHwLayers; i++) {
+            private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
+            if(hnd && hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY) {
+                waitForVsync = (index == (aNumExtLayers - 1));
+                ExtDispOnly::prepare(ctx, &(list->hwLayers[i]),
+                    index, waitForVsync);
+                index++;
+            }
+        }
+    } else {
+        ExtDispOnly::close();
+    }
+#endif
+    return overlay::NO_ERROR;
+}
+
+void ExtDispOnly::storeLockedHandles(hwc_layer_list_t* list) {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    int index = 0;
+    if(sBlockLayerPresent) {
+        private_handle_t *hnd = (private_handle_t *)
+            list->hwLayers[sBlockLayerIndex].handle;
+        if(list->hwLayers[sBlockLayerIndex].flags & HWC_USE_EXT_ONLY) {
+            if(!(hnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK)) {
+                ExtDispOnly::lockBuffer(hnd);
+            }
+            sPreviousExtHandle[index] = hnd;
+            LOGE_IF(EXTDEBUG, "%s BLOCK: handle = %p", __func__, hnd);
+            return;
+        }
+    }
+    for(int i = 0; i < list->numHwLayers; i++) {
+        private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
+        if(list->hwLayers[i].flags & HWC_USE_EXT_ONLY) {
+            if(!(hnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK)) {
+                ExtDispOnly::lockBuffer(hnd);
+            }
+            sPreviousExtHandle[index] = hnd;
+            index++;
+            LOGE_IF(EXTDEBUG, "%s: handle = %p", __func__, hnd);
+        }
+    }
+#endif
+}
+
+int ExtDispOnly::draw(hwc_context_t *ctx, hwc_layer_list_t *list) {
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+    LOGE_IF(EXTDEBUG, "%s", __func__);
+    if(ctx->mHDMIEnabled == EXT_DISPLAY_OFF ||
+        ctx->pendingHDMI == true) {
+        ExtDispOnly::close();
+        return -1;
+    }
+
+    int ret = overlay::NO_ERROR;
+    int index = 0;
+
+    //If skip layer present or list invalid unlock and return.
+    if(sSkipLayerPresent || list == NULL) {
+        ExtDispOnly::unlockPreviousBuffers();
+        return overlay::NO_ERROR;
+    }
+
+    if(sBlockLayerPresent) {
+        private_handle_t *hnd = (private_handle_t*)
+            list->hwLayers[sBlockLayerIndex].handle;
+        ExtDispOnly::lockBuffer(hnd);
+        ret =  sOvExtUI[index]->queueBuffer(hnd);
+        if (ret) {
+            LOGE("%s queueBuffer failed", __func__);
+            // Unlock the locked buffer
+            ExtDispOnly::unlockBuffer(hnd);
+            ExtDispOnly::close();
+            return -1;
+        }
+        ExtDispOnly::unlockPreviousBuffers();
+        ExtDispOnly::storeLockedHandles(list);
+        return overlay::NO_ERROR;
+    }
+
+    for(int i = 0; i < list->numHwLayers; i++) {
+        private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
+        if(hnd && list->hwLayers[i].flags & HWC_USE_EXT_ONLY) {
+            overlay::OverlayUI *ovUI = sOvExtUI[index];
+            ExtDispOnly::lockBuffer(hnd);
+            ret = ovUI->queueBuffer(hnd);
+            if (ret) {
+                LOGE("%s queueBuffer failed", __func__);
+                // Unlock the all the currently locked buffers
+                for (int j = 0; j <= i; j++) {
+                    private_handle_t *tmphnd =
+                        (private_handle_t *)list->hwLayers[j].handle;
+                    if(hnd && list->hwLayers[j].flags & HWC_USE_EXT_ONLY)
+                        ExtDispOnly::unlockBuffer(tmphnd);
+                }
+                ExtDispOnly::close();
+                return -1;
+            }
+            index++;
+        }
+    }
+    ExtDispOnly::unlockPreviousBuffers();
+    ExtDispOnly::storeLockedHandles(list);
+#endif
+    return overlay::NO_ERROR;
+}
+
+#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
+overlay::OverlayUI* ExtDispOnly::sOvExtUI[MAX_EXT_ONLY_LAYERS];
+native_handle_t* ExtDispOnly::sPreviousExtHandle[MAX_EXT_ONLY_LAYERS];
+ExtDispOnly::ExternalOnlyMode ExtDispOnly::sExtOnlyMode;
+int ExtDispOnly::sNumExtOnlyLayers;
+bool ExtDispOnly::sSkipLayerPresent;
+bool ExtDispOnly::sBlockLayerPresent;
+int ExtDispOnly::sBlockLayerIndex;
+#endif