Merge "hwc: disable MDP composition on Secondary display"
diff --git a/libgralloc/Android.mk b/libgralloc/Android.mk
index a879c5c..ef10f54 100644
--- a/libgralloc/Android.mk
+++ b/libgralloc/Android.mk
@@ -27,7 +27,7 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
LOCAL_SRC_FILES := gpu.cpp gralloc.cpp framebuffer.cpp mapper.cpp
LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
-LOCAL_COPY_HEADERS := gralloc_priv.h
+LOCAL_COPY_HEADERS := gralloc_priv.h gr.h
include $(BUILD_SHARED_LIBRARY)
@@ -41,5 +41,6 @@
LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdmemalloc\"
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
LOCAL_SRC_FILES := ionalloc.cpp alloc_controller.cpp
+LOCAL_COPY_HEADERS := alloc_controller.h memalloc.h
include $(BUILD_SHARED_LIBRARY)
diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp
index f4192c4..da179f9 100644
--- a/libgralloc/gpu.cpp
+++ b/libgralloc/gpu.cpp
@@ -177,6 +177,9 @@
{
*bufferType = BUFFER_TYPE_VIDEO;
+ if (inputFormat == HAL_PIXEL_FORMAT_RGB_888)
+ return;
+
if (inputFormat <= HAL_PIXEL_FORMAT_sRGB_X_8888) {
// RGB formats
*bufferType = BUFFER_TYPE_UI;
diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk
index 7b2092d..72e064e 100644
--- a/libhwcomposer/Android.mk
+++ b/libhwcomposer/Android.mk
@@ -23,7 +23,8 @@
hwc_copybit.cpp \
hwc_qclient.cpp \
hwc_dump_layers.cpp \
- hwc_ad.cpp
+ hwc_ad.cpp \
+ hwc_virtual.cpp
ifeq ($(call is-board-platform-in-list, mpq8092 msm_bronze msm8916), true)
LOCAL_SRC_FILES += hwc_vpuclient.cpp
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index eb999f7..dcad00b 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -39,6 +39,7 @@
#include "hwc_ad.h"
#include "profiler.h"
#include "hwc_vpuclient.h"
+#include "hwc_virtual.h"
using namespace qhwc;
using namespace overlay;
@@ -127,15 +128,8 @@
ctx->mAD->reset();
MDPComp::reset();
-}
-
-//clear prev layer prop flags and realloc for current frame
-static void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers) {
- if(ctx->layerProp[dpy]) {
- delete[] ctx->layerProp[dpy];
- ctx->layerProp[dpy] = NULL;
- }
- ctx->layerProp[dpy] = new LayerProp[numAppLayers];
+ if(ctx->mHWCVirtual)
+ ctx->mHWCVirtual->destroy(ctx, numDisplays, displays);
}
static int hwc_prepare_primary(hwc_composer_device_1 *dev,
@@ -193,39 +187,6 @@
return 0;
}
-static int hwc_prepare_virtual(hwc_composer_device_1 *dev,
- hwc_display_contents_1_t *list) {
- ATRACE_CALL();
-
- hwc_context_t* ctx = (hwc_context_t*)(dev);
- const int dpy = HWC_DISPLAY_VIRTUAL;
-
- if (LIKELY(list && list->numHwLayers > 1) &&
- ctx->dpyAttr[dpy].isActive &&
- ctx->dpyAttr[dpy].connected) {
- reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
- if(!ctx->dpyAttr[dpy].isPause) {
- ctx->dpyAttr[dpy].isConfiguring = false;
- setListStats(ctx, list, dpy);
- if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
- const int fbZ = 0;
- ctx->mFBUpdate[dpy]->prepare(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;
-}
-
-
static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays,
hwc_display_contents_1_t** displays)
{
@@ -256,7 +217,8 @@
ret = hwc_prepare_external(dev, list);
break;
case HWC_DISPLAY_VIRTUAL:
- ret = hwc_prepare_virtual(dev, list);
+ if(ctx->mHWCVirtual)
+ ret = ctx->mHWCVirtual->prepare(dev, list);
break;
default:
ret = -EINVAL;
@@ -439,8 +401,11 @@
value[0] = 0;
break;
case HWC_DISPLAY_TYPES_SUPPORTED:
- if(ctx->mMDP.hasOverlay)
- supported |= HWC_DISPLAY_EXTERNAL_BIT;
+ if(ctx->mMDP.hasOverlay) {
+ supported |= HWC_DISPLAY_VIRTUAL_BIT;
+ if(!qdutils::MDPVersion::getInstance().is8x26())
+ supported |= HWC_DISPLAY_EXTERNAL_BIT;
+ }
value[0] = supported;
break;
case HWC_FORMAT_RB_SWAP:
@@ -567,75 +532,6 @@
return ret;
}
-static int hwc_set_virtual(hwc_context_t *ctx,
- hwc_display_contents_1_t* list)
-{
- ATRACE_CALL();
- int ret = 0;
-
- const int dpy = HWC_DISPLAY_VIRTUAL;
-
-
- if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
- ctx->dpyAttr[dpy].connected &&
- !ctx->dpyAttr[dpy].isPause) {
- uint32_t last = list->numHwLayers - 1;
- hwc_layer_1_t *fbLayer = &list->hwLayers[last];
- int fd = -1; //FenceFD from the Copybit(valid in async mode)
- bool copybitDone = false;
- if(ctx->mCopyBit[dpy])
- copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
-
- if(list->numHwLayers > 1)
- hwc_sync(ctx, list, dpy, fd);
-
- // Dump the layers for virtual
- if(ctx->mHwcDebug[dpy])
- ctx->mHwcDebug[dpy]->dumpLayers(list);
-
- if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
- ALOGE("%s: MDPComp draw failed", __FUNCTION__);
- ret = -1;
- }
-
- int extOnlyLayerIndex =
- ctx->listStats[dpy].extOnlyLayerIndex;
-
- private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
- if(extOnlyLayerIndex!= -1) {
- hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
- hnd = (private_handle_t *)extLayer->handle;
- } else if(copybitDone) {
- hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
- }
-
- if(hnd && !isYuvBuffer(hnd)) {
- if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
- ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
- ret = -1;
- }
- }
-
- if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
- ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
- ret = -1;
- }
- }
-
- closeAcquireFds(list);
-
- if (list && !ctx->mVirtualonExtActive && (list->retireFenceFd < 0) ) {
- // SF assumes HWC waits for the acquire fence and returns a new fence
- // that signals when we're done. Since we don't wait, and also don't
- // touch the buffer, we can just handle the acquire fence back to SF
- // as the retire fence.
- list->retireFenceFd = list->outbufAcquireFenceFd;
- }
-
- return ret;
-}
-
-
static int hwc_set(hwc_composer_device_1 *dev,
size_t numDisplays,
hwc_display_contents_1_t** displays)
@@ -653,7 +549,8 @@
ret = hwc_set_external(ctx, list);
break;
case HWC_DISPLAY_VIRTUAL:
- ret = hwc_set_virtual(ctx, list);
+ if(ctx->mHWCVirtual)
+ ret = ctx->mHWCVirtual->set(ctx, list);
break;
default:
ret = -EINVAL;
diff --git a/libhwcomposer/hwc_ad.cpp b/libhwcomposer/hwc_ad.cpp
index 104ffce..929ccc4 100644
--- a/libhwcomposer/hwc_ad.cpp
+++ b/libhwcomposer/hwc_ad.cpp
@@ -157,7 +157,7 @@
const hwc_display_contents_1_t* list) {
mDoable = false;
if(mFeatureEnabled &&
- !ctx->mExtDisplay->isConnected() &&
+ !isSecondaryConnected(ctx) &&
ctx->listStats[HWC_DISPLAY_PRIMARY].yuvCount == 1) {
int nYuvIndex = ctx->listStats[HWC_DISPLAY_PRIMARY].yuvIndices[0];
const hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 4600e9d..e84b345 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -413,13 +413,13 @@
ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__);
ret = false;
} else if(qdutils::MDPVersion::getInstance().is8x26() &&
- ctx->mVideoTransFlag && ctx->mVirtualDisplay->isConnected()) {
+ ctx->mVideoTransFlag &&
+ isSecondaryConnected(ctx)) {
//1 Padding round to shift pipes across mixers
ALOGD_IF(isDebug(),"%s: MDP Comp. video transition padding round",
__FUNCTION__);
ret = false;
- } else if(ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isConfiguring ||
- ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isConfiguring) {
+ } else if(isSecondaryConfiguring(ctx)) {
ALOGD_IF( isDebug(),"%s: External Display connection is pending",
__FUNCTION__);
ret = false;
@@ -987,11 +987,13 @@
int& maxBatchCount) {
int i = 0;
int fbZOrder =-1;
+ int droppedLayerCt = 0;
while (i < mCurrentFrame.layerCount) {
int batchCount = 0;
int batchStart = i;
int batchEnd = i;
- int fbZ = batchStart;
+ /* Adjust batch Z order with the dropped layers so far */
+ int fbZ = batchStart - droppedLayerCt;
int firstZReverseIndex = -1;
int updatingLayersAbove = 0;//Updating layer count in middle of batch
while(i < mCurrentFrame.layerCount) {
@@ -1006,6 +1008,7 @@
} else {
if(mCurrentFrame.drop[i]) {
i++;
+ droppedLayerCt++;
continue;
} else if(updatingLayersAbove <= 0) {
batchCount++;
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 512a120..bc41bd9 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -45,7 +45,7 @@
virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list) = 0;
/* dumpsys */
void dump(android::String8& buf);
-
+ bool isGLESOnlyComp() { return (mCurrentFrame.mdpCount == 0); }
static MDPComp* getObject(hwc_context_t *ctx, const int& dpy);
/* Handler to invoke frame redraw on Idle Timer expiry */
static void timeout_handler(void *udata);
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index fa021cc..d47e120 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -43,6 +43,7 @@
#include "hwc_qclient.h"
#include "QService.h"
#include "comptype.h"
+#include "hwc_virtual.h"
using namespace qClient;
using namespace qService;
@@ -170,6 +171,7 @@
ctx->mMDPComp[HWC_DISPLAY_PRIMARY] =
MDPComp::getObject(ctx, HWC_DISPLAY_PRIMARY);
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true;
+ ctx->mHWCVirtual = HWCVirtualBase::getObject();
for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
ctx->mHwcDebug[i] = new HwcDebug(i);
@@ -259,6 +261,10 @@
ctx->mLayerRotMap[i] = NULL;
}
}
+ if(ctx->mHWCVirtual) {
+ delete ctx->mHWCVirtual;
+ ctx->mHWCVirtual = NULL;
+ }
if(ctx->mAD) {
delete ctx->mAD;
ctx->mAD = NULL;
@@ -1143,12 +1149,19 @@
}
void closeAcquireFds(hwc_display_contents_1_t* list) {
- for(uint32_t i = 0; list && i < list->numHwLayers; i++) {
- //Close the acquireFenceFds
- //HWC_FRAMEBUFFER are -1 already by SF, rest we close.
- if(list->hwLayers[i].acquireFenceFd >= 0) {
- close(list->hwLayers[i].acquireFenceFd);
- list->hwLayers[i].acquireFenceFd = -1;
+ if(LIKELY(list)) {
+ for(uint32_t i = 0; i < list->numHwLayers; i++) {
+ //Close the acquireFenceFds
+ //HWC_FRAMEBUFFER are -1 already by SF, rest we close.
+ if(list->hwLayers[i].acquireFenceFd >= 0) {
+ close(list->hwLayers[i].acquireFenceFd);
+ list->hwLayers[i].acquireFenceFd = -1;
+ }
+ }
+ //Writeback
+ if(list->outbufAcquireFenceFd >= 0) {
+ close(list->outbufAcquireFenceFd);
+ list->outbufAcquireFenceFd = -1;
}
}
}
@@ -1160,6 +1173,7 @@
int acquireFd[MAX_NUM_APP_LAYERS];
int count = 0;
int releaseFd = -1;
+ int retireFd = -1;
int fbFd = -1;
bool swapzero = false;
int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
@@ -1168,6 +1182,8 @@
memset(&data, 0, sizeof(data));
data.acq_fen_fd = acquireFd;
data.rel_fen_fd = &releaseFd;
+ data.retire_fen_fd = &retireFd;
+ data.flags = MDP_BUF_SYNC_FLAG_RETIRE_FENCE;
char property[PROPERTY_VALUE_MAX];
if(property_get("debug.egl.swapinterval", property, "1") > 0) {
@@ -1207,6 +1223,11 @@
}
//Accumulate acquireFenceFds for MDP
+ if(list->outbufAcquireFenceFd >= 0) {
+ //Writeback output buffer
+ acquireFd[count++] = list->outbufAcquireFenceFd;
+ }
+
for(uint32_t i = 0; i < list->numHwLayers; i++) {
if((list->hwLayers[i].compositionType == HWC_OVERLAY ||
list->hwLayers[i].compositionType == HWC_BLIT) &&
@@ -1277,20 +1298,14 @@
//Signals when MDP finishes reading rotator buffers.
ctx->mLayerRotMap[dpy]->setReleaseFd(releaseFd);
+ close(releaseFd);
+ releaseFd = -1;
- // if external is animating, close the relaseFd
- if(isExtAnimating) {
- close(releaseFd);
- releaseFd = -1;
- }
-
- if(UNLIKELY(swapzero)){
+ if(UNLIKELY(swapzero)) {
list->retireFenceFd = -1;
- close(releaseFd);
} else {
- list->retireFenceFd = releaseFd;
+ list->retireFenceFd = retireFd;
}
-
return ret;
}
@@ -1847,7 +1862,7 @@
bool canUseRotator(hwc_context_t *ctx, int dpy) {
if(qdutils::MDPVersion::getInstance().is8x26() &&
- ctx->mVirtualDisplay->isConnected() &&
+ isSecondaryConnected(ctx) &&
!ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause) {
/* 8x26 mdss driver supports multiplexing of DMA pipe
* in LINE and BLOCK modes for writeback panels.
@@ -1883,6 +1898,15 @@
return false;
}
+//clear prev layer prop flags and realloc for current frame
+void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers) {
+ if(ctx->layerProp[dpy]) {
+ delete[] ctx->layerProp[dpy];
+ ctx->layerProp[dpy] = NULL;
+ }
+ ctx->layerProp[dpy] = new LayerProp[numAppLayers];
+}
+
void BwcPM::setBwc(hwc_context_t *ctx, const hwc_rect_t& crop,
const hwc_rect_t& dst, const int& transform,
ovutils::eMdpFlags& mdpFlags) {
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 4a20d47..e64f89c 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -59,6 +59,7 @@
class HwcDebug;
class AssertiveDisplay;
class VPUClient;
+class HWCVirtualBase;
struct MDPInfo {
@@ -221,6 +222,8 @@
bool isAlphaPresent(hwc_layer_1_t const* layer);
int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable);
int getBlending(int blending);
+bool isGLESOnlyComp(hwc_context_t *ctx, const int& dpy);
+void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers);
//Helper function to dump logs
void dumpsys_log(android::String8& buf, const char* fmt, ...);
@@ -465,6 +468,7 @@
qhwc::AssertiveDisplay *mAD;
qhwc::VPUClient *mVPUClient;
eAnimationState mAnimationState[HWC_NUM_DISPLAY_TYPES];
+ qhwc::HWCVirtualBase *mHWCVirtual;
// stores the primary device orientation
int deviceOrientation;
@@ -511,6 +515,16 @@
return ctx->listStats[dpy].isSecurePresent;
}
+static inline bool isSecondaryConfiguring(hwc_context_t* ctx) {
+ return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isConfiguring ||
+ ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isConfiguring);
+}
+
+static inline bool isSecondaryConnected(hwc_context_t* ctx) {
+ return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected ||
+ ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected);
+}
+
};
#endif //HWC_UTILS_H
diff --git a/libhwcomposer/hwc_virtual.cpp b/libhwcomposer/hwc_virtual.cpp
new file mode 100644
index 0000000..51ade32
--- /dev/null
+++ b/libhwcomposer/hwc_virtual.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fcntl.h>
+#include <errno.h>
+
+#include <cutils/log.h>
+#include <utils/Trace.h>
+#include <overlayWriteback.h>
+#include "hwc_utils.h"
+#include "hwc_fbupdate.h"
+#include "hwc_mdpcomp.h"
+#include "hwc_dump_layers.h"
+#include "hwc_copybit.h"
+#include "hwc_virtual.h"
+
+#define HWCVIRTUAL_LOG 0
+
+using namespace qhwc;
+using namespace overlay;
+
+HWCVirtualBase* HWCVirtualBase::getObject() {
+ char property[PROPERTY_VALUE_MAX];
+
+ 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();
+ }
+ }
+ ALOGD_IF(HWCVIRTUAL_LOG, "%s: V4L2 is enabled for Virtual display",
+ __FUNCTION__);
+ return new HWCVirtualV4L2();
+}
+
+void HWCVirtualVDS::init(hwc_context_t *ctx) {
+ const int dpy = HWC_DISPLAY_VIRTUAL;
+ ctx->mFBUpdate[dpy] =
+ IFBUpdate::getObject(ctx, dpy);
+ ctx->mMDPComp[dpy] = MDPComp::getObject(ctx, dpy);
+
+ if(ctx->mFBUpdate[dpy])
+ ctx->mFBUpdate[dpy]->reset();
+ if(ctx->mMDPComp[dpy])
+ ctx->mMDPComp[dpy]->reset();
+}
+
+void HWCVirtualVDS::destroy(hwc_context_t *ctx, size_t numDisplays,
+ hwc_display_contents_1_t** displays) {
+ int dpy = HWC_DISPLAY_VIRTUAL;
+
+ //Cleanup virtual display objs, since there is no explicit disconnect
+ if(ctx->dpyAttr[dpy].connected &&
+ (numDisplays <= HWC_NUM_PHYSICAL_DISPLAY_TYPES ||
+ displays[dpy] == NULL)) {
+ ctx->dpyAttr[dpy].connected = false;
+
+ if(ctx->mFBUpdate[dpy]) {
+ delete ctx->mFBUpdate[dpy];
+ ctx->mFBUpdate[dpy] = NULL;
+ }
+ if(ctx->mMDPComp[dpy]) {
+ delete ctx->mMDPComp[dpy];
+ ctx->mMDPComp[dpy] = NULL;
+ }
+ }
+}
+
+int HWCVirtualVDS::prepare(hwc_composer_device_1 *dev,
+ hwc_display_contents_1_t *list) {
+ ATRACE_CALL();
+ //XXX: Fix when framework support is added
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ const int dpy = HWC_DISPLAY_VIRTUAL;
+
+ if (list && list->outbuf && list->numHwLayers > 0) {
+ reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
+ uint32_t last = list->numHwLayers - 1;
+ hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+ int fbWidth = 0, fbHeight = 0;
+ getLayerResolution(fbLayer, fbWidth, fbHeight);
+ ctx->dpyAttr[dpy].xres = fbWidth;
+ ctx->dpyAttr[dpy].yres = fbHeight;
+
+ if(ctx->dpyAttr[dpy].connected == false) {
+ ctx->dpyAttr[dpy].connected = true;
+ init(ctx);
+ //First round, just setup and return so primary can free pipes
+ return 0;
+ }
+
+ 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]->prepare(ctx, list, fbZ);
+ }
+ }
+ return 0;
+}
+
+int HWCVirtualVDS::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
+ ATRACE_CALL();
+ int ret = 0;
+ const int dpy = HWC_DISPLAY_VIRTUAL;
+
+ if (list && list->outbuf && list->numHwLayers > 0) {
+ uint32_t last = list->numHwLayers - 1;
+ hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+
+ if(fbLayer->handle && !isSecondaryConfiguring(ctx) &&
+ !ctx->mMDPComp[dpy]->isGLESOnlyComp()) {
+ private_handle_t *ohnd = (private_handle_t *)list->outbuf;
+ Writeback::getInstance()->setOutputFormat(
+ utils::getMdpFormat(ohnd->format));
+
+ int fd = -1; //FenceFD from the Copybit
+ hwc_sync(ctx, list, dpy, fd);
+
+ if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
+ ALOGE("%s: MDPComp draw failed", __FUNCTION__);
+ ret = -1;
+ }
+ if (!ctx->mFBUpdate[dpy]->draw(ctx,
+ (private_handle_t *)fbLayer->handle)) {
+ ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
+ ret = -1;
+ }
+
+ Writeback::getInstance()->queueBuffer(ohnd->fd, ohnd->offset);
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail!", __FUNCTION__);
+ ret = -1;
+ }
+
+ } else if(list->outbufAcquireFenceFd >= 0) {
+ //If we dont handle the frame, set retireFenceFd to outbufFenceFd,
+ //which will make sure, the framework waits on it and closes it.
+ //The other way is to wait on outbufFenceFd ourselves, close it and
+ //set retireFenceFd to -1. Since we want hwc to be async, choosing
+ //the former.
+ //Also dup because, the closeAcquireFds() will close the outbufFence
+ list->retireFenceFd = dup(list->outbufAcquireFenceFd);
+ }
+ }
+
+ closeAcquireFds(list);
+ return ret;
+}
+
+/* Implementation for HWCVirtualV4L2 class */
+
+int HWCVirtualV4L2::prepare(hwc_composer_device_1 *dev,
+ hwc_display_contents_1_t *list) {
+ ATRACE_CALL();
+
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ const int dpy = HWC_DISPLAY_VIRTUAL;
+
+ if (LIKELY(list && list->numHwLayers > 1) &&
+ ctx->dpyAttr[dpy].isActive &&
+ ctx->dpyAttr[dpy].connected) {
+ reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
+ if(!ctx->dpyAttr[dpy].isPause) {
+ ctx->dpyAttr[dpy].isConfiguring = false;
+ setListStats(ctx, list, dpy);
+ if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
+ const int fbZ = 0;
+ ctx->mFBUpdate[dpy]->prepare(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;
+}
+
+int HWCVirtualV4L2::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
+ ATRACE_CALL();
+ int ret = 0;
+
+ const int dpy = HWC_DISPLAY_VIRTUAL;
+
+ if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
+ ctx->dpyAttr[dpy].connected &&
+ !ctx->dpyAttr[dpy].isPause) {
+ uint32_t last = list->numHwLayers - 1;
+ hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+ int fd = -1; //FenceFD from the Copybit(valid in async mode)
+ bool copybitDone = false;
+ if(ctx->mCopyBit[dpy])
+ copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
+
+ if(list->numHwLayers > 1)
+ hwc_sync(ctx, list, dpy, fd);
+
+ // Dump the layers for virtual
+ if(ctx->mHwcDebug[dpy])
+ ctx->mHwcDebug[dpy]->dumpLayers(list);
+
+ if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
+ ALOGE("%s: MDPComp draw failed", __FUNCTION__);
+ ret = -1;
+ }
+
+ int extOnlyLayerIndex =
+ ctx->listStats[dpy].extOnlyLayerIndex;
+
+ private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
+ if(extOnlyLayerIndex!= -1) {
+ hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
+ hnd = (private_handle_t *)extLayer->handle;
+ } else if(copybitDone) {
+ hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
+ }
+
+ if(hnd && !isYuvBuffer(hnd)) {
+ if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
+ ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
+ ret = -1;
+ }
+ }
+
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
+ ret = -1;
+ }
+ }
+
+ closeAcquireFds(list);
+
+ if (list && !ctx->mVirtualonExtActive && (list->retireFenceFd < 0) ) {
+ // SF assumes HWC waits for the acquire fence and returns a new fence
+ // that signals when we're done. Since we don't wait, and also don't
+ // touch the buffer, we can just handle the acquire fence back to SF
+ // as the retire fence.
+ list->retireFenceFd = list->outbufAcquireFenceFd;
+ }
+
+ return ret;
+}
diff --git a/libhwcomposer/hwc_virtual.h b/libhwcomposer/hwc_virtual.h
new file mode 100644
index 0000000..502aa3b
--- /dev/null
+++ b/libhwcomposer/hwc_virtual.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HWC_VIRTUAL
+#define HWC_VIRTUAL
+
+#include <hwc_utils.h>
+
+namespace qhwc {
+namespace ovutils = overlay::utils;
+
+// Base and abstract class for VDS and V4L2 wfd design.
+class HWCVirtualBase {
+public:
+ explicit HWCVirtualBase(){};
+ virtual ~HWCVirtualBase(){};
+ // instantiates and returns the pointer to VDS or V4L2 object.
+ static HWCVirtualBase* getObject();
+ 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;
+ 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;
+};
+
+class HWCVirtualVDS : public HWCVirtualBase {
+public:
+ explicit HWCVirtualVDS(){};
+ virtual ~HWCVirtualVDS(){};
+ // Chooses composition type and configures pipe for each layer in virtual
+ // display list
+ virtual int prepare(hwc_composer_device_1 *dev,
+ hwc_display_contents_1_t* list);
+ // Queues the buffer for each layer in virtual display list and call display
+ // commit.
+ virtual int set(hwc_context_t *ctx, hwc_display_contents_1_t *list);
+ // instantiates mdpcomp, copybit and fbupdate objects and initialize those
+ // objects for virtual display during virtual display connect.
+ virtual void init(hwc_context_t *ctx);
+ // Destroys mdpcomp, copybit and fbupdate objects and for virtual display
+ // during virtual display disconnect.
+ virtual void destroy(hwc_context_t *ctx, size_t numDisplays,
+ hwc_display_contents_1_t** displays);
+};
+
+class HWCVirtualV4L2 : public HWCVirtualBase {
+public:
+ explicit HWCVirtualV4L2(){};
+ virtual ~HWCVirtualV4L2(){};
+ // Chooses composition type and configures pipe for each layer in virtual
+ // display list
+ virtual int prepare(hwc_composer_device_1 *dev,
+ hwc_display_contents_1_t* list);
+ // Queues the buffer for each layer in virtual display list and call
+ // display commit.
+ virtual int set(hwc_context_t *ctx, hwc_display_contents_1_t *list);
+ // instantiates mdpcomp, copybit and fbupdate objects and initialize those
+ // objects for virtual display during virtual display connect. This function
+ // is no-op for V4L2 design
+ virtual void init(hwc_context_t *ctx) {};
+ // Destroys mdpcomp, copybit and fbupdate objects and for virtual display
+ // during virtual display disconnect. This function is no-op for V4L2 design
+ virtual void destroy(hwc_context_t *ctx, size_t numDisplays,
+ hwc_display_contents_1_t** displays){};
+};
+
+}; //namespace
+#endif