summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZohaib Alam <zalam@codeaurora.org>2013-09-28 03:38:20 -0400
committerZohaib Alam <zalam@codeaurora.org>2014-01-31 14:59:19 -0500
commit1bb656178eb1bb7a7f400060253a5a40e742c2f6 (patch)
tree7bc107b9324a9be01d33bad5b943ac45929b1d37
parentac067305709612b6287a2db33aae36597911ef20 (diff)
downloaddisplay-1bb656178eb1bb7a7f400060253a5a40e742c2f6.tar.gz
hwc: vpuclient: vpuClient implementation
Vpuclient is the client side for VFM in hwc. It follows the similar pattern of prepare and draw. It has 2 step prepare including: setVpuSession and prepare. The setVpuSession function passes all the layers from the SF list to VFM, which marks the layers that it can support. After this, the layer allocation/configuration is done, and finally in prepare the allocated pipes are passed down to VFM. The draw function passes the handle to the VFM to draw the video layer. Change-Id: I5d8795de35ed98716f7fa4cd48506b488cb3cb5d
-rw-r--r--common.mk3
-rw-r--r--libhwcomposer/Android.mk4
-rw-r--r--libhwcomposer/hwc.cpp26
-rw-r--r--libhwcomposer/hwc_qclient.cpp10
-rw-r--r--libhwcomposer/hwc_utils.cpp41
-rw-r--r--libhwcomposer/hwc_utils.h1
-rw-r--r--libhwcomposer/hwc_vpuclient.cpp989
-rw-r--r--libhwcomposer/hwc_vpuclient.h91
8 files changed, 1080 insertions, 85 deletions
diff --git a/common.mk b/common.mk
index 47c455fd..ae4ea610 100644
--- a/common.mk
+++ b/common.mk
@@ -36,8 +36,7 @@ ifeq ($(call is-board-platform-in-list, msm8974 msm8226 msm8610 apq8084 \
common_flags += -DMDSS_TARGET
endif
-ifeq ($(call is-board-platform-in-list, mpq8092 msm_bronze msm8916), true)
- #XXX: Replace with check from MDP when available
+ifeq ($(call is-board-platform-in-list, mpq8092), true)
common_flags += -DVPU_TARGET
endif
diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk
index 72e064e2..9749c697 100644
--- a/libhwcomposer/Android.mk
+++ b/libhwcomposer/Android.mk
@@ -25,10 +25,8 @@ LOCAL_SRC_FILES := hwc.cpp \
hwc_dump_layers.cpp \
hwc_ad.cpp \
hwc_virtual.cpp
-
-ifeq ($(call is-board-platform-in-list, mpq8092 msm_bronze msm8916), true)
+ifeq ($(call is-board-platform-in-list, mpq8092), true)
LOCAL_SRC_FILES += hwc_vpuclient.cpp
endif
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index b45a7cdb..431757db 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -180,6 +180,7 @@ static int hwc_prepare_primary(hwc_composer_device_1 *dev,
ATRACE_CALL();
hwc_context_t* ctx = (hwc_context_t*)(dev);
const int dpy = HWC_DISPLAY_PRIMARY;
+ bool fbComp = false;
if (LIKELY(list && list->numHwLayers > 1) &&
ctx->dpyAttr[dpy].isActive) {
@@ -188,13 +189,19 @@ static int hwc_prepare_primary(hwc_composer_device_1 *dev,
reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
setListStats(ctx, list, dpy);
+
+ if (ctx->mVPUClient == NULL)
+ fbComp = (ctx->mMDPComp[dpy]->prepare(ctx, list) < 0);
#ifdef VPU_TARGET
- ctx->mVPUClient->prepare(ctx, list);
+ else
+ fbComp = (ctx->mVPUClient->prepare(ctx, dpy, list) < 0);
#endif
- if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
+
+ if (fbComp) {
const int fbZ = 0;
ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
}
+
if (ctx->mMDP.version < qdutils::MDP_V4_0) {
if(ctx->mCopyBit[dpy])
ctx->mCopyBit[dpy]->prepare(ctx, list, dpy);
@@ -487,13 +494,15 @@ static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
if(ctx->mHwcDebug[dpy])
ctx->mHwcDebug[dpy]->dumpLayers(list);
- if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
+ if (ctx->mVPUClient != NULL) {
+#ifdef VPU_TARGET
+ ctx->mVPUClient->predraw(ctx, dpy, list);
+#endif
+ }
+ else if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
ALOGE("%s: MDPComp draw failed", __FUNCTION__);
ret = -1;
}
-#ifdef VPU_TARGET
- ctx->mVPUClient->draw(ctx, list);
-#endif
//TODO We dont check for SKIP flag on this layer because we need PAN
//always. Last layer is always FB
@@ -514,6 +523,11 @@ static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
ret = -1;
}
+
+#ifdef VPU_TARGET
+ if (ctx->mVPUClient != NULL)
+ ctx->mVPUClient->draw(ctx, dpy, list);
+#endif
}
closeAcquireFds(list);
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 8c99d64f..8c5b0798 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -31,6 +31,7 @@
#include <IQService.h>
#include <hwc_utils.h>
#include <hwc_vpuclient.h>
+#include <mdp_version.h>
#define QCLIENT_DEBUG 0
@@ -94,16 +95,19 @@ static android::status_t screenRefresh(hwc_context_t *ctx) {
return result;
}
+#ifdef VPU_TARGET
static android::status_t vpuCommand(hwc_context_t *ctx,
uint32_t command,
const Parcel* inParcel,
Parcel* outParcel) {
status_t result = NO_INIT;
-#ifdef VPU_TARGET
- result = ctx->mVPUClient->processCommand(command, inParcel, outParcel);
+#ifdef QCOM_BSP
+ if(qdutils::MDPVersion::getInstance().is8092())
+ result = ctx->mVPUClient->processCommand(command, inParcel, outParcel);
#endif
return result;
}
+#endif
static void setExtOrientation(hwc_context_t *ctx, uint32_t orientation) {
ctx->mExtOrientation = orientation;
@@ -181,10 +185,12 @@ status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
Parcel* outParcel) {
status_t ret = NO_ERROR;
+#ifdef VPU_TARGET
if (command > IQService::VPU_COMMAND_LIST_START &&
command < IQService::VPU_COMMAND_LIST_END) {
return vpuCommand(mHwcContext, command, inParcel, outParcel);
}
+#endif
switch(command) {
case IQService::SECURING:
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index ececa70f..f6476f58 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -232,8 +232,11 @@ void initContext(hwc_context_t *ctx)
// Initialize device orientation to its default orientation
ctx->deviceOrientation = 0;
ctx->mBufferMirrorMode = false;
+ ctx->mVPUClient = NULL;
+
#ifdef VPU_TARGET
- ctx->mVPUClient = new VPUClient();
+ if(qdutils::MDPVersion::getInstance().is8092())
+ ctx->mVPUClient = new VPUClient(ctx);
#endif
ALOGI("Initializing Qualcomm Hardware Composer");
@@ -270,9 +273,8 @@ void closeContext(hwc_context_t *ctx)
}
#ifdef VPU_TARGET
- if(ctx->mVPUClient) {
+ if(ctx->mVPUClient != NULL)
delete ctx->mVPUClient;
- }
#endif
for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
@@ -1302,6 +1304,7 @@ int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy,
dpy, list->numHwLayers);
}
+ LayerProp *layerProp = ctx->layerProp[dpy];
for(uint32_t i = 0; i < list->numHwLayers; i++) {
if(list->hwLayers[i].compositionType == HWC_OVERLAY ||
list->hwLayers[i].compositionType == HWC_BLIT ||
@@ -1313,8 +1316,10 @@ int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy,
// Release all the app layer fds immediately,
// if animation is in progress.
list->hwLayers[i].releaseFenceFd = -1;
- } else if(list->hwLayers[i].releaseFenceFd < 0) {
- //If rotator has not already populated this field.
+ } else if(list->hwLayers[i].releaseFenceFd < 0 &&
+ !(layerProp[i].mFlags & HWC_VPUCOMP)) {
+ //If rotator has not already populated this field
+ // & if it's a not VPU layer
list->hwLayers[i].releaseFenceFd = dup(releaseFd);
}
}
@@ -1361,8 +1366,10 @@ void setMdpFlags(hwc_layer_1_t *layer,
ovutils::setMdpFlags(mdpFlags,
ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
}
+ // in mpq, deinterlacing is done in vpu
if(metadata && (metadata->operation & PP_PARAM_INTERLACED) &&
- metadata->interlaced) {
+ metadata->interlaced &&
+ (!qdutils::MDPVersion::getInstance().is8092())) {
ovutils::setMdpFlags(mdpFlags,
ovutils::OV_MDP_DEINTERLACE);
}
@@ -1549,6 +1556,17 @@ int configureNonSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
int rotFlags = ovutils::ROT_FLAGS_NONE;
uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd));
Whf whf(getWidth(hnd), getHeight(hnd), format, hnd->size);
+ LayerProp *layerProp = ctx->layerProp[dpy];
+
+#ifdef VPU_TARGET
+ if(ctx->mVPUClient != NULL &&
+ ctx->mVPUClient->supportedVPULayer(dpy, layer)) {
+ whf.format = getMdpFormat(
+ ctx->mVPUClient->getLayerFormat(dpy, layer));
+ whf.w = ctx->mVPUClient->getWidth(dpy, layer);
+ whf.h = ctx->mVPUClient->getHeight(dpy, layer);
+ }
+#endif
// Handle R/B swap
if (layer->flags & HWC_FORMAT_RB_SWAP) {
@@ -1656,6 +1674,17 @@ int configureSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
int rotFlags = ROT_FLAGS_NONE;
uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd));
Whf whf(getWidth(hnd), getHeight(hnd), format, hnd->size);
+ LayerProp *layerProp = ctx->layerProp[dpy];
+
+#ifdef VPU_TARGET
+ if(ctx->mVPUClient != NULL &&
+ ctx->mVPUClient->supportedVPULayer(dpy, layer)) {
+ whf.format = getMdpFormat(
+ ctx->mVPUClient->getLayerFormat(dpy, layer));
+ whf.w = ctx->mVPUClient->getWidth(dpy, layer);
+ whf.h = ctx->mVPUClient->getHeight(dpy, layer);
+ }
+#endif
// Handle R/B swap
if (layer->flags & HWC_FORMAT_RB_SWAP) {
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 9ccfa1b7..ce1abebf 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -145,6 +145,7 @@ struct BwcPM {
enum {
HWC_MDPCOMP = 0x00000001,
HWC_COPYBIT = 0x00000002,
+ HWC_VPUCOMP = 0x00000004,
};
// HAL specific features
diff --git a/libhwcomposer/hwc_vpuclient.cpp b/libhwcomposer/hwc_vpuclient.cpp
index 23c68417..6904efce 100644
--- a/libhwcomposer/hwc_vpuclient.cpp
+++ b/libhwcomposer/hwc_vpuclient.cpp
@@ -1,93 +1,964 @@
/*
-* Copyright (c) 2013 The Linux Foundation. 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 The Linux Foundation. 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.
-*/
+ * Copyright (c) 2013-2014 The Linux Foundation. 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 The Linux Foundation. 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. INNO 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 INCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING INANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
#include <dlfcn.h>
#include "hwc_vpuclient.h"
-#include "hwc_utils.h"
-#include <vpu/vpu.h>
#include <binder/Parcel.h>
-
+#include "hwc_fbupdate.h"
+#include <vpu/vpu.h>
using namespace vpu;
using namespace android;
+using namespace overlay::utils;
+namespace ovutils = overlay::utils;
+
namespace qhwc {
-VPUClient::VPUClient()
+VPUClient::VPUClient(hwc_context_t *ctx)
{
mVPULib = dlopen("libvpu.so", RTLD_NOW);
- VPU* (*init)();
- *(void **) &init = dlsym(mVPULib, "getObject");
- if(init)
- mVPU = init();
- else
- mVPU = NULL;
+ VPU* (*getObject)();
+
+ mVPU = NULL;
+ if (mVPULib == NULL) {
+ ALOGE("%s: Cannot open libvpu.so object", __FUNCTION__);
+ return;
+ }
+
+ *(void **) &getObject = dlsym(mVPULib, "getObject");
+ if (getObject) {
+ mVPU = getObject();
+ ALOGI("Initializing VPU client..");
+
+ // calling vpu init
+ if (mVPU->init() == NO_ERROR) {
+ // passing display attributes to libvpu
+ ALOGD_IF(isDebug(), "%s: VFM init successful!", __FUNCTION__);
+
+ DispAttr_t attr;
+ attr.width = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+ attr.height = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
+ attr.fp100s = (ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period) ?
+ 1000000000/(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period/100):0;
+ mVPU->setDisplayAttr((DISPLAY_ID)HWC_DISPLAY_PRIMARY, attr);
+
+ ALOGD_IF(isDebug(),"%s: Display attr: width:%d height:%d fp100s:%d",
+ __FUNCTION__, attr.width, attr.height, attr.fp100s);
+
+ // memsetting the pipe structure to 0
+ memset(mProp, 0, sizeof(mProp));
+
+ mDebugLogs = 0;
+ // enable logs
+ char property[PROPERTY_VALUE_MAX];
+ if ( property_get("debug.vpuclient.logs", property, NULL) > 0 )
+ mDebugLogs = atoi(property);
+
+ // allocating memory for LayerList
+ for (int i = 0; i < HWC_NUM_DISPLAY_TYPES; ++i)
+ vList[i] = (LayerList*) malloc(sizeof(LayerList));
+ }
+ else {
+ ALOGE("Error: VPU init failed!");
+ mVPU = NULL;
+ }
+ }
}
VPUClient::~VPUClient()
{
+ // freeing LayerList
+ for (int i = 0; i < HWC_NUM_DISPLAY_TYPES; ++i) {
+ if (vList[i])
+ free(vList[i]);
+ }
+
void (*destroy) (VPU*);
*(void **) &destroy = dlsym(mVPULib, "deleteObject");
dlclose(mVPULib);
}
-int VPUClient::prepare(hwc_context_t *ctx,
- hwc_display_contents_1_t* list)
+void setLayer(hwc_layer_1_t *layer, Layer *vLayer)
{
- int err = 0;
- if(!mVPU)
- return err;
- // * Check VPU status
- // * Check session availability
- // * Other individual checks
- // Do not pass hwc context/list
- // Mark buffers to be drawn for VPU
- return err;
+ // setting handle info in vLayer
+ vLayer->handle = (private_handle_t *)(layer->handle);
+
+ if (vLayer->handle) {
+ vLayer->srcStride.width = getWidth(vLayer->handle);
+ vLayer->srcStride.height = getHeight(vLayer->handle);
+ }
+
+ // setting source crop
+ hwc_rect_t sourceRect = integerizeSourceCrop(layer->sourceCropf);
+ vLayer->srcRect.left = sourceRect.left;
+ vLayer->srcRect.top = sourceRect.top;
+ vLayer->srcRect.right = sourceRect.right;
+ vLayer->srcRect.bottom = sourceRect.bottom;
+
+ // setting destination crop
+ vLayer->tgtRect.left = layer->displayFrame.left;
+ vLayer->tgtRect.top = layer->displayFrame.top;
+ vLayer->tgtRect.right = layer->displayFrame.right;
+ vLayer->tgtRect.bottom = layer->displayFrame.bottom;
+
+ if (layer->flags & HWC_GEOMETRY_CHANGED)
+ vLayer->inFlags |= GEOMETRY_CHANGED;
+
+ vLayer->acquireFenceFd = layer->acquireFenceFd;
+
+ if (layer->compositionType == HWC_FRAMEBUFFER_TARGET || isSkipLayer(layer))
+ vLayer->inFlags |= SKIP_LAYER;
+}
+
+int VPUClient::setupVpuSession(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list)
+{
+ memset(vList[display], 0, sizeof(LayerList));
+ memset(mProp, 0, sizeof(mProp));
+ mNumVpuLayers = 0;
+
+ // setting up the layer
+ LayerList *vpuList = vList[display];
+ vpuList->numLayers = list->numHwLayers;
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ Layer *vLayer = &vpuList->layers[i];
+ VpuLayerProp* prop = &mProp[display][i];
+
+ // Storing the sourceCropf, as it's going to be changed for overlay Set
+ // will be restored after overlay set in prepare.
+ prop->sourceCropf = layer->sourceCropf;
+
+ // filling up the vpu list
+ setLayer(layer, vLayer);
+ ALOGD_IF(isDebug2(), "%s:Done setting lyr:%d for VFM", __FUNCTION__, i);
+ }
+
+ if (mVPU->setupVpuSession((DISPLAY_ID)display, vpuList) != NO_ERROR) {
+ //error in vpu prepare
+ ALOGE("%s: ERROR in VPU::setupVpuSession", __FUNCTION__);
+ return -1;
+ }
+ ALOGD_IF(isDebug2(), "%s: Done VFM: setupVpuSession", __FUNCTION__);
+
+ mGpuFallback = true;
+ LayerProp *layerProp = ctx->layerProp[display];
+ // check if the pipeID is already set for this layer, then will need to
+ // ensure that it is reserved in overlay
+ for (unsigned int i=0; i<(vpuList->numLayers); ++i) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ Layer *vLayer = &vpuList->layers[i];
+ VpuLayerProp* prop = &mProp[display][i];
+
+ if (vLayer->outFlags & VPU_LAYER) {
+ ALOGD_IF(isDebug(), "%s: VPU supported layer:%d", __FUNCTION__, i);
+
+ mNumVpuLayers++;
+ mGpuFallback = false;
+ // Reserving the pipe used in last iteration for the same layer
+ if ((vLayer->outFlags & RESERVE_PREV_PIPES) &&
+ vLayer->sDestPipes.numPipes > 0) {
+ prop->pipeCount = vLayer->sDestPipes.numPipes;
+ if (prop->pipeCount == 1) {
+ setPipeId(prop, vLayer->sDestPipes.pipe[0]);
+ ALOGD_IF(isDebug(), "%s: VPU: Reserved pipe:%d",
+ __FUNCTION__, prop->pipeID[0]);
+ }
+ else if (prop->pipeCount == 2) {
+ setPipeId(prop, vLayer->sDestPipes.pipe[0],
+ vLayer->sDestPipes.pipe[1]);
+ ALOGD_IF(isDebug(), "%s: VPU: Reserved lpipe:%d, rpipe:%d",
+ __FUNCTION__, prop->pipeID[0], prop->pipeID[1]);
+ }
+ else {
+ ALOGE("%s: Invalid pipeCount for resevation", __FUNCTION__);
+ }
+ }
+ else {
+ ALOGD_IF(isDebug(), "%s: 1st vid frame for VPU", __FUNCTION__);
+ prop->firstBuffer = true;
+ }
+
+ // marking the layer pipes for vpu.
+ prop->vpuLayer = true;
+ prop->layer = layer;
+ layer->flags |= HWC_VPU_PIPE;
+
+ // getting image width and height
+ prop->width = layer->displayFrame.right - layer->displayFrame.left;
+ prop->height = layer->displayFrame.bottom - layer->displayFrame.top;
+
+ //setting source crop = dest crop (only for layers drawn by vpu,
+ // since we know it will be scaled up/down by vpu)
+ layer->sourceCropf.left = 0.0;
+ layer->sourceCropf.top = 0.0;
+ layer->sourceCropf.right = (float) prop->width;
+ layer->sourceCropf.bottom = (float) prop->height;
+
+ // setting the flag so that mdpComp wont recognize it as the MDPCOMP
+ layerProp[i].mFlags |= HWC_VPUCOMP;
+
+ // TODO: need to get the proper solution for color fill
+
+ // storing locally the vpu supported format from VFM
+ prop->format = vLayer->vpuOutPixFmt;
+ ALOGD_IF(isDebug(), "%s: MDP: sourceCropf: w:%d h:%d format:%d",
+ __FUNCTION__, prop->width, prop->height, prop->format);
+ }
+ }
+ return 0;
+}
+
+bool VPUClient::allocResLayerPipes(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list)
+{
+ overlay::Overlay& ov = *ctx->mOverlay;
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ int pipeid = -1;
+ VpuLayerProp* prop = &mProp[dpy][i];
+
+ // checking if there is already a reserved pipe for this layer
+ // then use the same allocated pipe for this layer
+ getPipeId(prop, pipeid);
+
+ if (pipeid != -1) {
+ // there is a reserved pipe for this layer.
+ ovutils::eDest dest = ov.reservePipe(pipeid);
+ if (dest == ovutils::OV_INVALID) {
+ ALOGE("%s: Unable to get reserved pipe: layer#%d",
+ __FUNCTION__, i);
+ return false;
+ }
+
+ // setting dest locally
+ setDest(prop, dest);
+ ALOGD_IF(isDebug(), "%s: Reserving pipe:%d, dest:%d ", __FUNCTION__,
+ pipeid, dest);
+ }
+ else {
+ ALOGD_IF(isDebug2(), "%s: No reserved pipe for layer:%d",
+ __FUNCTION__, i);
+ }
+ }
+ return true;
}
-int VPUClient::draw(hwc_context_t *ctx,
- hwc_display_contents_1_t* list)
+bool VPUClient::allocLayerPipes(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list)
+{
+ // checking if the pipes are reserved for any layer,
+ // if yes, then updating the index of the pipes
+ if (!allocResLayerPipes(ctx, dpy, list)) {
+ ALOGE("%s: Reserved pipe alloc failed", __FUNCTION__);
+ return false;
+ }
+
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ VpuLayerProp* prop = &mProp[dpy][i];
+ int pipe = -1;
+ overlay::Overlay& ov = *ctx->mOverlay;
+
+ // only care about the layers supported by VPU
+ if (!prop->vpuLayer)
+ continue;
+
+ // continue if this layer has reserved pipe
+ getPipeId(prop, pipe);
+ if (pipe != -1)
+ continue;
+
+ ovutils::eDest dest = ov.nextPipe(ovutils::OV_MDP_PIPE_VG, dpy,
+ overlay::Overlay::MIXER_DEFAULT);
+ if (dest == ovutils::OV_INVALID) {
+ ALOGE("%s: Unable to allocate pipe for layer#%d", __FUNCTION__, i);
+ return false;
+ }
+
+ // setting dest locally
+ setDest(prop, dest);
+ ALOGD_IF(isDebug(), "%s: Newly allocated pipe_dest:%d", __FUNCTION__,
+ dest);
+ }
+ return true;
+}
+
+bool VPUClient::allocResLayerPipesSplit(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list)
+{
+ overlay::Overlay& ov = *ctx->mOverlay;
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ int lpipeid = -1;
+ int rpipeid = -1;
+ VpuLayerProp* prop = &mProp[dpy][i];
+
+ // checking if there is already a reserved pipe for this layer
+ // then use the same allocated pipe for this layer
+ getPipeId(prop, lpipeid, rpipeid);
+
+ if (lpipeid != -1 && rpipeid != -1) {
+ ovutils::eDest ldest = ov.reservePipe(lpipeid);
+ if (ldest == ovutils::OV_INVALID) {
+ ALOGD_IF(isDebug(), "%s: Unable to get reserved pipe-lsplit: "
+ "layer#%d", __FUNCTION__, i);
+ return false;
+ }
+
+ ovutils::eDest rdest = ov.reservePipe(rpipeid);
+ if (rdest == ovutils::OV_INVALID) {
+ ALOGD_IF(isDebug(), "%s: Unable to get reserved pipe-rsplit: "
+ "layer#%d", __FUNCTION__, i);
+ return false;
+ }
+
+ setDest(prop, ldest, rdest);
+ ALOGD_IF(isDebug(), "%s: Reserve lpipe:%d, ldest:%d, rpipe:%d, "
+ "rdest:%d", __FUNCTION__, lpipeid, ldest, rpipeid, rdest);
+ }
+ else if (lpipeid != -1 || rpipeid != -1) {
+ ALOGE("%s: Bug: only one pipe reserved!", __FUNCTION__);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VPUClient::allocLayerPipesSplit(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list)
+{
+ // checking if the pipes are reserved for any layer,
+ // if yes, then updating the index of the pipes
+ if (!allocResLayerPipesSplit(ctx, dpy, list)) {
+ ALOGE("%s: Reserved pipe alloc failed", __FUNCTION__);
+ return false;
+ }
+
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ VpuLayerProp* prop = &mProp[dpy][i];
+ int lpipe, rpipe;
+ overlay::Overlay& ov = *ctx->mOverlay;
+
+ // only care about the layers supported by VPU
+ if (!prop->vpuLayer)
+ continue;
+
+ // only care about the layers supported by VPU
+ getPipeId(prop, lpipe, rpipe);
+ if (lpipe != -1 && rpipe != -1)
+ continue;
+
+ ovutils::eDest ldest = ov.nextPipe(ovutils::OV_MDP_PIPE_VG, dpy,
+ overlay::Overlay::MIXER_LEFT);
+ if (ldest == ovutils::OV_INVALID) {
+ ALOGE("%s: Unable to allocate pipe for layer#%d", __FUNCTION__, i);
+ return false;
+ }
+
+ ovutils::eDest rdest = ov.nextPipe(ovutils::OV_MDP_PIPE_VG, dpy,
+ overlay::Overlay::MIXER_RIGHT);
+ if (rdest == ovutils::OV_INVALID) {
+ ALOGE("%s: Unable to allocate pipe for layer#%d", __FUNCTION__, i);
+ return false;
+ }
+
+ // setting dests locally
+ setDest(prop, ldest, rdest);
+ ALOGD_IF(isDebug(), "%s: Newly allocated ldest:%d rdest:%d",
+ __FUNCTION__, ldest, rdest);
+ }
+ return true;
+}
+
+bool VPUClient::configureLayers(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list)
+{
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ VpuLayerProp* prop = &mProp[dpy][i];
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+
+ if (!prop->vpuLayer)
+ continue;
+
+ eMdpFlags mdpFlags = OV_MDP_BACKEND_COMPOSITION;
+ eZorder zOrder = static_cast<eZorder>(i);
+ eIsFg isFg = IS_FG_OFF;
+ setPipeCount(prop, 1);
+ eDest dest = (eDest) getDest(prop, 0);
+
+ ALOGD_IF(isDebug(),"%s: configuring: layer:%p z_order:%d dest_pipe:%d",
+ __FUNCTION__, layer, zOrder, dest);
+
+ if (configureNonSplit(ctx, layer, dpy, mdpFlags, zOrder, isFg,
+ dest, NULL)) {
+ ALOGE("%s: Failed to configure overlay for layer %d",
+ __FUNCTION__, i);
+ return false;
+ }
+ ALOGD_IF(isDebug2(), "%s: layer:%d configured!", __FUNCTION__, i);
+
+ // Pipe is successfully allocated for this layer; retrieving it from
+ // overlay
+ int pipeId = ctx->mOverlay->getPipeId((eDest) getDest(prop, 0));
+ setPipeId(prop, pipeId);
+
+ ALOGD_IF(isDebug(), "%s: allocated pipe:%d layer:%d", __FUNCTION__,
+ pipeId, i);
+ }
+ return true;
+}
+
+bool VPUClient::configureLayersSplit(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list)
+{
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ VpuLayerProp* prop = &mProp[dpy][i];
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+
+ if (!prop->vpuLayer)
+ continue;
+
+ eMdpFlags mdpFlags = OV_MDP_BACKEND_COMPOSITION;
+ eZorder zOrder = static_cast<eZorder>(i);
+ eIsFg isFg = IS_FG_OFF;
+ setPipeCount(prop, 2);
+ eDest ldest = (eDest) getDest(prop, 0);
+ eDest rdest = (eDest) getDest(prop, 1);
+
+ ALOGD_IF(isDebug(),"%s: configuring: layer:%p z_order:%d dest_pipeL:%d"
+ "dest_pipeR:%d",__FUNCTION__, layer, zOrder, ldest, rdest);
+
+ if (configureSplit(ctx, layer, dpy, mdpFlags, zOrder, isFg, ldest,
+ rdest, NULL)) {
+ ALOGE("%s: Failed to configure overlay for layer %d",
+ __FUNCTION__, i);
+ return false;
+ }
+ ALOGD_IF(isDebug2(), "%s: layer:%d configured!", __FUNCTION__, i);
+
+ // Pipe is successfully allocated for this layer; retrieving it from
+ // overlay
+ int lpipeId = ctx->mOverlay->getPipeId((eDest) getDest(prop, 0));
+ int rpipeId = ctx->mOverlay->getPipeId((eDest) getDest(prop, 1));
+ setPipeId(prop, lpipeId, rpipeId);
+
+ ALOGD_IF(isDebug(), "%s: allocated l-pipe:%d - r-pipe:%d for layer:%d",
+ __FUNCTION__, lpipeId, rpipeId, i);
+ }
+ return true;
+}
+
+void VPUClient::setMDPCompLayerFlags(hwc_context_t *ctx, int dpy,
+ hwc_display_contents_1_t* list)
+{
+ LayerProp *layerProp = ctx->layerProp[dpy];
+
+ // disableGpu only disables gpu for video layer. The expected behavior is to
+ // show a blank screen in case VPU doesnt support a video layer, and gpu
+ // fallback is disabled by the user.
+ bool disableGpu = false;
+ char property[PROPERTY_VALUE_MAX];
+ if ((property_get("persist.hwc.noGpuFallback", property, NULL) > 0) &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+ (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ ALOGD_IF(isDebug(), "%s: GPU fallback is disabled through prop",
+ __FUNCTION__);
+ disableGpu = true;
+ }
+
+ // no layers are supported by vpu
+ if (mGpuFallback && !disableGpu) {
+ ALOGD_IF(isDebug(), "%s: No VPU supported layers - Falling back to GPU",
+ __FUNCTION__);
+ return;
+ }
+
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ hwc_layer_1_t* layer = &(list->hwLayers[i]);
+ VpuLayerProp* prop = &mProp[dpy][i];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+
+ // mark vpu layers as HWC_OVERLAY, and those video layers that
+ // are not supported by vpu and gpu fallback is disabled by the
+ // user.
+ if (prop->vpuLayer || (isYuvBuffer(hnd) && disableGpu)) {
+ layer->compositionType = HWC_OVERLAY;
+ layer->hints |= HWC_HINT_CLEAR_FB;
+ ALOGD_IF(isDebug(), "%s: Marking layer:%d as overlay",
+ __FUNCTION__, i);
+ }
+ }
+}
+
+int VPUClient::prepare(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list)
+{
+ if (!mVPU) {
+ return -1;
+ }
+
+ const int numLayers = ctx->listStats[display].numAppLayers;
+ //number of app layers exceeds MAX_NUM_APP_LAYERS fall back to GPU
+ //do not cache the information for next draw cycle.
+ if (numLayers > MAX_NUM_APP_LAYERS) {
+ ALOGE("%s: Number of App layers exceeded the limit ",__FUNCTION__);
+ return -1;
+ }
+
+ if (setupVpuSession(ctx, display, list)) {
+ ALOGD_IF(isDebug(), "%s: Vpu session setup failed! ",__FUNCTION__);
+ return -1;
+ }
+
+ LayerProp *layerProp = ctx->layerProp[display];
+ bool isSplit = isDisplaySplit(ctx, display);
+ ALOGD_IF(isDebug2(), "%s: Split Pipe:%d ", __FUNCTION__,
+ isSplit ? 1 : 0);
+
+ // setting up the layer
+ LayerList *vpuList = vList[display];
+ vpuList->numLayers = list->numHwLayers;
+
+ // Prepare FB Update at z-0
+ if (numLayers > mNumVpuLayers) {
+ if (!ctx->mFBUpdate[display]->prepare(ctx, list, mNumVpuLayers)) {
+ ALOGD_IF(isDebug(), "%s configure framebuffer failed",
+ __FUNCTION__);
+ return -1;
+ }
+ }
+
+ // Allocate pipe for layers
+ if (!isSplit ? !allocLayerPipes(ctx, display, list) :
+ !allocLayerPipesSplit(ctx, display, list)) {
+ ALOGD_IF(isDebug(), "%s: Unable to allocate MDP pipes", __FUNCTION__);
+ return -1;
+ }
+
+ // Configure layers
+ if (!isSplit ? !configureLayers(ctx, display, list) :
+ !configureLayersSplit(ctx, display, list)) {
+ ALOGD_IF(isDebug(), "%s: Unable to configure MDP pipes", __FUNCTION__);
+ return -1;
+ }
+
+ // Set layer flags for MDP/VPU composition
+ setMDPCompLayerFlags(ctx, display, list);
+
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ VpuLayerProp* prop = &mProp[display][i];
+
+ if (!prop->vpuLayer)
+ continue;
+
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ Layer *vLayer = &vpuList->layers[i];
+
+ // re-storing the sourceCropf, as it was changed in setVpuSession for
+ // overlay set
+ layer->sourceCropf = prop->sourceCropf;
+
+ // updating the pipe info inside vfm list
+ if ( prop->pipeCount > 0 && prop->pipeCount <= MAX_PIPES_PER_LAYER ) {
+ vLayer->sDestPipes.numPipes = prop->pipeCount;
+
+ for (int j=0; j < prop->pipeCount; ++j) {
+ // Setting pipe for VPU
+ vLayer->sDestPipes.pipe[j] = prop->pipeID[j];
+ }
+ }
+ }
+
+ if (mVPU->prepare((DISPLAY_ID)display, vpuList) != NO_ERROR) {
+ //error in vpu prepare
+ ALOGE("%s: ERROR in VPU::prepare", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+bool VPUClient::queueHandle(hwc_context_t* ctx, VpuLayerProp* prop,
+ private_handle_t* hnd)
+{
+ overlay::Overlay& ov = *ctx->mOverlay;
+ ovutils::eDest dest = (eDest) getDest(prop, 0);
+
+ int fd = hnd->fd;
+ uint32_t offset = hnd->offset;
+
+ if (dest != ovutils::OV_INVALID) {
+ if (!ov.queueBuffer(fd, offset, dest)) {
+ ALOGE("%s: queueBuffer failed", __FUNCTION__);
+ return false;
+ }
+ else {
+ ALOGD_IF(isDebug(), "%s: Queue handle successful: hnd:0x%x "
+ "dest:%d", __FUNCTION__, (unsigned int) hnd, dest);
+ }
+ }
+ else {
+ ALOGE("%s: Invalid Dest: dest:%d", __FUNCTION__, dest);
+ return false;
+ }
+ return true;
+}
+
+bool VPUClient::queueHandleSplit(hwc_context_t* ctx, VpuLayerProp* prop,
+ private_handle_t* hnd)
+{
+ overlay::Overlay& ov = *ctx->mOverlay;
+ ovutils::eDest ldest = (eDest) getDest(prop, 0);
+ ovutils::eDest rdest = (eDest) getDest(prop, 1);
+
+ int fd = hnd->fd;
+ uint32_t offset = hnd->offset;
+
+ // play left mixer
+ if (ldest != ovutils::OV_INVALID) {
+ ALOGD_IF(isDebug(), "%s: Queuing left mixer", __FUNCTION__);
+ if (!ov.queueBuffer(fd, offset, ldest)) {
+ ALOGE("%s: queueBuffer failed for left mixer ", __FUNCTION__);
+ return false;
+ }
+ else {
+ ALOGD_IF(isDebug(), "%s: Queue left-handle successful: hnd:0x%x "
+ "ldest:%d", __FUNCTION__, (unsigned int) hnd, ldest);
+ }
+ }
+ else {
+ ALOGE("%s: Invalid l-Split Dest", __FUNCTION__);
+ return false;
+ }
+
+ // play right mixer
+ if (rdest != ovutils::OV_INVALID) {
+ ALOGD_IF(isDebug(), "%s: Queuing right mixer", __FUNCTION__);
+ if (!ov.queueBuffer(fd, offset, rdest)) {
+ ALOGE("%s: queueBuffer failed for right mixer ", __FUNCTION__);
+ return false;
+ }
+ else {
+ ALOGD_IF(isDebug(), "%s: Queue right-handle successful: hnd:0x%x "
+ "rdest:%d", __FUNCTION__, (unsigned int) hnd, rdest);
+ }
+ }
+ else {
+ ALOGE("%s: Invalid r-Split Dest", __FUNCTION__);
+ return false;
+ }
+ return true;
+}
+
+bool VPUClient::drawDummyLayers(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list)
{
int err = 0;
- if(!mVPU)
- return err;
- // Queue buffers to VPU
- return err;
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ VpuLayerProp* prop = &mProp[dpy][i];
+
+ if (!prop->vpuLayer)
+ continue;
+
+ // displaying blank screen for the first frame
+ if (prop->firstBuffer) {
+ ALOGD_IF(isDebug(), "%s: Displaying first (blank) frame",
+ __FUNCTION__);
+ prop->firstBuffer = false;
+
+ if (mHnd[dpy][i] != NULL)
+ free_buffer(mHnd[dpy][i]);
+
+ // TO-FIX: out dummy buffer is currently allocated based on
+ // RGB888 format
+ err = alloc_buffer(&mHnd[dpy][i], prop->width, prop->height,
+ HAL_PIXEL_FORMAT_RGB_888, GRALLOC_USAGE_PRIVATE_IOMMU_HEAP);
+ if (err == -1) {
+ ALOGE("%s: Dummy buffer allocation failed!", __FUNCTION__);
+ return false;
+ }
+
+ private_handle_t* hnd = mHnd[dpy][i];
+ if (prop->format == HAL_PIXEL_FORMAT_RGB_888) {
+ ALOGD_IF(isDebug(), "%s: Format: RGB888", __FUNCTION__);
+ memset((void*)hnd->base, 0x0, hnd->size);
+ }
+ else if (prop->format ==
+ HAL_PIXEL_FORMAT_YCbCr_422_I_10BIT_COMPRESSED) {
+ ALOGD_IF(isDebug(), "%s: Format: 10BIT_BWC", __FUNCTION__);
+ memset((void*)hnd->base, 0xaa, hnd->size);
+ }
+ else {
+ ALOGE("%s: Error! Wrong VPU out format - layer:%d",
+ __FUNCTION__, i);
+ return false;
+ }
+
+ bool isSplit = isDisplaySplit(ctx, dpy);
+ if (!isSplit ? !queueHandle(ctx, prop, hnd) :
+ !queueHandleSplit(ctx, prop, hnd)) {
+ ALOGD_IF(isDebug(), "%s: Error in queue handle: layer:%d",
+ __FUNCTION__, i);
+ return false;
+ }
+ else {
+ ALOGD_IF(isDebug(), "%s: queue handle successful: hnd:0x%x "
+ "layer:%d", __FUNCTION__, (unsigned int) hnd, i);
+ }
+ }
+ }
+ return true;
+}
+
+int VPUClient::predraw(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list)
+{
+ if (!mVPU) {
+ return -1;
+ }
+
+ if (!ctx || !list) {
+ ALOGE("%s: invalid contxt or list",__FUNCTION__);
+ return -1;
+ }
+
+ if (ctx->listStats[display].numAppLayers > MAX_NUM_APP_LAYERS) {
+ ALOGE("%s: Exceeding max layer count", __FUNCTION__);
+ return -1;
+ }
+
+ // Although all the video layers are composed through VPU, but still need to
+ // queue the first buffer (blank screen) to mdp in order to initialize the
+ // settings
+ if (!drawDummyLayers(ctx, display, list)) {
+ ALOGE("%s: Failed to draw the first layer through overlay",
+ __FUNCTION__);
+ return -1;
+ }
+ return 0;
+}
+
+int VPUClient::draw(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list)
+{
+ if (!mVPU) {
+ return -1;
+ }
+
+ LayerList *vpuList = vList[display];
+ vpuList->numLayers = list->numHwLayers;
+
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ Layer *vLayer = &vpuList->layers[i];
+
+ // setting layer info again for the update content.
+ setLayer(layer, vLayer);
+ }
+
+ // queuing the buffer to VPU
+ if (mVPU->draw((DISPLAY_ID)display, vpuList) != NO_ERROR) {
+ //error in vpu draw
+ ALOGE("%s: ERROR in VPU::draw", __func__);
+ return -1;
+ }
+
+ ALOGD_IF(isDebug2(), "%s: Done VFM draw", __FUNCTION__);
+
+ LayerProp *layerProp = ctx->layerProp[display];
+ // setting releaseFenceFd for the vpu layer
+ for (unsigned int i=0; i<(vpuList->numLayers); ++i) {
+
+ VpuLayerProp* prop = &mProp[display][i];
+ if (!prop->vpuLayer)
+ continue;
+
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ Layer *vLayer = &vpuList->layers[i];
+
+ // TODO: Fix properly once the releaseFenceFd is implemented
+ layer->releaseFenceFd = vLayer->releaseFenceFd;
+ ALOGD_IF(isDebug(), "%s: releaseFd:%d for layer:%d", __FUNCTION__,
+ layer->releaseFenceFd, i);
+ }
+ return 0;
+}
+
+int VPUClient::getLayerIdx(int dpy, hwc_layer_1_t *layer)
+{
+ for (int i=0; i < MAX_NUM_APP_LAYERS; ++i) {
+ VpuLayerProp* prop = &mProp[dpy][i];
+
+ if (!prop->vpuLayer)
+ continue;
+
+ if (prop->layer == layer) {
+ ALOGD_IF(isDebug2(), "%s: OUT - dpy:%d", __FUNCTION__, dpy);
+ return i;
+ }
+ }
+ return -1;
+}
+
+int VPUClient::getLayerFormat(int dpy, hwc_layer_1_t *layer)
+{
+ if (!mVPU) {
+ return -1;
+ }
+
+ int idx = -1;
+ if ((idx = getLayerIdx(dpy, layer)) == -1) {
+ ALOGE("%s: Layer not found!", __FUNCTION__);
+ return -1;
+ }
+
+ VpuLayerProp* prop = &mProp[dpy][idx];
+ ALOGD_IF(isDebug(), "%s: layer:%d format:0x%x", __FUNCTION__, idx,
+ (unsigned int) prop->format);
+
+ return prop->format;
+}
+
+int VPUClient::getWidth(int dpy, hwc_layer_1_t *layer)
+{
+ if (!mVPU) {
+ return -1;
+ }
+
+ int idx = -1;
+ if ((idx = getLayerIdx(dpy, layer)) == -1) {
+ ALOGE("%s: Layer not found!", __FUNCTION__);
+ return -1;
+ }
+
+ VpuLayerProp* prop = &mProp[dpy][idx];
+ ALOGD_IF(isDebug(), "%s: layer:%d width:%d", __FUNCTION__, idx,
+ prop->width);
+
+ return prop->width;
+}
+
+int VPUClient::getHeight(int dpy, hwc_layer_1_t *layer)
+{
+ if (!mVPU) {
+ return -1;
+ }
+
+ int idx = -1;
+ if ((idx = getLayerIdx(dpy, layer)) == -1) {
+ ALOGE("%s: Layer not found!", __FUNCTION__);
+ return -1;
+ }
+
+ VpuLayerProp* prop = &mProp[dpy][idx];
+ ALOGD_IF(isDebug(), "%s: layer:%d height:%d", __FUNCTION__, idx,
+ prop->height);
+
+ return prop->height;
+}
+
+// TODO: getter function has side-effect. Need to cleanup
+void VPUClient::getPipeId(VpuLayerProp* prop, int &pipe)
+{
+ pipe = (prop->pipeCount == 1) ? (prop->pipeID[0]) : -1;
+}
+
+void VPUClient::getPipeId(VpuLayerProp* prop, int &lPipe, int &rPipe)
+{
+ lPipe = (prop->pipeCount == 2) ? (prop->pipeID[0]) : -1;
+ rPipe = (prop->pipeCount == 2) ? (prop->pipeID[1]) : -1;
+}
+
+int VPUClient::getDest(VpuLayerProp* prop, int pipenum)
+{
+ return (prop->pipeCount > 0) ? (prop->dest[pipenum]) : -1;
+}
+
+void VPUClient::setPipeCount(VpuLayerProp* prop, int count)
+{
+ prop->pipeCount = count;
+}
+
+void VPUClient::setPipeId(VpuLayerProp* prop, int lPipeId, int rPipeId)
+{
+ prop->pipeCount = 2;
+ prop->pipeID[0] = lPipeId;
+ prop->pipeID[1] = rPipeId;
+}
+
+void VPUClient::setPipeId(VpuLayerProp* prop, int pipeId)
+{
+ prop->pipeCount = 1;
+ prop->pipeID[0] = pipeId;
+}
+
+void VPUClient::setDest(VpuLayerProp* prop, int lDest, int rDest)
+{
+ prop->dest[0] = lDest;
+ prop->dest[1] = rDest;
+}
+
+void VPUClient::setDest(VpuLayerProp* prop, int dest)
+{
+ prop->dest[0] = dest;
+}
+
+bool VPUClient::supportedVPULayer(VpuLayerProp* prop)
+{
+ if (!prop->vpuLayer)
+ return false;
+
+ return true;
+}
+
+bool VPUClient::supportedVPULayer(int dpy, hwc_layer_1_t *layer)
+{
+ if (!mVPU) {
+ return false;
+ }
+
+ int idx = -1;
+ if ((idx = getLayerIdx(dpy, layer)) == -1) {
+ ALOGD_IF(isDebug(), "%s: Layer not found!", __FUNCTION__);
+ return false;
+ }
+ return true;
}
int VPUClient::processCommand(uint32_t command,
- const Parcel* inParcel, Parcel* outParcel)
+ const Parcel* inParcel, Parcel* outParcel)
{
- if(!mVPU)
+ if (!mVPU)
return 0;
- //XXX: Enable when VPU enables it
- //return mVPU->processCommand(command, inParcel, outParcel);
- return 0;
+
+ return mVPU->processCommand(command, inParcel, outParcel);
}
}; // namespace qhwc
diff --git a/libhwcomposer/hwc_vpuclient.h b/libhwcomposer/hwc_vpuclient.h
index 99855172..bb2a4b65 100644
--- a/libhwcomposer/hwc_vpuclient.h
+++ b/libhwcomposer/hwc_vpuclient.h
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013 The Linux Foundation. All rights reserved.
+* Copyright (c) 2013-2014 The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -31,13 +31,20 @@
#define HWC_VPU_H
#include <sys/types.h>
+#include "hwc_utils.h"
+
+#define MAX_PIPES_PER_LAYER 2
//Forward declarations
struct hwc_display_contents_1;
typedef struct hwc_display_contents_1 hwc_display_contents_1_t;
+struct hwc_layer_1;
+typedef struct hwc_layer_1 hwc_layer_1_t;
struct hwc_context_t;
+
namespace vpu {
class VPU;
+struct LayerList;
};
namespace android {
class Parcel;
@@ -47,21 +54,91 @@ namespace qhwc {
class VPUClient {
public:
- VPUClient();
+ VPUClient(hwc_context_t *ctx);
~VPUClient();
- int prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list);
-
- int draw(hwc_context_t *ctx, hwc_display_contents_1_t* list);
-
+ int setupVpuSession(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list);
+ int prepare(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list);
+ int predraw(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list);
+ int draw(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list);
int processCommand(uint32_t command,
- const android::Parcel* inParcel, android::Parcel* outParcel);
+ const android::Parcel* inParcel, android::Parcel* outParcel);
+ int getLayerFormat(int dpy, hwc_layer_1_t *layer);
+ int getWidth(int dpy, hwc_layer_1_t *layer);
+ int getHeight(int dpy, hwc_layer_1_t *layer);
+ bool supportedVPULayer(int dpy, hwc_layer_1_t *layer);
private:
vpu::VPU *mVPU;
void* mVPULib;
+ /* VpuLayerProp struct:
+ * This struct corresponds to only one layer
+ * pipeCount: number of pipes required for a layer
+ * pipeID[]: pipe ids corresponding to the layer
+ */
+ struct VpuLayerProp {
+ int format;
+ int width;
+ int height;
+ int pipeCount;
+ bool vpuLayer;
+ bool firstBuffer;
+ hwc_frect_t sourceCropf;
+ hwc_layer_1_t *layer;
+ int pipeID[MAX_PIPES_PER_LAYER];
+ int dest[MAX_PIPES_PER_LAYER];
+ };
+ int mNumVpuLayers; /* total num of vpu supported layers */
+ int mGpuFallback; /* all layers are not supported by vpu */
+
+ VpuLayerProp mProp[HWC_NUM_DISPLAY_TYPES][MAX_NUM_APP_LAYERS];
+ int mDebugLogs;
+ private_handle_t *mHnd[HWC_NUM_DISPLAY_TYPES][MAX_NUM_APP_LAYERS];
+ vpu::LayerList *vList[HWC_NUM_DISPLAY_TYPES];
+
+ /* Private debug functions */
+ int32_t isDebug() { return (mDebugLogs >= 1); }
+ int32_t isDebug2() { return (mDebugLogs >= 2); }
+
+ /* Private Get/Set functions */
+ int getLayerIdx(int dpy, hwc_layer_1_t *layer);
+ void getPipeId(VpuLayerProp* prop, int &pipe);
+ void getPipeId(VpuLayerProp* prop, int &lPipe, int &rPipe);
+ int getDest(VpuLayerProp* prop, int pipenum);
+ void setPipeCount(VpuLayerProp* prop, int count);
+ void setPipeId(VpuLayerProp* prop, int lPipeId, int rPipeId);
+ void setPipeId(VpuLayerProp* prop, int pipeId);
+ void setDest(VpuLayerProp* prop, int lDest, int rDest);
+ void setDest(VpuLayerProp* prop, int dest);
+
+ /* Private implementations */
+ bool supportedVPULayer(VpuLayerProp* prop);
+ bool allocResLayerPipes(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ bool allocLayerPipes(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ bool allocResLayerPipesSplit(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ bool allocLayerPipesSplit(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ bool configureLayers(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ bool configureLayersSplit(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ void setMDPCompLayerFlags(hwc_context_t *ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ bool drawDummyLayers(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ bool queueHandle(hwc_context_t* ctx, VpuLayerProp* prop,
+ private_handle_t* hnd);
+ bool queueHandleSplit(hwc_context_t* ctx, VpuLayerProp* prop,
+ private_handle_t* hnd);
}; // class VPU
}; // namespace qhwc
#endif /* end of include guard: HWC_VPU_H */