1. In PTOR feature, offset for the second overlap layer on render buffer, depends on stride calculated by gralloc for RGBA (4 bpp). 2. If mCopyBit object exists for external, we need setReleaseFd() Change-Id: I74e365def2a6e540b2f2ba2b294b6b1e00e0ea96
1190 lines
42 KiB
C++
1190 lines
42 KiB
C++
/*
|
|
* Copyright (C) 2010 The Android Open Source Project
|
|
* Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
|
|
*
|
|
* Not a Contribution.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#define DEBUG_COPYBIT 0
|
|
#include <copybit.h>
|
|
#include <utils/Timers.h>
|
|
#include <mdp_version.h>
|
|
#include "hwc_copybit.h"
|
|
#include "comptype.h"
|
|
#include "gr.h"
|
|
#include "cb_utils.h"
|
|
#include "cb_swap_rect.h"
|
|
#include "math.h"
|
|
#include "sync/sync.h"
|
|
|
|
using namespace qdutils;
|
|
namespace qhwc {
|
|
|
|
struct range {
|
|
int current;
|
|
int end;
|
|
};
|
|
struct region_iterator : public copybit_region_t {
|
|
|
|
region_iterator(hwc_region_t region) {
|
|
mRegion = region;
|
|
r.end = (int)region.numRects;
|
|
r.current = 0;
|
|
this->next = iterate;
|
|
}
|
|
|
|
private:
|
|
static int iterate(copybit_region_t const * self, copybit_rect_t* rect){
|
|
if (!self || !rect) {
|
|
ALOGE("iterate invalid parameters");
|
|
return 0;
|
|
}
|
|
|
|
region_iterator const* me =
|
|
static_cast<region_iterator const*>(self);
|
|
if (me->r.current != me->r.end) {
|
|
rect->l = me->mRegion.rects[me->r.current].left;
|
|
rect->t = me->mRegion.rects[me->r.current].top;
|
|
rect->r = me->mRegion.rects[me->r.current].right;
|
|
rect->b = me->mRegion.rects[me->r.current].bottom;
|
|
me->r.current++;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
hwc_region_t mRegion;
|
|
mutable range r;
|
|
};
|
|
|
|
void CopyBit::reset() {
|
|
mIsModeOn = false;
|
|
mCopyBitDraw = false;
|
|
}
|
|
|
|
bool CopyBit::canUseCopybitForYUV(hwc_context_t *ctx) {
|
|
// return true for non-overlay targets
|
|
if(ctx->mMDP.hasOverlay && ctx->mMDP.version >= qdutils::MDP_V4_0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CopyBit::canUseCopybitForRGB(hwc_context_t *ctx,
|
|
hwc_display_contents_1_t *list,
|
|
int dpy) {
|
|
int compositionType = qdutils::QCCompositionType::
|
|
getInstance().getCompositionType();
|
|
|
|
if (compositionType & qdutils::COMPOSITION_TYPE_DYN) {
|
|
// DYN Composition:
|
|
// use copybit, if (TotalRGBRenderArea < threashold * FB Area)
|
|
// this is done based on perf inputs in ICS
|
|
// TODO: Above condition needs to be re-evaluated in JB
|
|
int fbWidth = ctx->dpyAttr[dpy].xres;
|
|
int fbHeight = ctx->dpyAttr[dpy].yres;
|
|
unsigned int fbArea = (fbWidth * fbHeight);
|
|
unsigned int renderArea = getRGBRenderingArea(list);
|
|
ALOGD_IF (DEBUG_COPYBIT, "%s:renderArea %u, fbArea %u",
|
|
__FUNCTION__, renderArea, fbArea);
|
|
if (renderArea < (mDynThreshold * fbArea)) {
|
|
return true;
|
|
}
|
|
} else if ((compositionType & qdutils::COMPOSITION_TYPE_MDP)) {
|
|
// MDP composition, use COPYBIT always
|
|
return true;
|
|
} else if ((compositionType & qdutils::COMPOSITION_TYPE_C2D)) {
|
|
// C2D composition, use COPYBIT
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
unsigned int CopyBit::getRGBRenderingArea
|
|
(const hwc_display_contents_1_t *list) {
|
|
//Calculates total rendering area for RGB layers
|
|
unsigned int renderArea = 0;
|
|
unsigned int w=0, h=0;
|
|
// Skipping last layer since FrameBuffer layer should not affect
|
|
// which composition to choose
|
|
for (unsigned int i=0; i<list->numHwLayers -1; i++) {
|
|
private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
|
|
if (hnd) {
|
|
if (BUFFER_TYPE_UI == hnd->bufferType) {
|
|
getLayerResolution(&list->hwLayers[i], w, h);
|
|
renderArea += (w*h);
|
|
}
|
|
}
|
|
}
|
|
return renderArea;
|
|
}
|
|
|
|
int CopyBit::getLayersChanging(hwc_context_t *ctx,
|
|
hwc_display_contents_1_t *list,
|
|
int dpy){
|
|
|
|
int changingLayerIndex = -1;
|
|
if(mLayerCache.layerCount != ctx->listStats[dpy].numAppLayers) {
|
|
mLayerCache.reset();
|
|
mFbCache.reset();
|
|
mLayerCache.updateCounts(ctx,list,dpy);
|
|
return -1;
|
|
}
|
|
|
|
int updatingLayerCount = 0;
|
|
for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--){
|
|
//swap rect will kick in only for single updating layer
|
|
if(mLayerCache.hnd[k] != list->hwLayers[k].handle){
|
|
updatingLayerCount ++;
|
|
if(updatingLayerCount == 1)
|
|
changingLayerIndex = k;
|
|
}
|
|
}
|
|
//since we are using more than one framebuffers,we have to
|
|
//kick in swap rect only if we are getting continuous same
|
|
//dirty rect for same layer at least equal of number of
|
|
//framebuffers
|
|
|
|
if ( updatingLayerCount == 1 ) {
|
|
hwc_rect_t dirtyRect = list->hwLayers[changingLayerIndex].displayFrame;
|
|
#ifdef QCOM_BSP
|
|
dirtyRect = list->hwLayers[changingLayerIndex].dirtyRect;
|
|
#endif
|
|
|
|
for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--){
|
|
//disable swap rect for overlapping visible layer(s)
|
|
hwc_rect_t displayFrame = list->hwLayers[k].displayFrame;
|
|
hwc_rect_t result = getIntersection(displayFrame,dirtyRect);
|
|
if((k != changingLayerIndex) && isValidRect(result)){
|
|
return -1;
|
|
}
|
|
}
|
|
mFbCache.insertAndUpdateFbCache(dirtyRect);
|
|
if(mFbCache.getUnchangedFbDRCount(dirtyRect) <
|
|
NUM_RENDER_BUFFERS)
|
|
changingLayerIndex = -1;
|
|
}else {
|
|
mFbCache.reset();
|
|
changingLayerIndex = -1;
|
|
}
|
|
mLayerCache.updateCounts(ctx,list,dpy);
|
|
return changingLayerIndex;
|
|
}
|
|
|
|
int CopyBit::checkDirtyRect(hwc_context_t *ctx,
|
|
hwc_display_contents_1_t *list,
|
|
int dpy) {
|
|
|
|
//dirty rect will enable only if
|
|
//1.Only single layer is updating.
|
|
//2.No overlapping
|
|
//3.No scaling
|
|
//4.No video layer
|
|
if(mSwapRectEnable == false)
|
|
return -1;
|
|
int changingLayerIndex = getLayersChanging(ctx, list, dpy);
|
|
//swap rect will kick in only for single updating layer
|
|
if(changingLayerIndex == -1){
|
|
return -1;
|
|
}
|
|
if(!needsScaling(&list->hwLayers[changingLayerIndex])){
|
|
private_handle_t *hnd =
|
|
(private_handle_t *)list->hwLayers[changingLayerIndex].handle;
|
|
if( hnd && !isYuvBuffer(hnd))
|
|
return changingLayerIndex;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
bool CopyBit::prepareOverlap(hwc_context_t *ctx,
|
|
hwc_display_contents_1_t *list) {
|
|
|
|
if (ctx->mMDP.version < qdutils::MDP_V4_0) {
|
|
ALOGE("%s: Invalid request", __FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
if (mEngine == NULL || !(validateParams(ctx, list))) {
|
|
ALOGE("%s: Invalid Params", __FUNCTION__);
|
|
return false;
|
|
}
|
|
PtorInfo* ptorInfo = &(ctx->mPtorInfo);
|
|
|
|
// Allocate render buffers if they're not allocated
|
|
int alignW = 0, alignH = 0;
|
|
int finalW = 0, finalH = 0;
|
|
for (int i = 0; i < ptorInfo->count; i++) {
|
|
int ovlapIndex = ptorInfo->layerIndex[i];
|
|
hwc_rect_t overlap = list->hwLayers[ovlapIndex].displayFrame;
|
|
// render buffer width will be the max of two layers
|
|
// Align Widht and height to 32, Mdp would be configured
|
|
// with Aligned overlap w/h
|
|
finalW = max(finalW, ALIGN((overlap.right - overlap.left), 32));
|
|
finalH += ALIGN((overlap.bottom - overlap.top), 32);
|
|
if(finalH > ALIGN((overlap.bottom - overlap.top), 32)) {
|
|
// Calculate the dest top, left will always be zero
|
|
ptorInfo->displayFrame[i].top = (finalH -
|
|
(ALIGN((overlap.bottom - overlap.top), 32)));
|
|
}
|
|
// calculate the right and bottom values
|
|
ptorInfo->displayFrame[i].right = ptorInfo->displayFrame[i].left +
|
|
(overlap.right - overlap.left);
|
|
ptorInfo->displayFrame[i].bottom = ptorInfo->displayFrame[i].top +
|
|
(overlap.bottom - overlap.top);
|
|
}
|
|
|
|
getBufferSizeAndDimensions(finalW, finalH, HAL_PIXEL_FORMAT_RGBA_8888,
|
|
alignW, alignH);
|
|
|
|
int heightFromTop = 0;
|
|
for (int i = 0; i < ptorInfo->count; i++) {
|
|
// Offset depends on stride calculated by gralloc for RGBA (4 bpp)
|
|
ptorInfo->mRenderBuffOffset[i] = alignW * heightFromTop * 4;
|
|
heightFromTop += ALIGN((ptorInfo->displayFrame[i].bottom -
|
|
ptorInfo->displayFrame[i].top), 32);
|
|
}
|
|
|
|
if ((mAlignedWidth != alignW) || (mAlignedHeight != alignH)) {
|
|
// Overlap rect has changed, so free render buffers
|
|
freeRenderBuffers();
|
|
}
|
|
|
|
int ret = allocRenderBuffers(alignW, alignH, HAL_PIXEL_FORMAT_RGBA_8888);
|
|
|
|
if (ret < 0) {
|
|
ALOGE("%s: Render buffer allocation failed", __FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
mAlignedWidth = alignW;
|
|
mAlignedHeight = alignH;
|
|
mCurRenderBufferIndex = (mCurRenderBufferIndex + 1) % NUM_RENDER_BUFFERS;
|
|
return true;
|
|
}
|
|
|
|
bool CopyBit::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list,
|
|
int dpy) {
|
|
|
|
if(mEngine == NULL) {
|
|
// No copybit device found - cannot use copybit
|
|
return false;
|
|
}
|
|
int compositionType = qdutils::QCCompositionType::
|
|
getInstance().getCompositionType();
|
|
|
|
if ((compositionType == qdutils::COMPOSITION_TYPE_GPU) ||
|
|
(compositionType == qdutils::COMPOSITION_TYPE_CPU)) {
|
|
//GPU/CPU composition, don't change layer composition type
|
|
return true;
|
|
}
|
|
|
|
if(!(validateParams(ctx, list))) {
|
|
ALOGE("%s:Invalid Params", __FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
if(ctx->listStats[dpy].skipCount) {
|
|
//GPU will be anyways used
|
|
return false;
|
|
}
|
|
|
|
if (ctx->listStats[dpy].numAppLayers > MAX_NUM_APP_LAYERS) {
|
|
// Reached max layers supported by HWC.
|
|
return false;
|
|
}
|
|
|
|
bool useCopybitForYUV = canUseCopybitForYUV(ctx);
|
|
bool useCopybitForRGB = canUseCopybitForRGB(ctx, list, dpy);
|
|
LayerProp *layerProp = ctx->layerProp[dpy];
|
|
|
|
// Following are MDP3 limitations for which we
|
|
// need to fallback to GPU composition:
|
|
// 1. Plane alpha is not supported by MDP3.
|
|
// 2. Scaling is within range
|
|
if (qdutils::MDPVersion::getInstance().getMDPVersion() < 400) {
|
|
for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) {
|
|
int dst_h, dst_w, src_h, src_w;
|
|
float dx, dy;
|
|
hwc_layer_1_t *layer = (hwc_layer_1_t *) &list->hwLayers[i];
|
|
if (layer->planeAlpha != 0xFF)
|
|
return true;
|
|
hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
|
|
|
|
if (has90Transform(layer)) {
|
|
src_h = sourceCrop.right - sourceCrop.left;
|
|
src_w = sourceCrop.bottom - sourceCrop.top;
|
|
} else {
|
|
src_h = sourceCrop.bottom - sourceCrop.top;
|
|
src_w = sourceCrop.right - sourceCrop.left;
|
|
}
|
|
dst_h = layer->displayFrame.bottom - layer->displayFrame.top;
|
|
dst_w = layer->displayFrame.right - layer->displayFrame.left;
|
|
|
|
if(src_w <=0 || src_h<=0 ||dst_w<=0 || dst_h<=0 ) {
|
|
ALOGE("%s: wrong params for display screen_w=%d \
|
|
src_crop_width=%d screen_h=%d src_crop_height=%d",
|
|
__FUNCTION__, dst_w,src_w,dst_h,src_h);
|
|
return false;
|
|
}
|
|
dx = (float)dst_w/(float)src_w;
|
|
dy = (float)dst_h/(float)src_h;
|
|
|
|
if (dx > MAX_SCALE_FACTOR || dx < MIN_SCALE_FACTOR)
|
|
return false;
|
|
|
|
if (dy > MAX_SCALE_FACTOR || dy < MIN_SCALE_FACTOR)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//Allocate render buffers if they're not allocated
|
|
if (ctx->mMDP.version != qdutils::MDP_V3_0_4 &&
|
|
(useCopybitForYUV || useCopybitForRGB)) {
|
|
int ret = allocRenderBuffers(mAlignedWidth,
|
|
mAlignedHeight,
|
|
HAL_PIXEL_FORMAT_RGBA_8888);
|
|
if (ret < 0) {
|
|
return false;
|
|
} else {
|
|
mCurRenderBufferIndex = (mCurRenderBufferIndex + 1) %
|
|
NUM_RENDER_BUFFERS;
|
|
}
|
|
}
|
|
|
|
// We cannot mix copybit layer with layers marked to be drawn on FB
|
|
if (!useCopybitForYUV && ctx->listStats[dpy].yuvCount)
|
|
return true;
|
|
|
|
mCopyBitDraw = false;
|
|
if (useCopybitForRGB &&
|
|
(useCopybitForYUV || !ctx->listStats[dpy].yuvCount)) {
|
|
mCopyBitDraw = true;
|
|
// numAppLayers-1, as we iterate till 0th layer index
|
|
// Mark all layers to be drawn by copybit
|
|
for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) {
|
|
layerProp[i].mFlags |= HWC_COPYBIT;
|
|
#ifdef QCOM_BSP
|
|
if (ctx->mMDP.version == qdutils::MDP_V3_0_4)
|
|
list->hwLayers[i].compositionType = HWC_BLIT;
|
|
else
|
|
#endif
|
|
list->hwLayers[i].compositionType = HWC_OVERLAY;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int CopyBit::clear (private_handle_t* hnd, hwc_rect_t& rect)
|
|
{
|
|
int ret = 0;
|
|
copybit_rect_t clear_rect = {rect.left, rect.top,
|
|
rect.right,
|
|
rect.bottom};
|
|
|
|
copybit_image_t buf;
|
|
buf.w = ALIGN(getWidth(hnd),32);
|
|
buf.h = getHeight(hnd);
|
|
buf.format = hnd->format;
|
|
buf.base = (void *)hnd->base;
|
|
buf.handle = (native_handle_t *)hnd;
|
|
|
|
copybit_device_t *copybit = mEngine;
|
|
ret = copybit->clear(copybit, &buf, &clear_rect);
|
|
return ret;
|
|
}
|
|
|
|
bool CopyBit::drawUsingAppBufferComposition(hwc_context_t *ctx,
|
|
hwc_display_contents_1_t *list,
|
|
int dpy, int *copybitFd) {
|
|
int layerCount = 0;
|
|
uint32_t last = (uint32_t)list->numHwLayers - 1;
|
|
hwc_layer_1_t *fbLayer = &list->hwLayers[last];
|
|
private_handle_t *fbhnd = (private_handle_t *)fbLayer->handle;
|
|
|
|
if(ctx->enableABC == false)
|
|
return false;
|
|
|
|
if(ctx->listStats[dpy].numAppLayers > MAX_LAYERS_FOR_ABC )
|
|
return false;
|
|
|
|
layerCount = ctx->listStats[dpy].numAppLayers;
|
|
//bottom most layer should
|
|
//equal to FB
|
|
hwc_layer_1_t *tmpLayer = &list->hwLayers[0];
|
|
private_handle_t *hnd = (private_handle_t *)tmpLayer->handle;
|
|
if(hnd && fbhnd && (hnd->size == fbhnd->size) &&
|
|
(hnd->width == fbhnd->width) && (hnd->height == fbhnd->height)){
|
|
if(tmpLayer->transform ||
|
|
(!(hnd->format == HAL_PIXEL_FORMAT_RGBA_8888 ||
|
|
hnd->format == HAL_PIXEL_FORMAT_RGBX_8888)) ||
|
|
(needsScaling(tmpLayer) == true)) {
|
|
return false;
|
|
}else {
|
|
ctx->listStats[dpy].renderBufIndexforABC = 0;
|
|
}
|
|
}
|
|
|
|
if(ctx->listStats[dpy].renderBufIndexforABC == 0) {
|
|
if(layerCount == 1)
|
|
return true;
|
|
|
|
if(layerCount == MAX_LAYERS_FOR_ABC) {
|
|
int abcRenderBufIdx = ctx->listStats[dpy].renderBufIndexforABC;
|
|
//enable ABC only for non intersecting layers.
|
|
hwc_rect_t displayFrame =
|
|
list->hwLayers[abcRenderBufIdx].displayFrame;
|
|
for (int i = abcRenderBufIdx + 1; i < layerCount; i++) {
|
|
hwc_rect_t tmpDisplayFrame = list->hwLayers[i].displayFrame;
|
|
hwc_rect_t result = getIntersection(displayFrame,tmpDisplayFrame);
|
|
if (isValidRect(result)) {
|
|
ctx->listStats[dpy].renderBufIndexforABC = -1;
|
|
return false;
|
|
}
|
|
}
|
|
// Pass the Acquire Fence FD to driver for base layer
|
|
private_handle_t *renderBuffer =
|
|
(private_handle_t *)list->hwLayers[abcRenderBufIdx].handle;
|
|
copybit_device_t *copybit = getCopyBitDevice();
|
|
if(list->hwLayers[abcRenderBufIdx].acquireFenceFd >=0){
|
|
copybit->set_sync(copybit,
|
|
list->hwLayers[abcRenderBufIdx].acquireFenceFd);
|
|
}
|
|
for(int i = abcRenderBufIdx + 1; i < layerCount; i++){
|
|
int retVal = drawLayerUsingCopybit(ctx,
|
|
&(list->hwLayers[i]),renderBuffer, 0);
|
|
if(retVal < 0) {
|
|
ALOGE("%s : Copybit failed", __FUNCTION__);
|
|
}
|
|
}
|
|
// Get Release Fence FD of copybit for the App layer(s)
|
|
copybit->flush_get_fence(copybit, copybitFd);
|
|
close(list->hwLayers[abcRenderBufIdx].acquireFenceFd);
|
|
list->hwLayers[abcRenderBufIdx].acquireFenceFd = -1;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CopyBit::draw(hwc_context_t *ctx, hwc_display_contents_1_t *list,
|
|
int dpy, int32_t *fd) {
|
|
// draw layers marked for COPYBIT
|
|
int retVal = true;
|
|
int copybitLayerCount = 0;
|
|
uint32_t last = 0;
|
|
LayerProp *layerProp = ctx->layerProp[dpy];
|
|
private_handle_t *renderBuffer;
|
|
|
|
if(mCopyBitDraw == false){
|
|
mFbCache.reset(); // there is no layer marked for copybit
|
|
return false ;
|
|
}
|
|
|
|
if(drawUsingAppBufferComposition(ctx, list, dpy, fd)) {
|
|
return true;
|
|
}
|
|
//render buffer
|
|
if (ctx->mMDP.version == qdutils::MDP_V3_0_4) {
|
|
last = (uint32_t)list->numHwLayers - 1;
|
|
renderBuffer = (private_handle_t *)list->hwLayers[last].handle;
|
|
} else {
|
|
renderBuffer = getCurrentRenderBuffer();
|
|
}
|
|
if (!renderBuffer) {
|
|
ALOGE("%s: Render buffer layer handle is NULL", __FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
if (ctx->mMDP.version >= qdutils::MDP_V4_0) {
|
|
//Wait for the previous frame to complete before rendering onto it
|
|
if(mRelFd[mCurRenderBufferIndex] >=0) {
|
|
sync_wait(mRelFd[mCurRenderBufferIndex], 1000);
|
|
close(mRelFd[mCurRenderBufferIndex]);
|
|
mRelFd[mCurRenderBufferIndex] = -1;
|
|
}
|
|
} else {
|
|
if(list->hwLayers[last].acquireFenceFd >=0) {
|
|
copybit_device_t *copybit = getCopyBitDevice();
|
|
copybit->set_sync(copybit, list->hwLayers[last].acquireFenceFd);
|
|
}
|
|
}
|
|
|
|
mDirtyLayerIndex = checkDirtyRect(ctx, list, dpy);
|
|
if( mDirtyLayerIndex != -1){
|
|
hwc_layer_1_t *layer = &list->hwLayers[mDirtyLayerIndex];
|
|
#ifdef QCOM_BSP
|
|
clear(renderBuffer,layer->dirtyRect);
|
|
#else
|
|
clear(renderBuffer,layer->displayFrame);
|
|
#endif
|
|
} else {
|
|
hwc_rect_t clearRegion = {0,0,0,0};
|
|
if(CBUtils::getuiClearRegion(list, clearRegion, layerProp))
|
|
clear(renderBuffer, clearRegion);
|
|
}
|
|
|
|
// numAppLayers-1, as we iterate from 0th layer index with HWC_COPYBIT flag
|
|
for (int i = 0; i <= (ctx->listStats[dpy].numAppLayers-1); i++) {
|
|
if(!(layerProp[i].mFlags & HWC_COPYBIT)) {
|
|
ALOGD_IF(DEBUG_COPYBIT, "%s: Not Marked for copybit", __FUNCTION__);
|
|
continue;
|
|
}
|
|
//skip non updating layers
|
|
if((mDirtyLayerIndex != -1) && (mDirtyLayerIndex != i) )
|
|
continue;
|
|
int ret = -1;
|
|
if (list->hwLayers[i].acquireFenceFd != -1
|
|
&& ctx->mMDP.version >= qdutils::MDP_V4_0) {
|
|
// Wait for acquire Fence on the App buffers.
|
|
ret = sync_wait(list->hwLayers[i].acquireFenceFd, 1000);
|
|
if(ret < 0) {
|
|
ALOGE("%s: sync_wait error!! error no = %d err str = %s",
|
|
__FUNCTION__, errno, strerror(errno));
|
|
}
|
|
close(list->hwLayers[i].acquireFenceFd);
|
|
list->hwLayers[i].acquireFenceFd = -1;
|
|
}
|
|
retVal = drawLayerUsingCopybit(ctx, &(list->hwLayers[i]),
|
|
renderBuffer, !i);
|
|
copybitLayerCount++;
|
|
if(retVal < 0) {
|
|
ALOGE("%s : drawLayerUsingCopybit failed", __FUNCTION__);
|
|
}
|
|
}
|
|
|
|
if (copybitLayerCount) {
|
|
copybit_device_t *copybit = getCopyBitDevice();
|
|
// Async mode
|
|
copybit->flush_get_fence(copybit, fd);
|
|
if(ctx->mMDP.version == qdutils::MDP_V3_0_4 &&
|
|
list->hwLayers[last].acquireFenceFd >= 0) {
|
|
close(list->hwLayers[last].acquireFenceFd);
|
|
list->hwLayers[last].acquireFenceFd = -1;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int CopyBit::drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
|
|
int fd = -1;
|
|
PtorInfo* ptorInfo = &(ctx->mPtorInfo);
|
|
|
|
if (ctx->mMDP.version < qdutils::MDP_V4_0) {
|
|
ALOGE("%s: Invalid request", __FUNCTION__);
|
|
return fd;
|
|
}
|
|
|
|
private_handle_t *renderBuffer = getCurrentRenderBuffer();
|
|
|
|
if (!renderBuffer) {
|
|
ALOGE("%s: Render buffer layer handle is NULL", __FUNCTION__);
|
|
return fd;
|
|
}
|
|
|
|
int copybitLayerCount = 0;
|
|
for(int j = 0; j < ptorInfo->count; j++) {
|
|
int ovlapIndex = ptorInfo->layerIndex[j];
|
|
hwc_rect_t overlap = list->hwLayers[ovlapIndex].displayFrame;
|
|
|
|
// Draw overlapped content of layers on render buffer
|
|
for (int i = 0; i <= ovlapIndex; i++) {
|
|
hwc_layer_1_t *layer = &list->hwLayers[i];
|
|
if(!isValidRect(getIntersection(layer->displayFrame,
|
|
overlap))) {
|
|
continue;
|
|
}
|
|
if ((list->hwLayers[i].acquireFenceFd != -1)) {
|
|
// Wait for acquire fence on the App buffers.
|
|
if(sync_wait(list->hwLayers[i].acquireFenceFd, 1000) < 0) {
|
|
ALOGE("%s: sync_wait error!! error no = %d err str = %s",
|
|
__FUNCTION__, errno, strerror(errno));
|
|
}
|
|
close(list->hwLayers[i].acquireFenceFd);
|
|
list->hwLayers[i].acquireFenceFd = -1;
|
|
}
|
|
|
|
int retVal = drawRectUsingCopybit(ctx, layer, renderBuffer, overlap,
|
|
ptorInfo->displayFrame[j]);
|
|
copybitLayerCount++;
|
|
if(retVal < 0) {
|
|
ALOGE("%s: drawRectUsingCopybit failed", __FUNCTION__);
|
|
copybitLayerCount = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (copybitLayerCount) {
|
|
copybit_device_t *copybit = getCopyBitDevice();
|
|
copybit->flush_get_fence(copybit, &fd);
|
|
}
|
|
|
|
ALOGD_IF(DEBUG_COPYBIT, "%s: done! copybitLayerCount = %d", __FUNCTION__,
|
|
copybitLayerCount);
|
|
return fd;
|
|
}
|
|
|
|
int CopyBit::drawRectUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
|
|
private_handle_t *renderBuffer, hwc_rect_t overlap,
|
|
hwc_rect_t destRect)
|
|
{
|
|
hwc_context_t* ctx = (hwc_context_t*)(dev);
|
|
if (!ctx) {
|
|
ALOGE("%s: null context ", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
private_handle_t *hnd = (private_handle_t *)layer->handle;
|
|
if (!hnd) {
|
|
ALOGE("%s: invalid handle", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
private_handle_t *dstHandle = (private_handle_t *)renderBuffer;
|
|
if (!dstHandle) {
|
|
ALOGE("%s: RenderBuffer handle is NULL", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
// Set the Copybit Source
|
|
copybit_image_t src;
|
|
src.handle = (native_handle_t *)layer->handle;
|
|
src.w = hnd->width;
|
|
src.h = hnd->height;
|
|
src.base = (void *)hnd->base;
|
|
src.format = hnd->format;
|
|
src.horiz_padding = 0;
|
|
src.vert_padding = 0;
|
|
|
|
|
|
hwc_rect_t dispFrame = layer->displayFrame;
|
|
hwc_rect_t iRect = getIntersection(dispFrame, overlap);
|
|
hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
|
|
qhwc::calculate_crop_rects(crop, dispFrame, iRect,
|
|
layer->transform);
|
|
|
|
// Copybit source rect
|
|
copybit_rect_t srcRect = {crop.left, crop.top, crop.right,
|
|
crop.bottom};
|
|
|
|
// Copybit destination rect
|
|
copybit_rect_t dstRect = {destRect.left, destRect.top, destRect.right,
|
|
destRect.bottom};
|
|
|
|
// Copybit dst
|
|
copybit_image_t dst;
|
|
dst.handle = (native_handle_t *)dstHandle;
|
|
dst.w = ALIGN(dstHandle->width, 32);
|
|
dst.h = dstHandle->height;
|
|
dst.base = (void *)dstHandle->base;
|
|
dst.format = dstHandle->format;
|
|
|
|
copybit_device_t *copybit = mEngine;
|
|
|
|
// Copybit region is the destRect
|
|
hwc_rect_t regRect = {dstRect.l,dstRect.t, dstRect.r, dstRect.b};
|
|
hwc_region_t region;
|
|
region.numRects = 1;
|
|
region.rects = ®Rect;
|
|
region_iterator copybitRegion(region);
|
|
int acquireFd = layer->acquireFenceFd;
|
|
|
|
copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_WIDTH,
|
|
renderBuffer->width);
|
|
copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_HEIGHT,
|
|
renderBuffer->height);
|
|
copybit->set_parameter(copybit, COPYBIT_TRANSFORM, layer->transform);
|
|
copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, layer->planeAlpha);
|
|
copybit->set_parameter(copybit, COPYBIT_BLEND_MODE, layer->blending);
|
|
copybit->set_parameter(copybit, COPYBIT_DITHER,
|
|
(dst.format == HAL_PIXEL_FORMAT_RGB_565) ? COPYBIT_ENABLE :
|
|
COPYBIT_DISABLE);
|
|
copybit->set_sync(copybit, acquireFd);
|
|
int err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect,
|
|
©bitRegion);
|
|
|
|
if (err < 0)
|
|
ALOGE("%s: copybit stretch failed",__FUNCTION__);
|
|
|
|
return err;
|
|
}
|
|
|
|
int CopyBit::drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
|
|
private_handle_t *renderBuffer, bool isFG)
|
|
{
|
|
hwc_context_t* ctx = (hwc_context_t*)(dev);
|
|
int err = 0, acquireFd;
|
|
if(!ctx) {
|
|
ALOGE("%s: null context ", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
private_handle_t *hnd = (private_handle_t *)layer->handle;
|
|
if(!hnd) {
|
|
if (layer->flags & HWC_COLOR_FILL) { // Color layer
|
|
return fillColorUsingCopybit(layer, renderBuffer);
|
|
}
|
|
ALOGE("%s: invalid handle", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
private_handle_t *fbHandle = (private_handle_t *)renderBuffer;
|
|
if(!fbHandle) {
|
|
ALOGE("%s: Framebuffer handle is NULL", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
// Set the copybit source:
|
|
copybit_image_t src;
|
|
src.w = getWidth(hnd);
|
|
src.h = getHeight(hnd);
|
|
src.format = hnd->format;
|
|
|
|
// Handle R/B swap
|
|
if ((layer->flags & HWC_FORMAT_RB_SWAP)) {
|
|
if (src.format == HAL_PIXEL_FORMAT_RGBA_8888) {
|
|
src.format = HAL_PIXEL_FORMAT_BGRA_8888;
|
|
} else if (src.format == HAL_PIXEL_FORMAT_RGBX_8888) {
|
|
src.format = HAL_PIXEL_FORMAT_BGRX_8888;
|
|
}
|
|
}
|
|
|
|
src.base = (void *)hnd->base;
|
|
src.handle = (native_handle_t *)layer->handle;
|
|
src.horiz_padding = src.w - getWidth(hnd);
|
|
// Initialize vertical padding to zero for now,
|
|
// this needs to change to accomodate vertical stride
|
|
// if needed in the future
|
|
src.vert_padding = 0;
|
|
|
|
int layerTransform = layer->transform ;
|
|
// When flip and rotation(90) are present alter the flip,
|
|
// as GPU is doing the flip and rotation in opposite order
|
|
// to that of MDP3.0
|
|
// For 270 degrees, we get 90 + (H+V) which is same as doing
|
|
// flip first and then rotation (H+V) + 90
|
|
if (qdutils::MDPVersion::getInstance().getMDPVersion() < 400) {
|
|
if (((layer->transform& HAL_TRANSFORM_FLIP_H) ||
|
|
(layer->transform & HAL_TRANSFORM_FLIP_V)) &&
|
|
(layer->transform & HAL_TRANSFORM_ROT_90) &&
|
|
!(layer->transform == HAL_TRANSFORM_ROT_270)){
|
|
if(layer->transform & HAL_TRANSFORM_FLIP_H){
|
|
layerTransform ^= HAL_TRANSFORM_FLIP_H;
|
|
layerTransform |= HAL_TRANSFORM_FLIP_V;
|
|
}
|
|
if(layer->transform & HAL_TRANSFORM_FLIP_V){
|
|
layerTransform ^= HAL_TRANSFORM_FLIP_V;
|
|
layerTransform |= HAL_TRANSFORM_FLIP_H;
|
|
}
|
|
}
|
|
}
|
|
// Copybit source rect
|
|
hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
|
|
copybit_rect_t srcRect = {sourceCrop.left, sourceCrop.top,
|
|
sourceCrop.right,
|
|
sourceCrop.bottom};
|
|
|
|
// Copybit destination rect
|
|
hwc_rect_t displayFrame = layer->displayFrame;
|
|
copybit_rect_t dstRect = {displayFrame.left, displayFrame.top,
|
|
displayFrame.right,
|
|
displayFrame.bottom};
|
|
#ifdef QCOM_BSP
|
|
//change src and dst with dirtyRect
|
|
if(mDirtyLayerIndex != -1) {
|
|
srcRect.l = layer->dirtyRect.left;
|
|
srcRect.t = layer->dirtyRect.top;
|
|
srcRect.r = layer->dirtyRect.right;
|
|
srcRect.b = layer->dirtyRect.bottom;
|
|
dstRect = srcRect;
|
|
}
|
|
#endif
|
|
// Copybit dst
|
|
copybit_image_t dst;
|
|
dst.w = ALIGN(fbHandle->width,32);
|
|
dst.h = fbHandle->height;
|
|
dst.format = fbHandle->format;
|
|
dst.base = (void *)fbHandle->base;
|
|
dst.handle = (native_handle_t *)fbHandle;
|
|
|
|
copybit_device_t *copybit = mEngine;
|
|
|
|
int32_t screen_w = displayFrame.right - displayFrame.left;
|
|
int32_t screen_h = displayFrame.bottom - displayFrame.top;
|
|
int32_t src_crop_width = sourceCrop.right - sourceCrop.left;
|
|
int32_t src_crop_height = sourceCrop.bottom -sourceCrop.top;
|
|
|
|
// Copybit dst
|
|
float copybitsMaxScale =
|
|
(float)copybit->get(copybit,COPYBIT_MAGNIFICATION_LIMIT);
|
|
float copybitsMinScale =
|
|
(float)copybit->get(copybit,COPYBIT_MINIFICATION_LIMIT);
|
|
|
|
if (layer->transform & HWC_TRANSFORM_ROT_90) {
|
|
//swap screen width and height
|
|
int tmp = screen_w;
|
|
screen_w = screen_h;
|
|
screen_h = tmp;
|
|
}
|
|
private_handle_t *tmpHnd = NULL;
|
|
|
|
if(screen_w <=0 || screen_h<=0 ||src_crop_width<=0 || src_crop_height<=0 ) {
|
|
ALOGE("%s: wrong params for display screen_w=%d src_crop_width=%d \
|
|
screen_h=%d src_crop_height=%d", __FUNCTION__, screen_w,
|
|
src_crop_width,screen_h,src_crop_height);
|
|
return -1;
|
|
}
|
|
|
|
float dsdx = (float)screen_w/(float)src_crop_width;
|
|
float dtdy = (float)screen_h/(float)src_crop_height;
|
|
|
|
float scaleLimitMax = copybitsMaxScale * copybitsMaxScale;
|
|
float scaleLimitMin = copybitsMinScale * copybitsMinScale;
|
|
if(dsdx > scaleLimitMax ||
|
|
dtdy > scaleLimitMax ||
|
|
dsdx < 1/scaleLimitMin ||
|
|
dtdy < 1/scaleLimitMin) {
|
|
ALOGW("%s: greater than max supported size dsdx=%f dtdy=%f \
|
|
scaleLimitMax=%f scaleLimitMin=%f", __FUNCTION__,dsdx,dtdy,
|
|
scaleLimitMax,1/scaleLimitMin);
|
|
return -1;
|
|
}
|
|
acquireFd = layer->acquireFenceFd;
|
|
if(dsdx > copybitsMaxScale ||
|
|
dtdy > copybitsMaxScale ||
|
|
dsdx < 1/copybitsMinScale ||
|
|
dtdy < 1/copybitsMinScale){
|
|
// The requested scale is out of the range the hardware
|
|
// can support.
|
|
ALOGD("%s:%d::Need to scale twice dsdx=%f, dtdy=%f,copybitsMaxScale=%f,\
|
|
copybitsMinScale=%f,screen_w=%d,screen_h=%d \
|
|
src_crop_width=%d src_crop_height=%d",__FUNCTION__,__LINE__,
|
|
dsdx,dtdy,copybitsMaxScale,1/copybitsMinScale,screen_w,screen_h,
|
|
src_crop_width,src_crop_height);
|
|
|
|
|
|
int tmp_w = src_crop_width;
|
|
int tmp_h = src_crop_height;
|
|
|
|
if (dsdx > copybitsMaxScale || dtdy > copybitsMaxScale ){
|
|
tmp_w = (int)((float)src_crop_width*copybitsMaxScale);
|
|
tmp_h = (int)((float)src_crop_height*copybitsMaxScale);
|
|
}else if (dsdx < 1/copybitsMinScale ||dtdy < 1/copybitsMinScale ){
|
|
// ceil the tmp_w and tmp_h value to maintain proper ratio
|
|
// b/w src and dst (should not cross the desired scale limit
|
|
// due to float -> int )
|
|
tmp_w = (int)ceil((float)src_crop_width/copybitsMinScale);
|
|
tmp_h = (int)ceil((float)src_crop_height/copybitsMinScale);
|
|
}
|
|
ALOGD("%s:%d::tmp_w = %d,tmp_h = %d",__FUNCTION__,__LINE__,tmp_w,tmp_h);
|
|
|
|
int usage = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP;
|
|
int format = fbHandle->format;
|
|
|
|
// We do not want copybit to generate alpha values from nothing
|
|
if (format == HAL_PIXEL_FORMAT_RGBA_8888 &&
|
|
src.format != HAL_PIXEL_FORMAT_RGBA_8888) {
|
|
format = HAL_PIXEL_FORMAT_RGBX_8888;
|
|
}
|
|
if (0 == alloc_buffer(&tmpHnd, tmp_w, tmp_h, format, usage) && tmpHnd) {
|
|
copybit_image_t tmp_dst;
|
|
copybit_rect_t tmp_rect;
|
|
tmp_dst.w = tmp_w;
|
|
tmp_dst.h = tmp_h;
|
|
tmp_dst.format = tmpHnd->format;
|
|
tmp_dst.handle = tmpHnd;
|
|
tmp_dst.horiz_padding = src.horiz_padding;
|
|
tmp_dst.vert_padding = src.vert_padding;
|
|
tmp_rect.l = 0;
|
|
tmp_rect.t = 0;
|
|
tmp_rect.r = tmp_dst.w;
|
|
tmp_rect.b = tmp_dst.h;
|
|
//create one clip region
|
|
hwc_rect tmp_hwc_rect = {0,0,tmp_rect.r,tmp_rect.b};
|
|
hwc_region_t tmp_hwc_reg = {1,(hwc_rect_t const*)&tmp_hwc_rect};
|
|
region_iterator tmp_it(tmp_hwc_reg);
|
|
copybit->set_parameter(copybit,COPYBIT_TRANSFORM,0);
|
|
//TODO: once, we are able to read layer alpha, update this
|
|
copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
|
|
copybit->set_sync(copybit, acquireFd);
|
|
err = copybit->stretch(copybit,&tmp_dst, &src, &tmp_rect,
|
|
&srcRect, &tmp_it);
|
|
if(err < 0){
|
|
ALOGE("%s:%d::tmp copybit stretch failed",__FUNCTION__,
|
|
__LINE__);
|
|
if(tmpHnd)
|
|
free_buffer(tmpHnd);
|
|
return err;
|
|
}
|
|
// use release fence as aquire fd for next stretch
|
|
if (ctx->mMDP.version < qdutils::MDP_V4_0) {
|
|
copybit->flush_get_fence(copybit, &acquireFd);
|
|
close(acquireFd);
|
|
acquireFd = -1;
|
|
}
|
|
// copy new src and src rect crop
|
|
src = tmp_dst;
|
|
srcRect = tmp_rect;
|
|
}
|
|
}
|
|
// Copybit region
|
|
hwc_region_t region = layer->visibleRegionScreen;
|
|
region_iterator copybitRegion(region);
|
|
|
|
copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_WIDTH,
|
|
renderBuffer->width);
|
|
copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_HEIGHT,
|
|
renderBuffer->height);
|
|
copybit->set_parameter(copybit, COPYBIT_TRANSFORM,
|
|
layerTransform);
|
|
//TODO: once, we are able to read layer alpha, update this
|
|
copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
|
|
copybit->set_parameter(copybit, COPYBIT_BLEND_MODE,
|
|
layer->blending);
|
|
copybit->set_parameter(copybit, COPYBIT_DITHER,
|
|
(dst.format == HAL_PIXEL_FORMAT_RGB_565)?
|
|
COPYBIT_ENABLE : COPYBIT_DISABLE);
|
|
copybit->set_parameter(copybit, COPYBIT_FG_LAYER, isFG ?
|
|
COPYBIT_ENABLE : COPYBIT_DISABLE);
|
|
|
|
copybit->set_parameter(copybit, COPYBIT_BLIT_TO_FRAMEBUFFER,
|
|
COPYBIT_ENABLE);
|
|
copybit->set_sync(copybit, acquireFd);
|
|
err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect,
|
|
©bitRegion);
|
|
copybit->set_parameter(copybit, COPYBIT_BLIT_TO_FRAMEBUFFER,
|
|
COPYBIT_DISABLE);
|
|
|
|
if(tmpHnd) {
|
|
if (ctx->mMDP.version < qdutils::MDP_V4_0){
|
|
int ret = -1, releaseFd;
|
|
// we need to wait for the buffer before freeing
|
|
copybit->flush_get_fence(copybit, &releaseFd);
|
|
ret = sync_wait(releaseFd, 1000);
|
|
if(ret < 0) {
|
|
ALOGE("%s: sync_wait error!! error no = %d err str = %s",
|
|
__FUNCTION__, errno, strerror(errno));
|
|
}
|
|
close(releaseFd);
|
|
}
|
|
free_buffer(tmpHnd);
|
|
}
|
|
|
|
if(err < 0)
|
|
ALOGE("%s: copybit stretch failed",__FUNCTION__);
|
|
return err;
|
|
}
|
|
|
|
int CopyBit::fillColorUsingCopybit(hwc_layer_1_t *layer,
|
|
private_handle_t *renderBuffer)
|
|
{
|
|
if (!renderBuffer) {
|
|
ALOGE("%s: Render Buffer is NULL", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
// Copybit dst
|
|
copybit_image_t dst;
|
|
dst.w = ALIGN(renderBuffer->width, 32);
|
|
dst.h = renderBuffer->height;
|
|
dst.format = renderBuffer->format;
|
|
dst.base = (void *)renderBuffer->base;
|
|
dst.handle = (native_handle_t *)renderBuffer;
|
|
|
|
// Copybit dst rect
|
|
hwc_rect_t displayFrame = layer->displayFrame;
|
|
copybit_rect_t dstRect = {displayFrame.left, displayFrame.top,
|
|
displayFrame.right, displayFrame.bottom};
|
|
|
|
uint32_t color = layer->transform;
|
|
copybit_device_t *copybit = mEngine;
|
|
copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_WIDTH,
|
|
renderBuffer->width);
|
|
copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_HEIGHT,
|
|
renderBuffer->height);
|
|
copybit->set_parameter(copybit, COPYBIT_DITHER,
|
|
(dst.format == HAL_PIXEL_FORMAT_RGB_565) ?
|
|
COPYBIT_ENABLE : COPYBIT_DISABLE);
|
|
copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
|
|
copybit->set_parameter(copybit, COPYBIT_BLEND_MODE, layer->blending);
|
|
copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, layer->planeAlpha);
|
|
copybit->set_parameter(copybit, COPYBIT_BLIT_TO_FRAMEBUFFER,COPYBIT_ENABLE);
|
|
int res = copybit->fill_color(copybit, &dst, &dstRect, color);
|
|
copybit->set_parameter(copybit,COPYBIT_BLIT_TO_FRAMEBUFFER,COPYBIT_DISABLE);
|
|
return res;
|
|
}
|
|
|
|
void CopyBit::getLayerResolution(const hwc_layer_1_t* layer,
|
|
unsigned int& width, unsigned int& height)
|
|
{
|
|
hwc_rect_t displayFrame = layer->displayFrame;
|
|
|
|
width = displayFrame.right - displayFrame.left;
|
|
height = displayFrame.bottom - displayFrame.top;
|
|
}
|
|
|
|
bool CopyBit::validateParams(hwc_context_t *ctx,
|
|
const hwc_display_contents_1_t *list) {
|
|
//Validate parameters
|
|
if (!ctx) {
|
|
ALOGE("%s:Invalid HWC context", __FUNCTION__);
|
|
return false;
|
|
} else if (!list) {
|
|
ALOGE("%s:Invalid HWC layer list", __FUNCTION__);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
int CopyBit::allocRenderBuffers(int w, int h, int f)
|
|
{
|
|
int ret = 0;
|
|
for (int i = 0; i < NUM_RENDER_BUFFERS; i++) {
|
|
if (mRenderBuffer[i] == NULL) {
|
|
ret = alloc_buffer(&mRenderBuffer[i],
|
|
w, h, f,
|
|
GRALLOC_USAGE_PRIVATE_IOMMU_HEAP);
|
|
}
|
|
if(ret < 0) {
|
|
freeRenderBuffers();
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void CopyBit::freeRenderBuffers()
|
|
{
|
|
for (int i = 0; i < NUM_RENDER_BUFFERS; i++) {
|
|
if(mRenderBuffer[i]) {
|
|
//Since we are freeing buffer close the fence if it has a valid one.
|
|
if(mRelFd[i] >= 0) {
|
|
close(mRelFd[i]);
|
|
mRelFd[i] = -1;
|
|
}
|
|
free_buffer(mRenderBuffer[i]);
|
|
mRenderBuffer[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
private_handle_t * CopyBit::getCurrentRenderBuffer() {
|
|
return mRenderBuffer[mCurRenderBufferIndex];
|
|
}
|
|
|
|
void CopyBit::setReleaseFd(int fd) {
|
|
if(mRelFd[mCurRenderBufferIndex] >=0)
|
|
close(mRelFd[mCurRenderBufferIndex]);
|
|
mRelFd[mCurRenderBufferIndex] = dup(fd);
|
|
}
|
|
|
|
void CopyBit::setReleaseFdSync(int fd) {
|
|
if (mRelFd[mCurRenderBufferIndex] >=0) {
|
|
int ret = -1;
|
|
ret = sync_wait(mRelFd[mCurRenderBufferIndex], 1000);
|
|
if (ret < 0)
|
|
ALOGE("%s: sync_wait error! errno = %d, err str = %s",
|
|
__FUNCTION__, errno, strerror(errno));
|
|
close(mRelFd[mCurRenderBufferIndex]);
|
|
}
|
|
mRelFd[mCurRenderBufferIndex] = dup(fd);
|
|
}
|
|
|
|
struct copybit_device_t* CopyBit::getCopyBitDevice() {
|
|
return mEngine;
|
|
}
|
|
|
|
CopyBit::CopyBit(hwc_context_t *ctx, const int& dpy) : mEngine(0),
|
|
mIsModeOn(false), mCopyBitDraw(false), mCurRenderBufferIndex(0) {
|
|
|
|
getBufferSizeAndDimensions(ctx->dpyAttr[dpy].xres,
|
|
ctx->dpyAttr[dpy].yres,
|
|
HAL_PIXEL_FORMAT_RGBA_8888,
|
|
mAlignedWidth,
|
|
mAlignedHeight);
|
|
|
|
hw_module_t const *module;
|
|
for (int i = 0; i < NUM_RENDER_BUFFERS; i++) {
|
|
mRenderBuffer[i] = NULL;
|
|
mRelFd[i] = -1;
|
|
}
|
|
|
|
char value[PROPERTY_VALUE_MAX];
|
|
property_get("debug.hwc.dynThreshold", value, "2");
|
|
mDynThreshold = atof(value);
|
|
|
|
property_get("debug.sf.swaprect", value, "0");
|
|
mSwapRectEnable = atoi(value) ? true:false ;
|
|
mDirtyLayerIndex = -1;
|
|
if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
|
|
if(copybit_open(module, &mEngine) < 0) {
|
|
ALOGE("FATAL ERROR: copybit open failed.");
|
|
}
|
|
} else {
|
|
ALOGE("FATAL ERROR: copybit hw module not found");
|
|
}
|
|
}
|
|
|
|
CopyBit::~CopyBit()
|
|
{
|
|
freeRenderBuffers();
|
|
if(mEngine)
|
|
{
|
|
copybit_close(mEngine);
|
|
mEngine = NULL;
|
|
}
|
|
}
|
|
CopyBit::LayerCache::LayerCache() {
|
|
reset();
|
|
}
|
|
void CopyBit::LayerCache::reset() {
|
|
memset(&hnd, 0, sizeof(hnd));
|
|
layerCount = 0;
|
|
}
|
|
void CopyBit::LayerCache::updateCounts(hwc_context_t *ctx,
|
|
hwc_display_contents_1_t *list, int dpy)
|
|
{
|
|
layerCount = ctx->listStats[dpy].numAppLayers;
|
|
for (int i=0; i<ctx->listStats[dpy].numAppLayers; i++){
|
|
hnd[i] = list->hwLayers[i].handle;
|
|
}
|
|
}
|
|
|
|
CopyBit::FbCache::FbCache() {
|
|
reset();
|
|
}
|
|
void CopyBit::FbCache::reset() {
|
|
memset(&FbdirtyRect, 0, sizeof(FbdirtyRect));
|
|
FbIndex =0;
|
|
}
|
|
|
|
void CopyBit::FbCache::insertAndUpdateFbCache(hwc_rect_t dirtyRect) {
|
|
FbIndex = FbIndex % NUM_RENDER_BUFFERS;
|
|
FbdirtyRect[FbIndex] = dirtyRect;
|
|
FbIndex++;
|
|
}
|
|
|
|
int CopyBit::FbCache::getUnchangedFbDRCount(hwc_rect_t dirtyRect){
|
|
int sameDirtyCount = 0;
|
|
for (int i = 0 ; i < NUM_RENDER_BUFFERS ; i++ ){
|
|
if( FbdirtyRect[i] == dirtyRect)
|
|
sameDirtyCount++;
|
|
}
|
|
return sameDirtyCount;
|
|
}
|
|
|
|
}; //namespace qhwc
|