diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp index 5d0cf2b..d21c3c3 100644 --- a/libgralloc/alloc_controller.cpp +++ b/libgralloc/alloc_controller.cpp @@ -71,7 +71,7 @@ static bool canFallback(int usage, bool triedSystem) if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_PRIVATE_CP_BUFFER)) return false; - if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_EXTERNAL_ONLY)) + if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY)) return false; //Return true by default return true; diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp index 4f00e4a..1ffcdfb 100644 --- a/libgralloc/gpu.cpp +++ b/libgralloc/gpu.cpp @@ -146,11 +146,13 @@ int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage, flags |= private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED; } - if (usage & GRALLOC_USAGE_EXTERNAL_ONLY) { + if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY) { flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY; //The EXTERNAL_BLOCK flag is always an add-on - if (usage & GRALLOC_USAGE_EXTERNAL_BLOCK) { + if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_BLOCK) { flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK; + }if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_CC) { + flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_CC; } } diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h index 1333edb..ae28a57 100644 --- a/libgralloc/gralloc_priv.h +++ b/libgralloc/gralloc_priv.h @@ -74,18 +74,20 @@ enum { GRALLOC_USAGE_PRIVATE_DO_NOT_MAP = 0X00800000, /* Buffer content should be displayed on an external display only */ - GRALLOC_USAGE_EXTERNAL_ONLY = 0x00010000, + GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY = 0x00010000, /* Only this buffer content should be displayed on external, even if * other EXTERNAL_ONLY buffers are available. Used during suspend. */ - GRALLOC_USAGE_EXTERNAL_BLOCK = 0x00020000, + GRALLOC_USAGE_PRIVATE_EXTERNAL_BLOCK = 0x00020000, + + /* Close Caption displayed on an external display only */ + GRALLOC_USAGE_PRIVATE_EXTERNAL_CC = 0x00040000, /* Use this flag to request content protected buffers. Please note * that this flag is different from the GRALLOC_USAGE_PROTECTED flag * which can be used for buffers that are not secured for DRM * but still need to be protected from screen captures - * 0x00040000 is reserved and these values are subject to change. */ GRALLOC_USAGE_PRIVATE_CP_BUFFER = 0x00080000, }; @@ -165,6 +167,8 @@ struct private_handle_t : public native_handle { PRIV_FLAGS_EXTERNAL_ONLY = 0x00002000, // Display only this buffer on external PRIV_FLAGS_EXTERNAL_BLOCK = 0x00004000, + // Display this buffer on external as close caption + PRIV_FLAGS_EXTERNAL_CC = 0x00008000, }; // file-descriptors diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk index 05d033e..51f1e00 100644 --- a/libhwcomposer/Android.mk +++ b/libhwcomposer/Android.mk @@ -9,8 +9,14 @@ LOCAL_SHARED_LIBRARIES := $(common_libs) libEGL liboverlay libgenlock \ libqdutils libhardware_legacy libdl libmemalloc LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"hwcomposer\" LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) -LOCAL_SRC_FILES := hwc.cpp hwc_video.cpp hwc_utils.cpp \ - hwc_uimirror.cpp hwc_external.cpp \ - hwc_uevents.cpp hwc_copybit.cpp \ - hwc_mdpcomp.cpp +LOCAL_SRC_FILES := hwc.cpp \ + hwc_video.cpp \ + hwc_utils.cpp \ + hwc_uimirror.cpp \ + hwc_external.cpp \ + hwc_uevents.cpp \ + hwc_copybit.cpp \ + hwc_mdpcomp.cpp \ + hwc_extonly.cpp + include $(BUILD_SHARED_LIBRARY) diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp index 442f8f6..6ee461c 100644 --- a/libhwcomposer/hwc.cpp +++ b/libhwcomposer/hwc.cpp @@ -32,6 +32,7 @@ #include "hwc_copybit.h" #include "hwc_external.h" #include "hwc_mdpcomp.h" +#include "hwc_extonly.h" using namespace qhwc; @@ -80,10 +81,16 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) ctx->qbuf->unlockAllPrevious(); if (LIKELY(list)) { + //reset for this draw round + VideoOverlay::reset(); + ExtOnly::reset(); + getLayerStats(ctx, list); if(VideoOverlay::prepare(ctx, list)) { ctx->overlayInUse = true; //Nothing here + } else if(ExtOnly::prepare(ctx, list)) { + ctx->overlayInUse = true; } else if(UIMirrorOverlay::prepare(ctx, list)) { ctx->overlayInUse = true; } else if(MDPComp::configure(dev, list)) { @@ -155,6 +162,7 @@ static int hwc_set(hwc_composer_device_t *dev, hwc_context_t* ctx = (hwc_context_t*)(dev); if (LIKELY(list)) { VideoOverlay::draw(ctx, list); + ExtOnly::draw(ctx, list); CopyBit::draw(ctx, list, (EGLDisplay)dpy, (EGLSurface)sur); MDPComp::draw(ctx, list); EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); diff --git a/libhwcomposer/hwc_extonly.cpp b/libhwcomposer/hwc_extonly.cpp new file mode 100644 index 0000000..77a96b6 --- /dev/null +++ b/libhwcomposer/hwc_extonly.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, Code Aurora Forum. All rights reserved. + * + * 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 "hwc_extonly.h" +#include "hwc_external.h" +#include "hwc_qbuf.h" + +namespace qhwc { + +#define EXTONLY_DEBUG 0 + +//Static Members +ovutils::eOverlayState ExtOnly::sState = ovutils::OV_CLOSED; +int ExtOnly::sExtCount = 0; +int ExtOnly::sExtIndex = -1; +bool ExtOnly::sIsExtBlock = false; +bool ExtOnly::sIsModeOn = false; + +//Cache stats, figure out the state, config overlay +bool ExtOnly::prepare(hwc_context_t *ctx, hwc_layer_list_t *list) { + sIsModeOn = false; + if(!ctx->mMDP.hasOverlay) { + ALOGD_IF(EXTONLY_DEBUG,"%s, this hw doesnt support overlay", + __FUNCTION__); + return false; + } + if(sExtIndex == -1) { + return false; + } + chooseState(ctx); + //if the state chosen above is CLOSED, skip this block. + if(sState != ovutils::OV_CLOSED) { + hwc_layer_t *extLayer = &list->hwLayers[sExtIndex]; + if(configure(ctx, extLayer)) { + markFlags(extLayer); + sIsModeOn = true; + } + } + + ALOGD_IF(EXTONLY_DEBUG, "%s: stats: extCount = %d, extIndex = %d," + "IsExtBlock = %d, IsModeOn = %d", + __func__, sExtCount, sExtIndex, + sIsExtBlock, sIsModeOn); + + return sIsModeOn; +} + +void ExtOnly::chooseState(hwc_context_t *ctx) { + ALOGD_IF(EXTONLY_DEBUG, "%s: old state = %s", __FUNCTION__, + ovutils::getStateString(sState)); + + ovutils::eOverlayState newState = ovutils::OV_CLOSED; + + if(sExtCount > 0 && + ctx->mExtDisplay->getExternalDisplay()) { + newState = ovutils::OV_DUAL_DISP; + } + + sState = newState; + ALOGD_IF(EXTONLY_DEBUG, "%s: new chosen state = %s", __FUNCTION__, + ovutils::getStateString(sState)); +} + +void ExtOnly::markFlags(hwc_layer_t *layer) { + switch(sState) { + case ovutils::OV_DUAL_DISP: + layer->compositionType = HWC_OVERLAY; + break; + default: + break; + } +} + +bool ExtOnly::configure(hwc_context_t *ctx, hwc_layer_t *layer) { + + overlay::Overlay& ov = *(ctx->mOverlay); + ov.setState(sState); + private_handle_t *hnd = (private_handle_t *)layer->handle; + ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size); + ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF; + ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE; + ovutils::PipeArgs parg(mdpFlags, + info, + ovutils::ZORDER_0, + isFgFlag, + ovutils::ROT_FLAG_DISABLED); + ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg }; + ov.setSource(pargs, ovutils::OV_PIPE0); + + hwc_rect_t sourceCrop = layer->sourceCrop; + // x,y,w,h + ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top, + sourceCrop.right - sourceCrop.left, + sourceCrop.bottom - sourceCrop.top); + ov.setCrop(dcrop, ovutils::OV_PIPE0); + + ov.setTransform(0, ovutils::OV_PIPE0); + + //Setting position same as crop + //FIXME stretch to full screen + ov.setPosition(dcrop, ovutils::OV_PIPE0); + + if (!ov.commit(ovutils::OV_PIPE0)) { + ALOGE("%s: commit fails", __FUNCTION__); + return false; + } + return true; +} + +bool ExtOnly::draw(hwc_context_t *ctx, hwc_layer_list_t *list) +{ + if(!sIsModeOn || sExtIndex == -1) { + return true; + } + + private_handle_t *hnd = (private_handle_t *) + list->hwLayers[sExtIndex].handle; + + // Lock this buffer for read. + ctx->qbuf->lockAndAdd(hnd); + bool ret = true; + overlay::Overlay& ov = *(ctx->mOverlay); + ovutils::eOverlayState state = ov.getState(); + + switch (state) { + case ovutils::OV_DUAL_DISP: + // Play external + if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE0)) { + ALOGE("%s: queueBuffer failed for external", __FUNCTION__); + ret = false; + } + // Wait for external vsync to be done + if (!ov.waitForVsync(ovutils::OV_PIPE0)) { + ALOGE("%s: waitForVsync failed for external", __FUNCTION__); + ret = false; + } + break; + default: + ALOGE("%s Unused state %s", __FUNCTION__, + ovutils::getStateString(state)); + break; + } + + return ret; +} + +}; //namespace qhwc diff --git a/libhwcomposer/hwc_extonly.h b/libhwcomposer/hwc_extonly.h new file mode 100644 index 0000000..26d5fb9 --- /dev/null +++ b/libhwcomposer/hwc_extonly.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, Code Aurora Forum. All rights reserved. + * + * 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_EXTONLY_H +#define HWC_EXTONLY_H + +#include +#include "hwc_utils.h" + +#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) + +namespace qhwc { +//Feature for using overlay to display external-only layers on HDTV +class ExtOnly { +public: + //Sets up members and prepares overlay if conditions are met + static bool prepare(hwc_context_t *ctx, hwc_layer_list_t *list); + //Draws layer if this feature is on + static bool draw(hwc_context_t *ctx, hwc_layer_list_t *list); + //Receives data from hwc + static void setStats(int extCount, int extIndex, bool isExtBlock); + //resets values + static void reset(); +private: + //Choose an appropriate overlay state based on conditions + static void chooseState(hwc_context_t *ctx); + //Configures overlay + static bool configure(hwc_context_t *ctx, hwc_layer_t *layer); + //Marks layer flags if this feature is used + static void markFlags(hwc_layer_t *layer); + //returns ext-only count + static int getExtCount(); + + //The chosen overlay state. + static ovutils::eOverlayState sState; + //Number of ext-only layers in this drawing round. Used for stats/debugging. + //This does not reflect the closed caption layer count even though its + //ext-only. + static int sExtCount; + //Index of ext-only layer. If there are 2 such layers with 1 marked as BLOCK + //then this will hold the index of BLOCK layer. + static int sExtIndex; + //Flags if ext-only layer is BLOCK, which means only this layer (sExtIndex) + //is displayed even if other ext-only layers are present to block their + //content. This is used for stats / debugging only. + static bool sIsExtBlock; + //Flags if this feature is on. + static bool sIsModeOn; +}; + +inline void ExtOnly::setStats(int extCount, int extIndex, bool isExtBlock) { + sExtCount = extCount; + sExtIndex = extIndex; + sIsExtBlock = isExtBlock; +} + +inline int ExtOnly::getExtCount() { return sExtCount; } +inline void ExtOnly::reset() { + sExtCount = 0; + sExtIndex = -1; + sIsExtBlock = false; + sIsModeOn = false; + sState = ovutils::OV_CLOSED; +} + +}; //namespace qhwc + +#endif //HWC_EXTONLY_H diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp index dd890a9..8bc8bfc 100644 --- a/libhwcomposer/hwc_utils.cpp +++ b/libhwcomposer/hwc_utils.cpp @@ -23,6 +23,7 @@ #include "hwc_copybit.h" #include "hwc_external.h" #include "hwc_mdpcomp.h" +#include "hwc_extonly.h" namespace qhwc { @@ -107,18 +108,32 @@ void getLayerStats(hwc_context_t *ctx, const hwc_layer_list_t *list) int yuvLayerIndex = -1; bool isYuvLayerSkip = false; int skipCount = 0; + int ccLayerIndex = -1; //closed caption + int extLayerIndex = -1; //ext-only or block except closed caption + int extCount = 0; //ext-only except closed caption + bool isExtBlockPresent = false; //is BLOCK layer present for (size_t i = 0; i < list->numHwLayers; i++) { private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; - if (isYuvBuffer(hnd)) { + if (UNLIKELY(isYuvBuffer(hnd))) { yuvCount++; yuvLayerIndex = i; //Animating if (isSkipLayer(&list->hwLayers[i])) { isYuvLayerSkip = true; } + } else if(UNLIKELY(isExtCC(hnd))) { + ccLayerIndex = i; + } else if(UNLIKELY(isExtBlock(hnd))) { + extCount++; + extLayerIndex = i; + isExtBlockPresent = true; + } else if(UNLIKELY(isExtOnly(hnd))) { + extCount++; + //If BLOCK layer present, dont cache index, display BLOCK only. + if(isExtBlockPresent == false) extLayerIndex = i; } else if (isSkipLayer(&list->hwLayers[i])) { //Popups //If video layer is below a skip layer if(yuvLayerIndex != -1 && yuvLayerIndex < (ssize_t)i) { @@ -128,7 +143,9 @@ void getLayerStats(hwc_context_t *ctx, const hwc_layer_list_t *list) } } - VideoOverlay::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip); + VideoOverlay::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip, + ccLayerIndex); + ExtOnly::setStats(extCount, extLayerIndex, isExtBlockPresent); CopyBit::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip); MDPComp::setStats(skipCount); diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h index 9ce0815..71c1f73 100644 --- a/libhwcomposer/hwc_utils.h +++ b/libhwcomposer/hwc_utils.h @@ -90,6 +90,21 @@ static inline bool isBufferLocked(const private_handle_t* hnd) { return (hnd && (private_handle_t::PRIV_FLAGS_HWC_LOCK & hnd->flags)); } +//Return true if buffer is for external display only +static inline bool isExtOnly(const private_handle_t* hnd) { + return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY)); +} + +//Return true if buffer is for external display only with a BLOCK flag. +static inline bool isExtBlock(const private_handle_t* hnd) { + return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK)); +} + +//Return true if buffer is for external display only with a Close Caption flag. +static inline bool isExtCC(const private_handle_t* hnd) { + return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_CC)); +} + // Initialize uevent thread void init_uevent_thread(hwc_context_t* ctx); diff --git a/libhwcomposer/hwc_video.cpp b/libhwcomposer/hwc_video.cpp index a0ae331..4fb88d7 100644 --- a/libhwcomposer/hwc_video.cpp +++ b/libhwcomposer/hwc_video.cpp @@ -29,8 +29,9 @@ namespace qhwc { ovutils::eOverlayState VideoOverlay::sState = ovutils::OV_CLOSED; int VideoOverlay::sYuvCount = 0; int VideoOverlay::sYuvLayerIndex = -1; +bool VideoOverlay::sIsYuvLayerSkip = false; +int VideoOverlay::sCCLayerIndex = -1; bool VideoOverlay::sIsModeOn = false; -bool VideoOverlay::sIsLayerSkip = false; //Cache stats, figure out the state, config overlay bool VideoOverlay::prepare(hwc_context_t *ctx, hwc_layer_list_t *list) { @@ -45,15 +46,21 @@ bool VideoOverlay::prepare(hwc_context_t *ctx, hwc_layer_list_t *list) { chooseState(ctx); //if the state chosen above is CLOSED, skip this block. if(sState != ovutils::OV_CLOSED) { - if(configure(ctx, &list->hwLayers[sYuvLayerIndex])) { + hwc_layer_t *yuvLayer = &list->hwLayers[sYuvLayerIndex]; + hwc_layer_t *ccLayer = NULL; + if(sCCLayerIndex != -1) + ccLayer = &list->hwLayers[sCCLayerIndex]; + + if(configure(ctx, yuvLayer, ccLayer)) { markFlags(&list->hwLayers[sYuvLayerIndex]); sIsModeOn = true; } } ALOGD_IF(VIDEO_DEBUG, "%s: stats: yuvCount = %d, yuvIndex = %d," - "IsModeOn = %d, IsSkipLayer = %d", __FUNCTION__, sYuvCount, - sYuvLayerIndex, sIsModeOn, sIsLayerSkip); + "IsYuvLayerSkip = %d, ccLayerIndex = %d, IsModeOn = %d", + __FUNCTION__, sYuvCount, sYuvLayerIndex, + sIsYuvLayerSkip, sCCLayerIndex, sIsModeOn); return sIsModeOn; } @@ -63,14 +70,13 @@ void VideoOverlay::chooseState(hwc_context_t *ctx) { ovutils::getStateString(sState)); ovutils::eOverlayState newState = ovutils::OV_CLOSED; - //TODO check if device supports overlay and hdmi //Support 1 video layer if(sYuvCount == 1) { //Skip on primary, display on ext. - if(sIsLayerSkip && ctx->mExtDisplay->getExternalDisplay()) { + if(sIsYuvLayerSkip && ctx->mExtDisplay->getExternalDisplay()) { newState = ovutils::OV_2D_VIDEO_ON_TV; - } else if(sIsLayerSkip) { //skip on primary, no ext + } else if(sIsYuvLayerSkip) { //skip on primary, no ext newState = ovutils::OV_CLOSED; } else if(ctx->mExtDisplay->getExternalDisplay()) { //display on both @@ -228,8 +234,49 @@ bool configExtVid(hwc_context_t *ctx, hwc_layer_t *layer) { return true; } -bool VideoOverlay::configure(hwc_context_t *ctx, hwc_layer_t *yuvLayer) -{ +bool configExtCC(hwc_context_t *ctx, hwc_layer_t *layer) { + if(layer == NULL) + return true; + + overlay::Overlay& ov = *(ctx->mOverlay); + private_handle_t *hnd = (private_handle_t *)layer->handle; + ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size); + ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF; + ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE; + ovutils::PipeArgs parg(mdpFlags, + info, + ovutils::ZORDER_1, + isFgFlag, + ovutils::ROT_FLAG_DISABLED); + ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg }; + ov.setSource(pargs, ovutils::OV_PIPE2); + + hwc_rect_t sourceCrop = layer->sourceCrop; + // x,y,w,h + ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top, + sourceCrop.right - sourceCrop.left, + sourceCrop.bottom - sourceCrop.top); + //Only for External + ov.setCrop(dcrop, ovutils::OV_PIPE2); + + // FIXME: Use source orientation for TV when source is portrait + //Only for External + ov.setTransform(0, ovutils::OV_PIPE2); + + //Setting position same as crop + //FIXME stretch to full screen + ov.setPosition(dcrop, ovutils::OV_PIPE2); + + if (!ov.commit(ovutils::OV_PIPE2)) { + ALOGE("%s: commit fails", __FUNCTION__); + return false; + } + return true; +} + +bool VideoOverlay::configure(hwc_context_t *ctx, hwc_layer_t *yuvLayer, + hwc_layer_t *ccLayer) { + bool ret = true; if (LIKELY(ctx->mOverlay)) { overlay::Overlay& ov = *(ctx->mOverlay); @@ -241,10 +288,12 @@ bool VideoOverlay::configure(hwc_context_t *ctx, hwc_layer_t *yuvLayer) break; case ovutils::OV_2D_VIDEO_ON_PANEL_TV: ret &= configExtVid(ctx, yuvLayer); + ret &= configExtCC(ctx, ccLayer); ret &= configPrimVid(ctx, yuvLayer); break; case ovutils::OV_2D_VIDEO_ON_TV: ret &= configExtVid(ctx, yuvLayer); + ret &= configExtCC(ctx, ccLayer); break; default: return false; @@ -262,11 +311,18 @@ bool VideoOverlay::draw(hwc_context_t *ctx, hwc_layer_list_t *list) return true; } - private_handle_t *hnd = - (private_handle_t *)list->hwLayers[sYuvLayerIndex].handle; + private_handle_t *hnd = (private_handle_t *) + list->hwLayers[sYuvLayerIndex].handle; + + private_handle_t *cchnd = NULL; + if(sCCLayerIndex != -1) { + cchnd = (private_handle_t *)list->hwLayers[sCCLayerIndex].handle; + ctx->qbuf->lockAndAdd(cchnd); + } // Lock this buffer for read. ctx->qbuf->lockAndAdd(hnd); + bool ret = true; overlay::Overlay& ov = *(ctx->mOverlay); ovutils::eOverlayState state = ov.getState(); @@ -278,6 +334,12 @@ bool VideoOverlay::draw(hwc_context_t *ctx, hwc_layer_list_t *list) ALOGE("%s: queueBuffer failed for external", __FUNCTION__); ret = false; } + //Play CC on external + if (cchnd && !ov.queueBuffer(cchnd->fd, cchnd->offset, + ovutils::OV_PIPE2)) { + ALOGE("%s: queueBuffer failed for cc external", __FUNCTION__); + ret = false; + } // Play primary if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE0)) { ALOGE("%s: queueBuffer failed for primary", __FUNCTION__); @@ -302,11 +364,18 @@ bool VideoOverlay::draw(hwc_context_t *ctx, hwc_layer_list_t *list) ALOGE("%s: queueBuffer failed for external", __FUNCTION__); ret = false; } + //Play CC on external + if (cchnd && !ov.queueBuffer(cchnd->fd, cchnd->offset, + ovutils::OV_PIPE2)) { + ALOGE("%s: queueBuffer failed for cc external", __FUNCTION__); + ret = false; + } // Wait for external vsync to be done if (!ov.waitForVsync(ovutils::OV_PIPE1)) { ALOGE("%s: waitForVsync failed for external", __FUNCTION__); ret = false; } + break; default: ALOGE("%s Unused state %s", __FUNCTION__, ovutils::getStateString(state)); diff --git a/libhwcomposer/hwc_video.h b/libhwcomposer/hwc_video.h index c6c6c22..62a32a9 100644 --- a/libhwcomposer/hwc_video.h +++ b/libhwcomposer/hwc_video.h @@ -30,12 +30,16 @@ public: //Draws layer if this feature is on static bool draw(hwc_context_t *ctx, hwc_layer_list_t *list); //Receives data from hwc - static void setStats(int yuvCount, int yuvLayerIndex, bool isYuvLayerSkip); + static void setStats(int yuvCount, int yuvLayerIndex, bool isYuvLayerSkip, + int ccLayerIndex); + //resets values + static void reset(); private: //Choose an appropriate overlay state based on conditions static void chooseState(hwc_context_t *ctx); - //Configures overlay - static bool configure(hwc_context_t *ctx, hwc_layer_t *layer); + //Configures overlay for video prim and ext + static bool configure(hwc_context_t *ctx, hwc_layer_t *yuvlayer, + hwc_layer_t *ccLayer); //Marks layer flags if this feature is used static void markFlags(hwc_layer_t *layer); //returns yuv count @@ -48,20 +52,30 @@ private: //Index of YUV layer, relevant only if count is 1 static int sYuvLayerIndex; //Flags if a yuv layer is animating or below something that is animating - static bool sIsLayerSkip; + static bool sIsYuvLayerSkip; + //Holds the closed caption layer index, -1 by default + static int sCCLayerIndex; //Flags if this feature is on. static bool sIsModeOn; }; inline void VideoOverlay::setStats(int yuvCount, int yuvLayerIndex, - bool isYuvLayerSkip) { + bool isYuvLayerSkip, int ccLayerIndex) { sYuvCount = yuvCount; sYuvLayerIndex = yuvLayerIndex; - sIsLayerSkip = isYuvLayerSkip; + sIsYuvLayerSkip = isYuvLayerSkip; + sCCLayerIndex = ccLayerIndex; } inline int VideoOverlay::getYuvCount() { return sYuvCount; } - +inline void VideoOverlay::reset() { + sYuvCount = 0; + sYuvLayerIndex = -1; + sIsYuvLayerSkip = false; + sCCLayerIndex = -1; + sIsModeOn = false; + sState = ovutils::OV_CLOSED; +} }; //namespace qhwc #endif //HWC_VIDEO_H diff --git a/liboverlay/overlayState.h b/liboverlay/overlayState.h index 518eafa..e4fbece 100644 --- a/liboverlay/overlayState.h +++ b/liboverlay/overlayState.h @@ -265,7 +265,7 @@ template <> struct StateTraits template <> struct StateTraits { typedef overlay::GenericPipe pipe0; - typedef overlay::GenericPipe pipe1; + typedef overlay::NullPipe pipe1; typedef overlay::NullPipe pipe2; typedef NullRotator rot0;