android13/hardware/rockchip/hwcomposer/drmhwc/hwc_rockchip.cpp

3850 lines
144 KiB
C++
Executable File

/*
* Copyright (C) 2018 Fuzhou Rockchip Electronics Co.Ltd.
*
* Modification based on code covered by the Apache License, Version 2.0 (the "License").
* You may not use this software except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS TO YOU ON AN "AS IS" BASIS
* AND ANY AND ALL WARRANTIES AND REPRESENTATIONS WITH RESPECT TO SUCH SOFTWARE, WHETHER EXPRESS,
* IMPLIED, STATUTORY OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF TITLE,
* NON-INFRINGEMENT, MERCHANTABILITY, SATISFACTROY QUALITY, ACCURACY OR FITNESS FOR A PARTICULAR
* PURPOSE 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) 2015 The Android Open Source Project
*
* 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 LOG_TAG "hwc_rk"
#include <inttypes.h>
#ifdef TARGET_BOARD_PLATFORM_RK3368
#include <hardware/img_gralloc_public.h>
#endif
#include "hwc_rockchip.h"
#include "hwc_util.h"
#if USE_GRALLOC_4
#include "src/mali_gralloc_formats.h"
#include "drmgralloc4.h"
#endif
namespace android {
int hwc_init_version()
{
char acVersion[50];
char acCommit[50];
memset(acVersion,0,sizeof(acVersion));
strcpy(acVersion,GHWC_VERSION);
#ifdef TARGET_BOARD_PLATFORM_RK3288
strcat(acVersion,"-rk3288");
#endif
#ifdef TARGET_BOARD_PLATFORM_RK3368
strcat(acVersion,"-rk3368");
#endif
#ifdef TARGET_BOARD_PLATFORM_RK3366
strcat(acVersion,"-rk3366");
#endif
#ifdef TARGET_BOARD_PLATFORM_RK3399
strcat(acVersion,"-rk3399");
#endif
#ifdef TARGET_BOARD_PLATFORM_RK3326
strcat(acVersion,"-rk3326");
#endif
#ifdef TARGET_BOARD_PLATFORM_RK3126C
strcat(acVersion,"-rk3126c");
#endif
#ifdef TARGET_BOARD_PLATFORM_RK3328
strcat(acVersion,"-rk3328");
#endif
#ifdef RK_MID
strcat(acVersion,"-MID");
#endif
#ifdef RK_BOX
strcat(acVersion,"-BOX");
#endif
#ifdef RK_PHONE
strcat(acVersion,"-PHONE");
#endif
#ifdef RK_VIR
strcat(acVersion,"-VR");
#endif
/* RK_GRAPHICS_VER=commit-id:067e5d0: only keep string after '=' */
sscanf(RK_GRAPHICS_VER, "%*[^=]=%s", acCommit);
property_set( PROPERTY_TYPE ".ghwc.version", acVersion);
property_set( PROPERTY_TYPE ".ghwc.commit", acCommit);
ALOGD(RK_GRAPHICS_VER);
return 0;
}
int g_drm_version = 0;
void gSetDrmVersion(int drm_version){
g_drm_version = drm_version;
}
bool gIsDrmVerison510(){
return g_drm_version == 3;
}
bool gIsDrmVerison419(){
return g_drm_version == 2;
}
#if USE_AFBC_LAYER
#ifdef TARGET_BOARD_PLATFORM_RK3368
int HALPixelFormatGetCompression(int iFormat)
{
/* Extension format. Return only the compression bits. */
if (iFormat >= 0x100 && iFormat <= 0x1FF)
return (iFormat & 0x70) >> 4;
/* Upstream formats are not compressible unless they are redefined as
* extension formats (e.g. RGB_565, BGRA_8888).
*/
return HAL_FB_COMPRESSION_NONE;
}
#endif
bool isAfbcInternalFormat(uint64_t internal_format)
{
#ifdef TARGET_BOARD_PLATFORM_RK3368
return (HALPixelFormatGetCompression(internal_format)==HAL_FB_COMPRESSION_NONE)?false:true;
#elif defined(TARGET_BOARD_PLATFORM_RK3399)
return (internal_format & GRALLOC_ARM_INTFMT_AFBC); // for Midgard gralloc r14
#elif defined(TARGET_BOARD_PLATFORM_RK3326)
ALOGD_IF(log_level(DBG_VERBOSE),"internal_format : %" PRIx64 ", MALI_GRALLOC_INTFMT_AFBC_BASIC : %llx", internal_format, MALI_GRALLOC_INTFMT_AFBC_BASIC);
return (internal_format & MALI_GRALLOC_INTFMT_AFBC_BASIC); // for Bifrost gralloc r8
#else
UN_USED(internal_format);
return false;
#endif
}
#endif
#if RK_INVALID_REFRESH
int init_thread_pamaters(threadPamaters* mThreadPamaters)
{
if(mThreadPamaters) {
mThreadPamaters->count = 0;
pthread_mutex_init(&mThreadPamaters->mtx, NULL);
pthread_mutex_init(&mThreadPamaters->mlk, NULL);
pthread_cond_init(&mThreadPamaters->cond, NULL);
} else {
ALOGE("{%s}%d,mThreadPamaters is NULL",__FUNCTION__,__LINE__);
}
return 0;
}
int free_thread_pamaters(threadPamaters* mThreadPamaters)
{
if(mThreadPamaters) {
pthread_mutex_destroy(&mThreadPamaters->mtx);
pthread_mutex_destroy(&mThreadPamaters->mlk);
pthread_cond_destroy(&mThreadPamaters->cond);
} else {
ALOGE("{%s}%d,mThreadPamaters is NULL",__FUNCTION__,__LINE__);
}
return 0;
}
void TimeInt2Obj(int imSecond, timeval *ptVal)
{
ptVal->tv_sec=imSecond/1000;
ptVal->tv_usec=(imSecond%1000)*1000;
}
int hwc_static_screen_opt_set(bool isGLESComp)
{
struct itimerval tv = {{0,0},{0,0}};
if (!isGLESComp) {
int interval_value = hwc_get_int_property( PROPERTY_TYPE ".vwb.time", "2500");
interval_value = interval_value > 5000? 5000:interval_value;
interval_value = interval_value < 250? 250:interval_value;
TimeInt2Obj(interval_value,&tv.it_value);
ALOGD_IF(log_level(DBG_VERBOSE),"reset timer!");
} else {
tv.it_value.tv_usec = 0;
ALOGD_IF(log_level(DBG_VERBOSE),"close timer!");
}
setitimer(ITIMER_REAL, &tv, NULL);
return 0;
}
#endif
#if RK_3D_VIDEO
#ifdef USE_HWC2
int detect_3d_mode(hwc_drm_display_t *hd, hwc_display_contents_1_t *display_content, int display)
{
bool is_3d = false;
int force3d = 0;
unsigned int numlayer = display_content->numHwLayers;
int needStereo = 0;
for (unsigned int j = 0; j <(numlayer - 1); j++) {
if(display_content->hwLayers[j].handle)
{
needStereo = hwc_get_handle_alreadyStereo(hd->gralloc, display_content->hwLayers[j].handle);
if(needStereo > 0)
{
break;
}
}
}
if(!needStereo)
{
force3d = hwc_get_int_property( PROPERTY_TYPE ".hwc.force3d.primary","0");
if(1==force3d || 2==force3d){
if(display == 0 || display == 1)
needStereo = force3d;
}
}
if(needStereo)
{
is_3d = true;
if(needStereo == 1)
hd->stereo_mode = H_3D;
else if (needStereo == 2)
hd->stereo_mode = V_3D;
else if (needStereo == 8)
hd->stereo_mode = FPS_3D;
else
ALOGD_IF(log_level(DBG_VERBOSE),"It is unknow 3d mode needStereo=%d",needStereo);
}
for (unsigned int j = 0; j <(numlayer - 1); j++) {
if(display_content->hwLayers[j].handle)
{
int ret = hwc_set_handle_displayStereo(hd->gralloc, display_content->hwLayers[j].handle, needStereo);
if(ret < 0)
{
ALOGE("%s:hwc_set_handle_displayStereo fail", __FUNCTION__);
break;
}
}
}
if (needStereo & 0x8000) {
for (unsigned int j = 0; j <(numlayer - 1); j++) {
if(display_content->hwLayers[j].handle)
{
int ret = hwc_set_handle_displayStereo(hd->gralloc, display_content->hwLayers[j].handle, needStereo & (~0x8000));
if(ret < 0)
{
ALOGE("%s:hwc_set_handle_displayStereo fail", __FUNCTION__);
break;
}
ret = hwc_set_handle_alreadyStereo(hd->gralloc, display_content->hwLayers[j].handle, 0);
if(ret < 0)
{
ALOGE("%s:hwc_set_handle_alreadyStereo fail", __FUNCTION__);
break;
}
}
}
}
return is_3d;
}
#else
int detect_3d_mode(hwc_drm_display_t *hd, hwc_display_contents_1_t *display_content, int display)
{
bool is_3d = false;
int force3d = 0;
unsigned int numlayer = display_content->numHwLayers;
int needStereo = 0;
for (unsigned int j = 0; j <(numlayer - 1); j++) {
if(display_content->hwLayers[j].alreadyStereo) {
needStereo = display_content->hwLayers[j].alreadyStereo;
break;
}
}
if(!needStereo)
{
force3d = hwc_get_int_property( PROPERTY_TYPE ".hwc.force3d.primary","0");
if(1==force3d || 2==force3d){
if(display == 0 || display == 1)
needStereo = force3d;
}
}
if(needStereo)
{
is_3d = true;
if(needStereo == 1)
hd->stereo_mode = H_3D;
else if (needStereo == 2)
hd->stereo_mode = V_3D;
else if (needStereo == 8)
hd->stereo_mode = FPS_3D;
else
ALOGD_IF(log_level(DBG_VERBOSE),"It is unknow 3d mode needStereo=%d",needStereo);
}
for (unsigned int j = 0; j <(numlayer - 1); j++) {
display_content->hwLayers[j].displayStereo = needStereo;
}
if (needStereo & 0x8000) {
for (unsigned int j = 0; j <(numlayer - 1); j++) {
display_content->hwLayers[j].alreadyStereo = 0;
display_content->hwLayers[j].displayStereo = (needStereo & (~0x8000));
}
}
#if 0
if(1==display && numlayer > 1) {
ALOGD_IF(log_level(DBG_VERBOSE),"Wake up hwc control stereo");
pthread_mutex_lock(&mControlStereo->mlk);
ctx->mControlStereo.count = needStereo;
pthread_mutex_unlock(&mControlStereo->mlk);
pthread_cond_signal(&mControlStereo->cond);
}
#endif
return is_3d;
}
#endif
#endif
#if 0
int map_3d_mode(int value, int flag)
{
if(flag == READ_3D_MODE)
{
switch (value)
{
case 0:
return 8;
case 6:
return 2;
case 8:
return 1;
default:
return 0;
}
}
else if(flag == WRITE_3D_MODE)
{
switch (value)
{
case 1:
return 8;
case 2:
return 6;
case 8:
return 0;
default:
return -1;
}
}
else
{
ALOGE("%s:line=%d invalid flag =%d", __FUNCTION__, __LINE__, flag);
return -1;
}
}
/*
* get or set 3d mode.
* flag : 0--read 1--write
*/
int hwc_control_3dmode(int fd_3d, int value, int flag)
{
int ret = 0;
int iMode;
ssize_t err;
char buf[200];
if(fd_3d < 0)
return -1;
switch(flag){
case READ_3D_MODE: //read
memset(buf,0,sizeof(buf));
lseek(fd,0,SEEK_SET);
err = read(fd, buf, sizeof(buf));
if(err <= 0)
ALOGW("read hdmi 3dmode err=%zd",err);
int mode,hdmi3dmode;
sscanf(buf,"3dmodes=%d cur3dmode=%d",&mode,&hdmi3dmode);
ALOGI_IF(log_level(DBG_VERBOSE),"hdmi3dmode=%d,mode=%d",hdmi3dmode,mode);
ret = map_3d_mode(value, READ_3D_MODE);
break;
case WRITE_3D_MODE: //write
lseek(fd,0,SEEK_SET);
iMode = map_3d_mode(value, WRITE_3D_MODE);
char acMode[25];
if(iMode != -1)
{
sprintf(acMode,"%d",iMode);
ret = write(fd, acMode, 2);
if(ret < 0)
{
ALOGE("change 3dmode to %d err is %s",value,strerror(errno));
}
}
else
{
ALOGE("%s:line=%d invalid write mode", __FUNCTION__, __LINE__);
}
break;
default:
break;
}
return ret;
}
#endif
#ifdef USE_HWC2
int hwc_get_handle_displayStereo(const gralloc_module_t *gralloc, buffer_handle_t hnd)
{
#if USE_GRALLOC_4
// dummy
return 0;
#else // USE_GRALLOC_4
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_RK_ASHMEM;
struct rk_ashmem_t rk_ashmem;
memset(&rk_ashmem,0x00,sizeof(struct rk_ashmem_t));
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &rk_ashmem);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
}
return rk_ashmem.displayStereo;
#endif // USE_GRALLOC_4
}
int hwc_set_handle_displayStereo(const gralloc_module_t *gralloc, buffer_handle_t hnd, int32_t displayStereo)
{
#if USE_GRALLOC_4
// dummy
return 0;
#else // USE_GRALLOC_4
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_RK_ASHMEM;
struct rk_ashmem_t rk_ashmem;
memset(&rk_ashmem,0x00,sizeof(struct rk_ashmem_t));
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &rk_ashmem);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
goto exit;
}
if(displayStereo != rk_ashmem.displayStereo)
{
op = GRALLOC_MODULE_PERFORM_SET_RK_ASHMEM;
rk_ashmem.displayStereo = displayStereo;
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &rk_ashmem);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
}
}
exit:
return ret;
#endif // USE_GRALLOC_4
}
int hwc_get_handle_alreadyStereo(const gralloc_module_t *gralloc, buffer_handle_t hnd)
{
#if USE_GRALLOC_4
// dummy
return 0;
#else // USE_GRALLOC_4
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_RK_ASHMEM;
struct rk_ashmem_t rk_ashmem;
memset(&rk_ashmem,0x00,sizeof(struct rk_ashmem_t));
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &rk_ashmem);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
}
return rk_ashmem.alreadyStereo;
#endif // USE_GRALLOC_4
}
int hwc_set_handle_alreadyStereo(const gralloc_module_t *gralloc, buffer_handle_t hnd, int32_t alreadyStereo)
{
#if USE_GRALLOC_4
// dummy
return 0;
#else // USE_GRALLOC_4
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_RK_ASHMEM;
struct rk_ashmem_t rk_ashmem;
memset(&rk_ashmem,0x00,sizeof(struct rk_ashmem_t));
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &rk_ashmem);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
goto exit;
}
if(alreadyStereo != rk_ashmem.alreadyStereo )
{
op = GRALLOC_MODULE_PERFORM_SET_RK_ASHMEM;
rk_ashmem.alreadyStereo = alreadyStereo;
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &rk_ashmem);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
}
}
exit:
return ret;
#endif // USE_GRALLOC_4
}
int hwc_get_handle_layername(const gralloc_module_t *gralloc, buffer_handle_t hnd, char* layername, unsigned long len)
{
#if USE_GRALLOC_4
std::string name;
int err = gralloc4::get_name(hnd, name);
if (err != android::OK)
{
ALOGE("Failed to get buffer format_requested, err : %d", err);
return -1;
}
int str_size = strlen(name.c_str())+1;
str_size = str_size > len ? len:str_size;
strncpy(layername, name.c_str(),str_size);
return 0;
#else // USE_GRALLOC_4
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_RK_ASHMEM;
struct rk_ashmem_t rk_ashmem;
unsigned long str_size;
if(!layername)
return -EINVAL;
memset(&rk_ashmem,0x00,sizeof(struct rk_ashmem_t));
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &rk_ashmem);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
goto exit;
}
str_size = strlen(rk_ashmem.LayerName)+1;
str_size = str_size > len ? len:str_size;
memcpy(layername,rk_ashmem.LayerName,str_size);
exit:
return ret;
#endif // USE_GRALLOC_4
}
int hwc_set_handle_layername(const gralloc_module_t *gralloc, buffer_handle_t hnd, const char* layername)
{
#if USE_GRALLOC_4
// dummy
return 0;
#else // USE_GRALLOC_4
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_RK_ASHMEM;
struct rk_ashmem_t rk_ashmem;
unsigned long str_size;
if(!layername)
return -EINVAL;
memset(&rk_ashmem,0x00,sizeof(struct rk_ashmem_t));
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &rk_ashmem);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
goto exit;
}
op = GRALLOC_MODULE_PERFORM_SET_RK_ASHMEM;
str_size = strlen(layername)+1;
str_size = str_size > sizeof(rk_ashmem.LayerName) ? sizeof(rk_ashmem.LayerName):str_size;
memcpy(rk_ashmem.LayerName,layername,str_size);
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &rk_ashmem);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
}
exit:
return ret;
#endif // USE_GRALLOC_4
}
#endif
int hwc_get_handle_width(const gralloc_module_t *gralloc, buffer_handle_t hnd)
{
#if USE_GRALLOC_4
uint64_t width;
int err = gralloc4::get_width(hnd, &width);
if (err != android::OK)
{
ALOGE("Failed to get buffer width, err : %d", err);
return -1;
}
return (int)width;
#else // USE_GRALLOC_4
#if RK_PER_MODE
struct gralloc_drm_handle_t* drm_hnd = (struct gralloc_drm_handle_t *)hnd;
UN_USED(gralloc);
return drm_hnd->width;
#else
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_HADNLE_WIDTH;
int width = -1;
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &width);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
}
return width;
#endif
#endif // USE_GRALLOC_4
}
int hwc_get_handle_height(const gralloc_module_t *gralloc, buffer_handle_t hnd)
{
#if USE_GRALLOC_4
uint64_t height;
int err = gralloc4::get_height(hnd, &height);
if (err != android::OK)
{
ALOGE("Failed to get buffer height, err : %d", err);
return -1;
}
return (int)height;
#else // USE_GRALLOC_4
#if RK_PER_MODE
struct gralloc_drm_handle_t* drm_hnd = (struct gralloc_drm_handle_t *)hnd;
UN_USED(gralloc);
return drm_hnd->height;
#else
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_HADNLE_HEIGHT;
int height = -1;
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &height);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
}
return height;
#endif
#endif // USE_GRALLOC_4
}
int hwc_get_handle_stride(const gralloc_module_t *gralloc, buffer_handle_t hnd)
{
#if USE_GRALLOC_4
int pixel_stride;
int err = gralloc4::get_pixel_stride(hnd, &pixel_stride);
if (err != android::OK)
{
ALOGE("Failed to get buffer pixel_stride, err : %d", err);
return -1;
}
return pixel_stride;
#else // USE_GRALLOC_4
#if RK_PER_MODE
struct gralloc_drm_handle_t* drm_hnd = (struct gralloc_drm_handle_t *)hnd;
UN_USED(gralloc);
return drm_hnd->pixel_stride;
#else
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_HADNLE_STRIDE;
int stride = -1;
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &stride);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
}
return stride;
#endif
#endif // USE_GRALLOC_4
}
int hwc_get_handle_byte_stride(const gralloc_module_t *gralloc, buffer_handle_t hnd)
{
#if USE_GRALLOC_4
int byte_stride;
int err = gralloc4::get_byte_stride(hnd, &byte_stride);
if (err != android::OK)
{
ALOGE("Failed to get buffer byte_stride, err : %d", err);
return -1;
}
return byte_stride;
#else // USE_GRALLOC_4
#if RK_PER_MODE
struct gralloc_drm_handle_t* drm_hnd = (struct gralloc_drm_handle_t *)hnd;
UN_USED(gralloc);
return drm_hnd->stride;
#else
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_HADNLE_BYTE_STRIDE;
int byte_stride = -1;
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &byte_stride);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
}
return byte_stride;
#endif
#endif // USE_GRALLOC_4
}
int hwc_get_handle_format(const gralloc_module_t *gralloc, buffer_handle_t hnd)
{
#if USE_GRALLOC_4
int format_requested;
int err = gralloc4::get_format_requested(hnd, &format_requested);
if (err != android::OK)
{
ALOGE("Failed to get buffer format_requested, err : %d", err);
return -1;
}
return format_requested;
#else // USE_GRALLOC_4
#if RK_PER_MODE
struct gralloc_drm_handle_t* drm_hnd = (struct gralloc_drm_handle_t *)hnd;
UN_USED(gralloc);
return drm_hnd->format;
#else
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_HADNLE_FORMAT;
int format = -1;
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &format);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
}
return format;
#endif
#endif // USE_GRALLOC_4
}
int hwc_get_handle_usage(const gralloc_module_t *gralloc, buffer_handle_t hnd)
{
#if USE_GRALLOC_4
uint64_t usage;
int err = gralloc4::get_usage(hnd, &usage);
if (err != android::OK)
{
ALOGE("Failed to get buffer usage, err : %d", err);
return -1;
}
return (int)usage;
#else // USE_GRALLOC_4
#if RK_PER_MODE
struct gralloc_drm_handle_t* drm_hnd = (struct gralloc_drm_handle_t *)hnd;
UN_USED(gralloc);
return drm_hnd->usage;
#else
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_USAGE;
int usage = -1;
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &usage);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
}
return usage;
#endif
#endif // USE_GRALLOC_4
}
int hwc_get_handle_size(const gralloc_module_t *gralloc, buffer_handle_t hnd)
{
#if USE_GRALLOC_4
uint64_t allocation_size;
int err = gralloc4::get_allocation_size(hnd, &allocation_size);
if (err != android::OK)
{
ALOGE("Failed to get buffer allocation_size, err : %d", err);
return -1;
}
return (int)allocation_size;
#else // USE_GRALLOC_4
#if RK_PER_MODE
struct gralloc_drm_handle_t* drm_hnd = (struct gralloc_drm_handle_t *)hnd;
UN_USED(gralloc);
return drm_hnd->size;
#else
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_HADNLE_SIZE;
int size = -1;
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &size);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
}
return size;
#endif
#endif // USE_GRALLOC_4
}
/*
@func hwc_get_handle_attributes:get attributes from handle.Before call this api,As far as now,
we need register the buffer first.May be the register is good for processer I think
@param hnd:
@param attrs: if size of attrs is small than 5,it will return EINVAL else
width = attrs[0]
height = attrs[1]
stride = attrs[2]
format = attrs[3]
size = attrs[4]
*/
int hwc_get_handle_attributes(const gralloc_module_t *gralloc, buffer_handle_t hnd, std::vector<int> *attrs)
{
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_HADNLE_ATTRIBUTES;
if (!hnd)
return -EINVAL;
if(gralloc && gralloc->perform)
{
ret = gralloc->perform(gralloc, op, hnd, attrs);
}
else
{
ret = -EINVAL;
}
if(ret) {
ALOGE("hwc_get_handle_attributes fail %d for:%s hnd=%p",ret,strerror(ret),hnd);
}
return ret;
}
int hwc_get_handle_attibute(const gralloc_module_t *gralloc, buffer_handle_t hnd, attribute_flag_t flag)
{
#if USE_GRALLOC_4
switch ( flag )
{
case ATT_WIDTH:
return hwc_get_handle_width(gralloc, hnd);
case ATT_HEIGHT:
return hwc_get_handle_height(gralloc, hnd);
case ATT_STRIDE:
return hwc_get_handle_stride(gralloc, hnd);
case ATT_FORMAT:
return hwc_get_handle_format(gralloc, hnd);
case ATT_SIZE:
return hwc_get_handle_size(gralloc, hnd);
case ATT_BYTE_STRIDE:
return hwc_get_handle_byte_stride(gralloc, hnd);
default:
LOG_ALWAYS_FATAL("unexpected flag : %d", flag);
return -1;
}
#else // USE_GRALLOC_4
std::vector<int> attrs;
int ret=0;
if(!hnd)
{
ALOGE("%s handle is null",__FUNCTION__);
return -1;
}
ret = hwc_get_handle_attributes(gralloc, hnd, &attrs);
if(ret < 0)
{
ALOGE("getHandleAttributes fail %d for:%s",ret,strerror(ret));
return ret;
}
else
{
return attrs.at(flag);
}
#endif // USE_GRALLOC_4
}
/*
@func getHandlePrimeFd:get prime_fd from handle.Before call this api,As far as now, we
need register the buffer first.May be the register is good for processer I think
@param hnd:
@return fd: prime_fd. and driver can call the dma_buf_get to get the buffer
*/
int hwc_get_handle_primefd(const gralloc_module_t *gralloc, buffer_handle_t hnd)
{
#if USE_GRALLOC_4
int share_fd;
int err = gralloc4::get_share_fd(hnd, &share_fd);
if (err != android::OK)
{
ALOGE("Failed to get buffer share_fd, err : %d", err);
return -1;
}
return (int)share_fd;
#else // USE_GRALLOC_4
#if RK_PER_MODE
struct gralloc_drm_handle_t* drm_hnd = (struct gralloc_drm_handle_t *)hnd;
UN_USED(gralloc);
return drm_hnd->prime_fd;
#else
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_HADNLE_PRIME_FD;
int fd = -1;
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &fd);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
}
return fd;
#endif
#endif // USE_GRALLOC_4
}
#if RK_DRM_GRALLOC
uint32_t hwc_get_handle_phy_addr(const gralloc_module_t *gralloc, buffer_handle_t hnd)
{
#if RK_PER_MODE
struct gralloc_drm_handle_t* drm_hnd = (struct gralloc_drm_handle_t *)hnd;
UN_USED(gralloc);
return drm_hnd->phy_addr;
#else
int ret = 0;
int op = GRALLOC_MODULE_PERFORM_GET_HADNLE_PHY_ADDR;
uint32_t phy_addr = 0;
if(gralloc && gralloc->perform)
ret = gralloc->perform(gralloc, op, hnd, &phy_addr);
else
ret = -EINVAL;
if(ret != 0)
{
ALOGE("%s:cann't get value from gralloc", __FUNCTION__);
}
return phy_addr;
#endif
}
#endif
uint32_t hwc_get_layer_colorspace(hwc_layer_1_t *layer)
{
uint32_t colorspace = (layer->reserved[0]) | (layer->reserved[1] << 8) |
(layer->reserved[2] << 16) | (layer->reserved[3] << 24);
ALOGD_IF(log_level(DBG_VERBOSE),"%s: reserved[0]=0x%x,reserved[1]=0x%x,reserved[2]=0x%x,reserved[3]=0x%x colorspace=0x%x",__FUNCTION__,
layer->reserved[0],layer->reserved[1],
layer->reserved[2],layer->reserved[3],colorspace);
return colorspace;
}
/*
ColorSpace: Linux standard definitions: Android standard definitions:
SRGB full range V4L2_COLORSPACE_SRGB HAL_DATASPACE_TRANSFER_SRGB
Bt601 full range V4L2_COLORSPACE_JPEG HAL_DATASPACE_V0_JFIF
Bt601 limit range V4L2_COLORSPACE_SMPTE170M HAL_DATASPACE_V0_BT601_525/HAL_DATASPACE_V0_BT601_625
Bt709 limit range V4L2_COLORSPACE_REC709 HAL_DATASPACE_V0_BT709
Bt2020 limit range V4L2_COLORSPACE_BT2020 HAL_DATASPACE_STANDARD_BT2020
*/
#define CONTAIN_VALUE(value,mask) ((colorspace & mask) == value)
uint32_t colorspace_convert_to_linux(uint32_t colorspace)
{
if (CONTAIN_VALUE(HAL_DATASPACE_STANDARD_BT2020, HAL_DATASPACE_STANDARD_MASK))
{
return V4L2_COLORSPACE_BT2020;
}
else if (CONTAIN_VALUE(HAL_DATASPACE_STANDARD_BT601_625, HAL_DATASPACE_STANDARD_MASK) &&
CONTAIN_VALUE(HAL_DATASPACE_TRANSFER_SMPTE_170M, HAL_DATASPACE_TRANSFER_MASK))
{
if (CONTAIN_VALUE(HAL_DATASPACE_RANGE_FULL, HAL_DATASPACE_RANGE_MASK))
return V4L2_COLORSPACE_JPEG;
else if (CONTAIN_VALUE(HAL_DATASPACE_RANGE_LIMITED, HAL_DATASPACE_RANGE_MASK))
return V4L2_COLORSPACE_SMPTE170M;
}
else if (CONTAIN_VALUE(HAL_DATASPACE_STANDARD_BT601_525, HAL_DATASPACE_STANDARD_MASK) &&
CONTAIN_VALUE(HAL_DATASPACE_TRANSFER_SMPTE_170M, HAL_DATASPACE_TRANSFER_MASK) &&
CONTAIN_VALUE(HAL_DATASPACE_RANGE_LIMITED, HAL_DATASPACE_RANGE_MASK))
{
return V4L2_COLORSPACE_SMPTE170M;
}
else if (CONTAIN_VALUE(HAL_DATASPACE_STANDARD_BT709, HAL_DATASPACE_STANDARD_MASK) &&
CONTAIN_VALUE(HAL_DATASPACE_TRANSFER_SMPTE_170M, HAL_DATASPACE_TRANSFER_MASK) &&
CONTAIN_VALUE(HAL_DATASPACE_RANGE_LIMITED, HAL_DATASPACE_RANGE_MASK))
{
return V4L2_COLORSPACE_REC709;
}
else if (CONTAIN_VALUE(HAL_DATASPACE_TRANSFER_SRGB, HAL_DATASPACE_TRANSFER_MASK))
{
return V4L2_COLORSPACE_SRGB;
}
//ALOGE("Unknow colorspace 0x%x",colorspace);
return 0;
}
bool vop_support_format(uint32_t hal_format) {
switch (hal_format) {
case HAL_PIXEL_FORMAT_RGB_888:
case HAL_PIXEL_FORMAT_BGRA_8888:
case HAL_PIXEL_FORMAT_RGBX_8888:
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGB_565:
case HAL_PIXEL_FORMAT_YCrCb_NV12:
case HAL_PIXEL_FORMAT_YCrCb_NV12_10:
case FBDC_BGRA_8888:
case FBDC_RGBA_8888:
return true;
default:
return false;
}
}
bool vop_support_scale(hwc_layer_1_t *layer,hwc_drm_display_t *hd) {
float hfactor;
float vfactor;
DrmHwcRect<float> source_crop;
DrmHwcRect<int> display_frame;
source_crop = DrmHwcRect<float>(
layer->sourceCropf.left, layer->sourceCropf.top,
layer->sourceCropf.right, layer->sourceCropf.bottom);
display_frame = DrmHwcRect<int>(
hd->w_scale * layer->displayFrame.left, hd->h_scale * layer->displayFrame.top,
hd->w_scale * layer->displayFrame.right, hd->h_scale * layer->displayFrame.bottom);
if((layer->transform == HWC_TRANSFORM_ROT_90)
||(layer->transform == HWC_TRANSFORM_ROT_270)){
hfactor = (float) (source_crop.bottom - source_crop.top)
/ (display_frame.right - display_frame.left);
vfactor = (float) (source_crop.right - source_crop.left)
/ (display_frame.bottom - display_frame.top);
} else {
hfactor = (float) (source_crop.right - source_crop.left)
/ (display_frame.right - display_frame.left);
vfactor = (float) (source_crop.bottom - source_crop.top)
/ (display_frame.bottom - display_frame.top);
}
if(hfactor >= 8.0 || vfactor >= 8.0 || hfactor <= 0.125 || vfactor <= 0.125 ){
ALOGD_IF(log_level(DBG_DEBUG), "scale [%f,%f]not support! at line=%d", hfactor, vfactor, __LINE__);
return false;
}
return true;
}
static bool is_rec1_intersect_rec2(DrmHwcRect<int>* rec1,DrmHwcRect<int>* rec2)
{
int iMaxLeft,iMaxTop,iMinRight,iMinBottom;
ALOGD_IF(log_level(DBG_DEBUG),"is_not_intersect: rec1[%d,%d,%d,%d],rec2[%d,%d,%d,%d]",rec1->left,rec1->top,
rec1->right,rec1->bottom,rec2->left,rec2->top,rec2->right,rec2->bottom);
iMaxLeft = rec1->left > rec2->left ? rec1->left: rec2->left;
iMaxTop = rec1->top > rec2->top ? rec1->top: rec2->top;
iMinRight = rec1->right <= rec2->right ? rec1->right: rec2->right;
iMinBottom = rec1->bottom <= rec2->bottom ? rec1->bottom: rec2->bottom;
if(iMaxLeft > iMinRight || iMaxTop > iMinBottom)
return false;
else
return true;
return false;
}
int is_x_intersect(DrmHwcRect<int>* rec,DrmHwcRect<int>* rec2)
{
if(rec2->top == rec->top)
return 1;
else if(rec2->top < rec->top)
{
if(rec2->bottom > rec->top)
return 1;
else
return 0;
}
else
{
if(rec->bottom > rec2->top )
return 1;
else
return 0;
}
return 0;
}
static bool is_layer_combine(DrmHwcLayer * layer_one,DrmHwcLayer * layer_two)
{
#if USE_MULTI_AREAS==0
ALOGD_IF(log_level(DBG_SILENT),"USE_MULTI_AREAS disable, can't support multi region");
return false;
#endif
#ifdef TARGET_BOARD_PLATFORM_RK3328
ALOGD_IF(log_level(DBG_SILENT),"rk3328 can't support multi region");
return false;
#endif
//multi region only support RGBA888 RGBX8888 RGB888 565 BGRA888
if(layer_one->format >= HAL_PIXEL_FORMAT_YCrCb_NV12
|| layer_two->format >= HAL_PIXEL_FORMAT_YCrCb_NV12
//RK3288 Rk3326 multi region format must be the same
#if RK_MULTI_AREAS_FORMAT_LIMIT
|| (layer_one->format != layer_two->format)
#endif
|| layer_one->alpha!= layer_two->alpha
|| layer_one->is_scale || layer_two->is_scale
|| is_rec1_intersect_rec2(&layer_one->display_frame,&layer_two->display_frame)
#if RK_HOR_INTERSECT_LIMIT
|| is_x_intersect(&layer_one->display_frame,&layer_two->display_frame)
#endif
)
{
ALOGD_IF(log_level(DBG_SILENT),"is_layer_combine layer one alpha=%d,is_scale=%d",layer_one->alpha,layer_one->is_scale);
ALOGD_IF(log_level(DBG_SILENT),"is_layer_combine layer two alpha=%d,is_scale=%d",layer_two->alpha,layer_two->is_scale);
return false;
}
return true;
}
static bool has_layer(std::vector<DrmHwcLayer*>& layer_vector,DrmHwcLayer &layer)
{
for (std::vector<DrmHwcLayer*>::const_iterator iter = layer_vector.begin();
iter != layer_vector.end(); ++iter) {
if((*iter)->sf_handle==layer.sf_handle)
if((*iter)->bClone_ == layer.bClone_)
return true;
}
return false;
}
static int combine_layer(LayerMap& layer_map,std::vector<DrmHwcLayer>& layers,
int iPlaneSize, bool use_combine)
{
/*Group layer*/
int zpos = 0;
size_t i,j;
uint32_t sort_cnt=0;
bool is_combine = false;
layer_map.clear();
for (i = 0; i < layers.size(); ) {
if(!layers[i].bUse)
continue;
sort_cnt=0;
if(i == 0)
{
layer_map[zpos].push_back(&layers[0]);
}
for(j = i+1; j < layers.size(); j++) {
DrmHwcLayer &layer_one = layers[j];
//layer_one.index = j;
is_combine = false;
for(size_t k = 0; k <= sort_cnt; k++ ) {
DrmHwcLayer &layer_two = layers[j-1-k];
//layer_two.index = j-1-k;
//juage the layer is contained in layer_vector
bool bHasLayerOne = has_layer(layer_map[zpos],layer_one);
bool bHasLayerTwo = has_layer(layer_map[zpos],layer_two);
//If it contain both of layers,then don't need to go down.
if(bHasLayerOne && bHasLayerTwo)
continue;
if(use_combine && is_layer_combine(&layer_one,&layer_two)) {
//append layer into layer_vector of layer_map_.
if(!bHasLayerOne && !bHasLayerTwo)
{
layer_map[zpos].emplace_back(&layer_one);
layer_map[zpos].emplace_back(&layer_two);
is_combine = true;
}
else if(!bHasLayerTwo)
{
is_combine = true;
for(std::vector<DrmHwcLayer*>::const_iterator iter= layer_map[zpos].begin();
iter != layer_map[zpos].end();++iter)
{
if((*iter)->sf_handle==layer_one.sf_handle)
if((*iter)->bClone_==layer_one.bClone_)
continue;
if(!is_layer_combine(*iter,&layer_two))
{
is_combine = false;
break;
}
}
if(is_combine)
layer_map[zpos].emplace_back(&layer_two);
}
else if(!bHasLayerOne)
{
is_combine = true;
for(std::vector<DrmHwcLayer*>::const_iterator iter= layer_map[zpos].begin();
iter != layer_map[zpos].end();++iter)
{
if((*iter)->sf_handle==layer_two.sf_handle)
if((*iter)->bClone_==layer_two.bClone_)
continue;
if(!is_layer_combine(*iter,&layer_one))
{
is_combine = false;
break;
}
}
if(is_combine)
{
layer_map[zpos].emplace_back(&layer_one);
}
}
}
if(!is_combine)
{
//if it cann't combine two layer,it need start a new group.
if(!bHasLayerOne)
{
zpos++;
layer_map[zpos].emplace_back(&layer_one);
}
is_combine = false;
break;
}
}
sort_cnt++; //update sort layer count
if(!is_combine)
{
break;
}
}
if(is_combine) //all remain layer or limit MOST_WIN_ZONES layer is combine well,it need start a new group.
zpos++;
if(sort_cnt)
i+=sort_cnt; //jump the sort compare layers.
else
i++;
}
#if RK_SORT_AREA_BY_XPOS
//sort layer by xpos
for (LayerMap::iterator iter = layer_map.begin();
iter != layer_map.end(); ++iter) {
if(iter->second.size() > 1) {
for(uint32_t i=0;i < iter->second.size()-1;i++) {
for(uint32_t j=i+1;j < iter->second.size();j++) {
if(iter->second[i]->display_frame.left > iter->second[j]->display_frame.left) {
ALOGD_IF(log_level(DBG_DEBUG),"swap %s and %s",iter->second[i]->name.c_str(),iter->second[j]->name.c_str());
std::swap(iter->second[i],iter->second[j]);
}
}
}
}
}
#else
//sort layer by ypos
for (LayerMap::iterator iter = layer_map.begin();
iter != layer_map.end(); ++iter) {
if(iter->second.size() > 1) {
for(uint32_t i=0;i < iter->second.size()-1;i++) {
for(uint32_t j=i+1;j < iter->second.size();j++) {
if(iter->second[i]->display_frame.top > iter->second[j]->display_frame.top) {
ALOGD_IF(log_level(DBG_DEBUG),"swap %s and %s",iter->second[i]->name.c_str(),iter->second[j]->name.c_str());
std::swap(iter->second[i],iter->second[j]);
}
}
}
}
}
#endif
for (LayerMap::iterator iter = layer_map.begin();
iter != layer_map.end(); ++iter) {
ALOGD_IF(log_level(DBG_DEBUG),"layer map id=%d,size=%zu",iter->first,iter->second.size());
for(std::vector<DrmHwcLayer*>::const_iterator iter_layer = iter->second.begin();
iter_layer != iter->second.end();++iter_layer)
{
ALOGD_IF(log_level(DBG_DEBUG),"\tlayer name=%s",(*iter_layer)->name.c_str());
}
}
if((int)layer_map.size() > iPlaneSize)
{
ALOGD_IF(log_level(DBG_DEBUG),"map size=%zu should not bigger than plane size=%d", layer_map.size(), iPlaneSize);
return -1;
}
return 0;
}
static bool rkHasPlanesWithSize(DrmCrtc *crtc, int layer_size) {
DrmResources* drm = crtc->getDrmReoources();
std::vector<PlaneGroup *>& plane_groups = drm->GetPlaneGroups();
//loop plane groups.
for (std::vector<PlaneGroup *> ::const_iterator iter = plane_groups.begin();
iter != plane_groups.end(); ++iter) {
if(GetCrtcSupported(*crtc, (*iter)->possible_crtcs) && !(*iter)->bUse &&
(*iter)->planes.size() == (size_t)layer_size)
return true;
}
return false;
}
#if USE_AFBC_LAYER
static std::vector<DrmPlane *> rkGetNoAfbcUsablePlanes(DrmCrtc *crtc) {
DrmResources* drm = crtc->getDrmReoources();
std::vector<PlaneGroup *>& plane_groups = drm->GetPlaneGroups();
std::vector<DrmPlane *> usable_planes;
//loop plane groups.
for (std::vector<PlaneGroup *> ::const_iterator iter = plane_groups.begin();
iter != plane_groups.end(); ++iter) {
if(!(*iter)->bUse)
//only count the first plane in plane group.
std::copy_if((*iter)->planes.begin(), (*iter)->planes.begin()+1,
std::back_inserter(usable_planes),
[=](DrmPlane *plane) {
return !plane->is_use() && plane->GetCrtcSupported(*crtc) && !plane->get_afbc(); }
);
}
return usable_planes;
}
#endif
static std::vector<DrmPlane *> rkGetNoYuvUsablePlanes(DrmCrtc *crtc) {
DrmResources* drm = crtc->getDrmReoources();
std::vector<PlaneGroup *>& plane_groups = drm->GetPlaneGroups();
std::vector<DrmPlane *> usable_planes;
//loop plane groups.
for (std::vector<PlaneGroup *> ::const_iterator iter = plane_groups.begin();
iter != plane_groups.end(); ++iter) {
if(!(*iter)->bUse)
//only count the first plane in plane group.
std::copy_if((*iter)->planes.begin(), (*iter)->planes.begin()+1,
std::back_inserter(usable_planes),
[=](DrmPlane *plane) {
return !plane->is_use() && plane->GetCrtcSupported(*crtc) && !plane->get_yuv(); }
);
}
return usable_planes;
}
static std::vector<DrmPlane *> rkGetNoScaleUsablePlanes(DrmCrtc *crtc) {
DrmResources* drm = crtc->getDrmReoources();
std::vector<PlaneGroup *>& plane_groups = drm->GetPlaneGroups();
std::vector<DrmPlane *> usable_planes;
//loop plane groups.
for (std::vector<PlaneGroup *> ::const_iterator iter = plane_groups.begin();
iter != plane_groups.end(); ++iter) {
if(!(*iter)->bUse)
//only count the first plane in plane group.
std::copy_if((*iter)->planes.begin(), (*iter)->planes.begin()+1,
std::back_inserter(usable_planes),
[=](DrmPlane *plane) {
return !plane->is_use() && plane->GetCrtcSupported(*crtc) && !plane->get_scale(); }
);
}
return usable_planes;
}
static std::vector<DrmPlane *> rkGetNoAlphaUsablePlanes(DrmCrtc *crtc) {
DrmResources* drm = crtc->getDrmReoources();
std::vector<PlaneGroup *>& plane_groups = drm->GetPlaneGroups();
std::vector<DrmPlane *> usable_planes;
//loop plane groups.
for (std::vector<PlaneGroup *> ::const_iterator iter = plane_groups.begin();
iter != plane_groups.end(); ++iter) {
if(!(*iter)->bUse)
//only count the first plane in plane group.
std::copy_if((*iter)->planes.begin(), (*iter)->planes.begin()+1,
std::back_inserter(usable_planes),
[=](DrmPlane *plane) {
return !plane->is_use() && plane->GetCrtcSupported(*crtc) && !plane->alpha_property().id(); }
);
}
return usable_planes;
}
static std::vector<DrmPlane *> rkGetNoEotfUsablePlanes(DrmCrtc *crtc) {
DrmResources* drm = crtc->getDrmReoources();
std::vector<PlaneGroup *>& plane_groups = drm->GetPlaneGroups();
std::vector<DrmPlane *> usable_planes;
//loop plane groups.
for (std::vector<PlaneGroup *> ::const_iterator iter = plane_groups.begin();
iter != plane_groups.end(); ++iter) {
if(!(*iter)->bUse)
//only count the first plane in plane group.
std::copy_if((*iter)->planes.begin(), (*iter)->planes.begin()+1,
std::back_inserter(usable_planes),
[=](DrmPlane *plane) {
return !plane->is_use() && plane->GetCrtcSupported(*crtc) && !plane->get_hdr2sdr(); }
);
}
return usable_planes;
}
//According to zpos and combine layer count,find the suitable plane.
// bReserve [IN]: True if want to reserve feature plane.
static bool MatchPlane(std::vector<DrmHwcLayer*>& layer_vector,
uint64_t* zpos,
DrmCrtc *crtc,
DrmResources *drm,
std::vector<DrmCompositionPlane>& composition_planes,
bool bMulArea,
bool is_interlaced,
int fbSize,
bool bReserve)
{
uint32_t combine_layer_count = 0;
uint32_t layer_size = layer_vector.size();
bool b_yuv=false,b_scale=false,b_alpha=false,b_hdr2sdr=false,b_afbc=false;
std::vector<PlaneGroup *> ::const_iterator iter;
std::vector<PlaneGroup *>& plane_groups = drm->GetPlaneGroups();
uint64_t rotation = 0;
uint64_t alpha = 0xFF;
uint16_t eotf = TRADITIONAL_GAMMA_SDR;
#ifndef TARGET_BOARD_PLATFORM_RK3288
UN_USED(fbSize);
#endif
//loop plane groups.
for (iter = plane_groups.begin();
iter != plane_groups.end(); ++iter) {
ALOGD_IF(log_level(DBG_DEBUG),"line=%d,last zpos=%" PRIu64 ",group(%" PRIu64 ") zpos=%d,group bUse=%d,crtc=0x%x,possible_crtcs=0x%x",
__LINE__, *zpos, (*iter)->share_id, (*iter)->zpos, (*iter)->bUse, (1<<crtc->pipe()), (*iter)->possible_crtcs);
//find the match zpos plane group
if(!(*iter)->bUse && !(*iter)->b_reserved)
{
ALOGD_IF(log_level(DBG_DEBUG),"line=%d,layer_size=%d,planes size=%zu",__LINE__,layer_size,(*iter)->planes.size());
//find the match combine layer count with plane size.
if(layer_size <= (*iter)->planes.size())
{
//loop layer
for(std::vector<DrmHwcLayer*>::const_iterator iter_layer= layer_vector.begin();
iter_layer != layer_vector.end();++iter_layer)
{
//reset is_match to false
(*iter_layer)->is_match = false;
if(bMulArea
&& !(*iter_layer)->is_yuv
&& !(*iter_layer)->is_scale
&& !((*iter_layer)->blending == DrmHwcBlending::kPreMult && (*iter_layer)->alpha != 0xFF)
&& layer_size == 1
&& layer_size < (*iter)->planes.size())
{
if(rkHasPlanesWithSize(crtc, layer_size))
{
ALOGD_IF(log_level(DBG_DEBUG),"Planes(%" PRIu64 ") don't need use multi area feature",(*iter)->share_id);
continue;
}
}
//loop plane
for(std::vector<DrmPlane*> ::const_iterator iter_plane=(*iter)->planes.begin();
!(*iter)->planes.empty() && iter_plane != (*iter)->planes.end(); ++iter_plane)
{
ALOGD_IF(log_level(DBG_DEBUG),"line=%d,crtc=0x%x,plane(%d) is_use=%d,possible_crtc_mask=0x%x",__LINE__,(1<<crtc->pipe()),
(*iter_plane)->id(),(*iter_plane)->is_use(),(*iter_plane)->get_possible_crtc_mask());
if(!(*iter_plane)->is_use() && (*iter_plane)->GetCrtcSupported(*crtc))
{
bool bNeed = false;
b_yuv = (*iter_plane)->get_yuv();
if((*iter_layer)->is_yuv)
{
if(!b_yuv)
{
ALOGD_IF(log_level(DBG_DEBUG),"Plane(%d) cann't support yuv",(*iter_plane)->id());
continue;
}
else
bNeed = true;
}
b_scale = (*iter_plane)->get_scale();
if((*iter_layer)->is_scale)
{
if(!b_scale)
{
ALOGD_IF(log_level(DBG_DEBUG),"Plane(%d) cann't support scale",(*iter_plane)->id());
continue;
}
else
{
if((*iter_layer)->h_scale_mul >= 8.0 || (*iter_layer)->v_scale_mul >= 8.0 ||
(*iter_layer)->h_scale_mul <= 0.125 || (*iter_layer)->v_scale_mul <= 0.125)
{
ALOGD_IF(log_level(DBG_DEBUG),"Plane(%d) cann't support scale factor(%f,%f)",
(*iter_plane)->id(), (*iter_layer)->h_scale_mul, (*iter_layer)->v_scale_mul);
continue;
}
else
bNeed = true;
}
}
if ((*iter_layer)->blending == DrmHwcBlending::kPreMult)
alpha = (*iter_layer)->alpha;
#ifdef TARGET_BOARD_PLATFORM_RK3328
//disable global alpha feature for rk3328,since vop has bug on rk3328.
b_alpha = false;
#else
b_alpha = (*iter_plane)->alpha_property().id()?true:false;
#endif
if(alpha != 0xFF)
{
if(!b_alpha)
{
ALOGV("layer name=%s,plane id=%d",(*iter_layer)->name.c_str(),(*iter_plane)->id());
ALOGD_IF(log_level(DBG_DEBUG),"Plane(%d) cann't support alpha,layer alpha=0x%x,alpha id=%d",
(*iter_plane)->id(),(*iter_layer)->alpha,(*iter_plane)->alpha_property().id());
continue;
}
else
bNeed = true;
}
eotf = (*iter_layer)->eotf;
b_hdr2sdr = (*iter_plane)->get_hdr2sdr();
if(eotf != TRADITIONAL_GAMMA_SDR)
{
if(!b_hdr2sdr)
{
ALOGV("layer name=%s,plane id=%d",(*iter_layer)->name.c_str(),(*iter_plane)->id());
ALOGD_IF(log_level(DBG_DEBUG),"Plane(%d) cann't support etof,layer eotf=%d,hdr2sdr=%d",
(*iter_plane)->id(),(*iter_layer)->eotf,(*iter_plane)->get_hdr2sdr());
continue;
}
else
bNeed = true;
}
#if USE_AFBC_LAYER
b_afbc = (*iter_plane)->get_afbc();
if((*iter_layer)->is_afbc && (*iter_plane)->get_afbc_prop())
{
if(!b_afbc)
{
ALOGV("layer name=%s,plane id=%d",(*iter_layer)->name.c_str(),(*iter_plane)->id());
ALOGD_IF(log_level(DBG_DEBUG),"Plane(%d) cann't support afbc,layer", (*iter_plane)->id());
continue;
}
else
bNeed = true;
}
#else
UN_USED(b_afbc);
#endif
#ifdef TARGET_BOARD_PLATFORM_RK3288
int src_w,src_h;
src_w = (int)((*iter_layer)->source_crop.right - (*iter_layer)->source_crop.left);
#if RK_VIDEO_SKIP_LINE
if((*iter_layer)->SkipLine)
{
src_h = (int)((*iter_layer)->source_crop.bottom - (*iter_layer)->source_crop.top)/(*iter_layer)->SkipLine;
}
else
#endif
src_h = (int)((*iter_layer)->source_crop.bottom - (*iter_layer)->source_crop.top);
float src_size = (float)src_w * src_h;
if(src_size/fbSize > 0.75)
{
bNeed = true;
ALOGD_IF(log_level(DBG_DEBUG),"Plane(%d) need by big area,src_size=%f,fbSize=%d",(*iter_plane)->id(),src_size,fbSize);
}
#endif
//Reserve some plane with no need for specific features in current layer.
if(bReserve && !bNeed && !bMulArea && !is_interlaced)
{
#if USE_AFBC_LAYER
if(!(*iter_layer)->is_afbc && b_afbc)
{
std::vector<DrmPlane *> no_afbc_planes = rkGetNoAfbcUsablePlanes(crtc);
if(no_afbc_planes.size() > 0)
{
ALOGD_IF(log_level(DBG_DEBUG),"Plane(%d) don't need use afbc feature",(*iter_plane)->id());
continue;
}
}
#endif
if(!(*iter_layer)->is_yuv && b_yuv)
{
std::vector<DrmPlane *> no_yuv_planes = rkGetNoYuvUsablePlanes(crtc);
if(no_yuv_planes.size() > 0)
{
ALOGD_IF(log_level(DBG_DEBUG),"Plane(%d) don't need use yuv feature",(*iter_plane)->id());
continue;
}
}
if(!(*iter_layer)->is_scale && b_scale)
{
std::vector<DrmPlane *> no_scale_planes = rkGetNoScaleUsablePlanes(crtc);
if(no_scale_planes.size() > 0)
{
ALOGD_IF(log_level(DBG_DEBUG),"Plane(%d) don't need use scale feature",(*iter_plane)->id());
continue;
}
}
if(alpha == 0xFF && b_alpha)
{
std::vector<DrmPlane *> no_alpha_planes = rkGetNoAlphaUsablePlanes(crtc);
if(no_alpha_planes.size() > 0)
{
ALOGD_IF(log_level(DBG_DEBUG),"Plane(%d) don't need use alpha feature",(*iter_plane)->id());
continue;
}
}
if(eotf == TRADITIONAL_GAMMA_SDR && b_hdr2sdr)
{
std::vector<DrmPlane *> no_eotf_planes = rkGetNoEotfUsablePlanes(crtc);
if(no_eotf_planes.size() > 0)
{
ALOGD_IF(log_level(DBG_DEBUG),"Plane(%d) don't need use eotf feature",(*iter_plane)->id());
continue;
}
}
}
#if (RK_RGA_COMPSITE_SYNC | RK_RGA_PREPARE_ASYNC)
if(!drm->isSupportRkRga()
#if USE_AFBC_LAYER
|| (*iter_layer)->is_afbc
#endif
)
#endif
{
rotation = 0;
if ((*iter_layer)->transform & DrmHwcTransform::kFlipH)
rotation |= 1 << DRM_REFLECT_X;
if ((*iter_layer)->transform & DrmHwcTransform::kFlipV)
rotation |= 1 << DRM_REFLECT_Y;
if ((*iter_layer)->transform & DrmHwcTransform::kRotate90)
rotation |= 1 << DRM_ROTATE_90;
else if ((*iter_layer)->transform & DrmHwcTransform::kRotate180)
rotation |= 1 << DRM_ROTATE_180;
else if ((*iter_layer)->transform & DrmHwcTransform::kRotate270)
rotation |= 1 << DRM_ROTATE_270;
if(rotation && !(rotation & (*iter_plane)->get_rotate()))
continue;
}
ALOGD_IF(log_level(DBG_DEBUG),"MatchPlane: match layer=%s,plane=%d,(*iter_layer)->index=%zu ,zops = %" PRIu64 "",(*iter_layer)->name.c_str(),
(*iter_plane)->id(),(*iter_layer)->index,*zpos);
//Find the match plane for layer,it will be commit.
composition_planes.emplace_back(DrmCompositionPlane::Type::kLayer, (*iter_plane), crtc, (*iter_layer)->zpos);
(*iter_layer)->is_match = true;
(*iter_plane)->set_use(true);
composition_planes.back().set_zpos(*zpos);
combine_layer_count++;
break;
}
}
}
if(combine_layer_count == layer_size)
{
ALOGD_IF(log_level(DBG_DEBUG),"line=%d all match",__LINE__);
//update zpos for the next time.
*zpos += 1;
(*iter)->bUse = true;
return true;
}
}
/*else
{
//1. cut out combine_layer_count to (*iter)->planes.size().
//2. combine_layer_count layer assign planes.
//3. extern layers assign planes.
return false;
}*/
}
}
return false;
}
bool MatchPlanes(
std::map<int, std::vector<DrmHwcLayer*>> &layer_map,
DrmCrtc *crtc,
DrmResources *drm,
std::vector<DrmCompositionPlane>& composition_planes,
bool bMulArea,
bool is_interlaced,
int fbSize)
{
std::vector<PlaneGroup *>& plane_groups = drm->GetPlaneGroups();
uint64_t last_zpos=0;
bool bMatch = false;
#ifdef USE_PLANE_RESERVED
uint64_t win1_reserved = hwc_get_int_property( PROPERTY_TYPE ".hwc.win1.reserved", "0");
uint64_t win1_zpos = hwc_get_int_property( PROPERTY_TYPE ".hwc.win1.zpos", "0");
#endif
//set use flag to false.
for (std::vector<PlaneGroup *> ::const_iterator iter = plane_groups.begin();
iter != plane_groups.end(); ++iter) {
(*iter)->bUse=false;
for(std::vector<DrmPlane *> ::const_iterator iter_plane=(*iter)->planes.begin();
iter_plane != (*iter)->planes.end(); ++iter_plane) {
if((*iter_plane)->GetCrtcSupported(*crtc)) //only init the special crtc's plane
(*iter_plane)->set_use(false);
}
}
//clear composition_plane
composition_planes.clear();
for (LayerMap::iterator iter = layer_map.begin();
iter != layer_map.end(); ++iter) {
#ifdef USE_PLANE_RESERVED
if(win1_reserved > 0 && win1_zpos == last_zpos)
{
last_zpos++;
}
#endif
if(iter == layer_map.begin())
{
DrmHwcLayer* first_layer = (iter->second)[0];
if(first_layer->alpha != 0xFF)
{
ALOGD_IF(log_level(DBG_DEBUG),"%s:line=%d vop cann't support first layer with global alpha",__FUNCTION__,__LINE__);
return false;
}
}
bMatch = MatchPlane(iter->second, &last_zpos, crtc, drm, composition_planes, bMulArea, is_interlaced, fbSize, true);
if(!bMatch)
{
ALOGD_IF(log_level(DBG_DEBUG),"hwc_prepare: first Cann't find the match plane for layer group %d",iter->first);
bMatch = MatchPlane(iter->second, &last_zpos, crtc, drm, composition_planes, bMulArea, is_interlaced, fbSize, false);
if(!bMatch)
{
ALOGD_IF(log_level(DBG_DEBUG),"hwc_prepare: second Cann't find the match plane for layer group %d",iter->first);
return false;
}
}
}
return true;
}
float getPixelWidthByAndroidFormat(int format)
{
float pixelWidth = 4.0;
switch (format) {
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGBX_8888:
case HAL_PIXEL_FORMAT_BGRA_8888:
pixelWidth = 4.0;
break;
case HAL_PIXEL_FORMAT_RGB_888:
pixelWidth = 3.0;
break;
case HAL_PIXEL_FORMAT_RGB_565:
pixelWidth = 2.0;
break;
case HAL_PIXEL_FORMAT_sRGB_A_8888:
case HAL_PIXEL_FORMAT_sRGB_X_8888:
ALOGE("format 0x%x not support",format);
break;
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
case HAL_PIXEL_FORMAT_YCbCr_422_I:
case HAL_PIXEL_FORMAT_YCrCb_NV12:
case HAL_PIXEL_FORMAT_YCrCb_NV12_VIDEO:
pixelWidth = 1.0;
break;
case HAL_PIXEL_FORMAT_YCrCb_NV12_10:
pixelWidth = 2;
break;
case HAL_PIXEL_FORMAT_YCbCr_422_SP_10:
case HAL_PIXEL_FORMAT_YCrCb_420_SP_10:
pixelWidth = 1.0;
break;
default:
ALOGE("format 0x%x not support",format);
break;
}
return pixelWidth;
}
static float vop_band_width(hwc_drm_display_t *hd, std::vector<DrmHwcLayer>& layers)
{
float scale_factor = 0;
if(hd->mixMode == HWC_MIX_DOWN || hd->mixMode == HWC_MIX_UP ||
hd->mixMode == HWC_MIX_CROSS)
{
scale_factor += 1.0;
}
for(size_t i = 0; i < layers.size(); ++i)
{
scale_factor += layers[i].h_scale_mul * layers[i].v_scale_mul;
}
return scale_factor;
}
bool GetCrtcSupported(const DrmCrtc &crtc, uint32_t possible_crtc_mask) {
return !!((1 << crtc.pipe()) & possible_crtc_mask);
}
bool match_process(DrmResources* drm, DrmCrtc *crtc, bool is_interlaced,
std::vector<DrmHwcLayer>& layers, int iPlaneSize, int fbSize,
std::vector<DrmCompositionPlane>& composition_planes)
{
int zpos = 0;
LayerMap layer_map;
int iMatchCnt = 0;
bool bMatch = false;
if(!crtc)
{
ALOGE("%s:line=%d crtc is null",__FUNCTION__,__LINE__);
return false;
}
//update zpos of layer
for (size_t i = 0; i < layers.size(); ++i)
{
layers[i].zpos = zpos;
zpos++;
}
int ret = combine_layer(layer_map, layers, iPlaneSize, !is_interlaced);
if(ret == 0)
{
bool bMulArea = layers.size() > layer_map.size();
bMatch = MatchPlanes(layer_map,crtc,drm,composition_planes, bMulArea, is_interlaced, fbSize);
}
if(bMatch)
{
for(std::vector<DrmHwcLayer>::const_iterator iter_layer= layers.begin();
iter_layer != layers.end();++iter_layer)
{
if((*iter_layer).is_match)
{
iMatchCnt++;
}
}
if(iMatchCnt == (int)layers.size())
return true;
}
return false;
}
static bool try_mix_policy(DrmResources* drm, DrmCrtc *crtc, bool is_interlaced,
std::vector<DrmHwcLayer>& layers, std::vector<DrmHwcLayer>& tmp_layers,
int iPlaneSize, std::vector<DrmCompositionPlane>& composition_planes,
int iFirst, int iLast, int fbSize)
{
bool bAllMatch = false;
if(iFirst < 0 || iLast < 0 || iFirst > iLast)
{
ALOGE("invalid value iFirst=%d, iLast=%d", iFirst, iLast);
return false;
}
for(auto i = layers.begin(); i != layers.end();i++)
{
if((*i).raw_sf_layer->compositionType == HWC_MIX)
(*i).raw_sf_layer->compositionType = HWC_FRAMEBUFFER;
}
/*************************mix down*************************
many layers
-----------+----------+------+------+----+------+-------------+--------------------------------+------------------------+------
GLES | 711aa61e80 | 0000 | 0000 | 00 | 0100 | RGBx_8888 | 0.0, 0.0, 2400.0, 1600.0 | 0, 0, 2400, 1600 | com.android.systemui.ImageWallpaper
GLES | 711ab1ef00 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 2400.0, 1600.0 | 0, 0, 2400, 1600 | com.android.launcher3/com.android.launcher3.Launcher
HWC | 711aa61100 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 2400.0, 2.0 | 0, 0, 2400, 2 | StatusBar
HWC | 711ec5ad80 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 2400.0, 84.0 | 0, 1516, 2400, 1600 | taskbar
HWC | 711ec5a900 | 0000 | 0002 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 39.0, 49.0 | 941, 810, 980, 859 | Sprite
************************************************************/
ALOGD_IF(log_level(DBG_DEBUG), "Go into Mix policy");
int interval = layers.size()-1-iLast;
ALOGD_IF(log_level(DBG_DEBUG), "try_mix_policy iFirst=%d,interval=%d",iFirst,interval);
for (auto i = layers.begin() + iFirst; i != layers.end() - interval;)
{
if((*i).bClone_)
continue;
(*i).bMix = true;
(*i).raw_sf_layer->compositionType = HWC_MIX;
//move gles layers
tmp_layers.emplace_back(std::move(*i));
i = layers.erase(i);
}
//add fb layer.
int pos = iFirst;
for (auto i = tmp_layers.begin(); i != tmp_layers.end();)
{
if((*i).raw_sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET)
{
layers.insert(layers.begin() + pos, std::move(*i));
pos++;
i = tmp_layers.erase(i);
continue;
}
i++;
}
bAllMatch = match_process(drm, crtc, is_interlaced, layers, iPlaneSize, fbSize, composition_planes);
if(bAllMatch)
return true;
return false;
}
void move_fb_layer_to_tmp(std::vector<DrmHwcLayer>& layers, std::vector<DrmHwcLayer>& tmp_layers)
{
for (auto i = layers.begin(); i != layers.end();)
{
if((*i).raw_sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET)
{
tmp_layers.emplace_back(std::move(*i));
i = layers.erase(i);
continue;
}
i++;
}
}
void resore_all_tmp_layers(std::vector<DrmHwcLayer>& layers, std::vector<DrmHwcLayer>& tmp_layers)
{
for (auto i = tmp_layers.begin(); i != tmp_layers.end();)
{
layers.emplace_back(std::move(*i));
i = tmp_layers.erase(i);
}
//sort
for (auto i = layers.begin(); i != layers.end()-1; i++)
{
for (auto j = i+1; j != layers.end(); j++)
{
if((*i).index > (*j).index)
{
std::swap(*i, *j);
}
}
}
}
void resore_tmp_layers_except_fb(std::vector<DrmHwcLayer>& layers, std::vector<DrmHwcLayer>& tmp_layers)
{
for (auto i = tmp_layers.begin(); i != tmp_layers.end();)
{
layers.emplace_back(std::move(*i));
i = tmp_layers.erase(i);
}
//sort by layer index
for (auto i = layers.begin(); i != layers.end()-1; i++)
{
for (auto j = i+1; j != layers.end(); j++)
{
if((*i).index > (*j).index)
{
std::swap(*i, *j);
}
}
}
move_fb_layer_to_tmp(layers, tmp_layers);
}
bool mix_policy(DrmResources* drm, DrmCrtc *crtc, hwc_drm_display_t *hd,
std::vector<DrmHwcLayer>& layers, int iPlaneSize, int fbSize,
std::vector<DrmCompositionPlane>& composition_planes)
{
bool bAllMatch = false, bHasSkipLayer = false;
std::vector<DrmHwcLayer> tmp_layers;
int skipCnt = 0;
int iUsePlane = 0;
std::vector<PlaneGroup *>& plane_groups = drm->GetPlaneGroups();
// Since we can't composite HWC_SKIP_LAYERs by ourselves, we'll let SF
// handle all layers in between the first and last skip layers. So find the
// outer indices and mark everything in between as HWC_FRAMEBUFFER
std::pair<int, int> skip_layer_indices(-1, -1);
std::pair<int, int> layer_indices(-1, -1);
if(!crtc)
{
ALOGE("%s:line=%d crtc is null",__FUNCTION__,__LINE__);
return false;
}
//save fb into tmp_layers
move_fb_layer_to_tmp(layers, tmp_layers);
//caculate the first and last skip layer
for (int i = 0; i < (int)layers.size(); ++i) {
DrmHwcLayer& layer = layers[i];
if (!layer.bSkipLayer)
continue;
if (skip_layer_indices.first == -1)
skip_layer_indices.first = i;
skip_layer_indices.second = i;
}
if(skip_layer_indices.first != -1)
{
bHasSkipLayer = true;
skipCnt = skip_layer_indices.second - skip_layer_indices.first + 1;
}
//OPT: Adjust skip_layer_indices.first and skip_layer_indices.second to limit in iPlaneSize.
if(!hd->is_3d && bHasSkipLayer && ((int)layers.size() - skipCnt + 1) > iPlaneSize)
{
int tmp_index = -1;
if(skip_layer_indices.first != 0)
{
tmp_index = skip_layer_indices.first;
//try decrease first skip index to 0.
skip_layer_indices.first = 0;
skipCnt = skip_layer_indices.second - skip_layer_indices.first + 1;
if(((int)layers.size() - skipCnt + 1) > iPlaneSize && skip_layer_indices.second != (int)layers.size()-1)
{
skip_layer_indices.first = tmp_index;
tmp_index = skip_layer_indices.second;
//try increase second skip index to last index.
skip_layer_indices.second = layers.size()-1;
skipCnt = skip_layer_indices.second - skip_layer_indices.first + 1;
if(((int)layers.size() - skipCnt + 1) > iPlaneSize)
{
ALOGD_IF(log_level(DBG_DEBUG), "%s:line=%d fail match (%d,%d)",__FUNCTION__,__LINE__,skip_layer_indices.first, tmp_index);
goto FailMatch;
}
}
}
else
{
if(skip_layer_indices.second != (int)layers.size()-1)
{
//try increase second skip index to last index-1.
skip_layer_indices.second = layers.size()-2;
skipCnt = skip_layer_indices.second + 1;
if(((int)layers.size() - skipCnt + 1) > iPlaneSize)
{
ALOGD_IF(log_level(DBG_DEBUG), "%s:line=%d fail match (%d,%d)",__FUNCTION__,__LINE__,skip_layer_indices.first, tmp_index);
goto FailMatch;
}
}
else
{
ALOGD_IF(log_level(DBG_DEBUG), "%s:line=%d fail match (%d,%d)",__FUNCTION__,__LINE__,skip_layer_indices.first, tmp_index);
goto FailMatch;
}
}
}
/*************************mix skip layer*************************/
if(!hd->is_3d && bHasSkipLayer && ((int)layers.size() - skipCnt + 1) <= iPlaneSize)
{
ALOGD_IF(log_level(DBG_DEBUG), "%s:has skip layer (%d,%d)",__FUNCTION__,skip_layer_indices.first, skip_layer_indices.second);
if(hd->mixMode != HWC_MIX_CROSS)
hd->mixMode = HWC_MIX_CROSS;
bAllMatch = try_mix_policy(drm, crtc, hd->is_interlaced, layers, tmp_layers, iPlaneSize, composition_planes,
skip_layer_indices.first, skip_layer_indices.second, fbSize);
if(bAllMatch)
goto AllMatch;
else
{
ALOGD_IF(log_level(DBG_DEBUG), "%s:line=%d fail match (%d,%d)",__FUNCTION__,__LINE__,skip_layer_indices.first, skip_layer_indices.second);
goto FailMatch;
}
}
/*************************mix 3d layer(mix up)*************************/
if(hd->is_3d)
{
ALOGD_IF(log_level(DBG_DEBUG), "%s:mix 3d (%d,%d)",__FUNCTION__,layer_indices.first, layer_indices.second);
if(hd->mixMode != HWC_MIX_3D)
hd->mixMode = HWC_MIX_3D;
if(hd->stereo_mode == H_3D || hd->stereo_mode == V_3D || hd->stereo_mode == FPS_3D)
{
if(layers[0].stereo)
{
layer_indices.first = 1;
layer_indices.second = layers.size() - 1;
bAllMatch = try_mix_policy(drm, crtc, hd->is_interlaced, layers, tmp_layers, iPlaneSize, composition_planes,
layer_indices.first, layer_indices.second, fbSize);
if(bAllMatch)
goto AllMatch;
else
{
//ALOGD_IF(log_level(DBG_DEBUG), "%s:line=%d fail match (%d,%d)",__FUNCTION__,__LINE__,skip_layer_indices.first, skip_layer_indices.second);
resore_tmp_layers_except_fb(layers, tmp_layers);
}
}
else
{
ALOGD_IF(log_level(DBG_DEBUG), "%s:line=%d fail match (%d,%d)",__FUNCTION__,__LINE__,skip_layer_indices.first, skip_layer_indices.second);
goto FailMatch;
}
}
}
/*************************common match*************************/
bAllMatch = match_process(drm, crtc, hd->is_interlaced, layers, iPlaneSize, fbSize, composition_planes);
if(bAllMatch)
goto AllMatch;
if( layers.size() < 2 /*|| iPlaneSize < 4*/)
{
ALOGD_IF(log_level(DBG_DEBUG), "%s:line=%d fail match iPlaneSize=%d, layer size=%d",__FUNCTION__,__LINE__,iPlaneSize,(int)layers.size());
goto FailMatch;
}
/*************************mix up*************************
Video ovelay
-----------+----------+------+------+----+------+-------------+--------------------------------+------------------------+------
HWC | 711aa61e80 | 0000 | 0000 | 00 | 0100 | RGBx_8888 | 0.0, 0.0, 2400.0, 1600.0 | 0, 0, 2400, 1600 | com.android.systemui.ImageWallpaper
HWC | 711ab1ef00 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 2400.0, 1600.0 | 0, 0, 2400, 1600 | com.android.launcher3/com.android.launcher3.Launcher
HWC | 711aa61700 | 0000 | 0000 | 00 | 0100 | ? 00000017 | 0.0, 0.0, 3840.0, 2160.0 | 600, 562, 1160, 982 | SurfaceView - MediaView
GLES | 711ab1e580 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 560.0, 420.0 | 600, 562, 1160, 982 | MediaView
GLES | 70b34c9c80 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 2400.0, 2.0 | 0, 0, 2400, 2 | StatusBar
GLES | 70b34c9080 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 2400.0, 84.0 | 0, 1516, 2400, 1600 | taskbar
GLES | 711ec5a900 | 0000 | 0002 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 39.0, 49.0 | 1136, 1194, 1175, 1243 | Sprite
************************************************************/
if(!hd->bPreferMixDown)
{
if(hd->mixMode != HWC_MIX_UP)
hd->mixMode = HWC_MIX_UP;
if((int)layers.size() < 4)
layer_indices.first = layers.size() - 2;
else
layer_indices.first = iPlaneSize - 1;
layer_indices.second = layers.size() - 1;
ALOGD_IF(log_level(DBG_DEBUG), "%s:mix up for video (%d,%d)",__FUNCTION__,layer_indices.first, layer_indices.second);
bAllMatch = try_mix_policy(drm, crtc,hd->is_interlaced, layers, tmp_layers, iPlaneSize, composition_planes,
layer_indices.first, layer_indices.second, fbSize);
if(bAllMatch)
goto AllMatch;
else
{
resore_tmp_layers_except_fb(layers, tmp_layers);
if(hd->isVideo)
for(-- layer_indices.first;layer_indices.first>0 ; -- layer_indices.first)
{
ALOGD_IF(log_level(DBG_DEBUG), "%s:mix up for video (%d,%d)",__FUNCTION__,layer_indices.first, layer_indices.second);
bAllMatch = try_mix_policy(drm, crtc,hd->is_interlaced, layers, tmp_layers, iPlaneSize, composition_planes,
layer_indices.first, layer_indices.second, fbSize);
if(bAllMatch)
goto AllMatch;
resore_tmp_layers_except_fb(layers, tmp_layers);
}
}
}
/*************************mix down*************************
Sprite layer
-----------+----------+------+------+----+------+-------------+--------------------------------+------------------------+------
GLES | 711aa61e80 | 0000 | 0000 | 00 | 0100 | RGBx_8888 | 0.0, 0.0, 2400.0, 1600.0 | 0, 0, 2400, 1600 | com.android.systemui.ImageWallpaper
GLES | 711ab1ef00 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 2400.0, 1600.0 | 0, 0, 2400, 1600 | com.android.launcher3/com.android.launcher3.Launcher
GLES | 711aa61100 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 2400.0, 2.0 | 0, 0, 2400, 2 | StatusBar
HWC | 711ec5ad80 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 2400.0, 84.0 | 0, 1516, 2400, 1600 | taskbar
HWC | 711ec5a900 | 0000 | 0002 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 39.0, 49.0 | 941, 810, 980, 859 | Sprite
************************************************************/
if(layers.size() >= 4 && layers.size() <= 6 )
{
if(hd->mixMode != HWC_MIX_DOWN)
hd->mixMode = HWC_MIX_DOWN;
layer_indices.first = 0;
layer_indices.second = 2;
ALOGD_IF(log_level(DBG_DEBUG), "%s:mix down (%d,%d)",__FUNCTION__,layer_indices.first, layer_indices.second);
bAllMatch = try_mix_policy(drm, crtc, hd->is_interlaced, layers, tmp_layers, iPlaneSize, composition_planes,
layer_indices.first, layer_indices.second, fbSize);
if(bAllMatch)
goto AllMatch;
else
resore_tmp_layers_except_fb(layers, tmp_layers);
}
if(hd->bPreferMixDown && ((int)layers.size() > iPlaneSize))
{
if(hd->mixMode != HWC_MIX_DOWN)
hd->mixMode = HWC_MIX_DOWN;
layer_indices.first = 0;
layer_indices.second = layers.size() - iPlaneSize;
ALOGD_IF(log_level(DBG_DEBUG), "%s:mix down (%d,%d)",__FUNCTION__,layer_indices.first, layer_indices.second);
bAllMatch = try_mix_policy(drm, crtc, hd->is_interlaced, layers, tmp_layers, iPlaneSize, composition_planes,
layer_indices.first, layer_indices.second, fbSize);
if(bAllMatch)
goto AllMatch;
else
resore_tmp_layers_except_fb(layers, tmp_layers);
}
/*************************mix up*************************
Many layers
************************************************************/
if(!hd->isVideo)
{
if(hd->mixMode != HWC_MIX_UP)
hd->mixMode = HWC_MIX_UP;
if((int)layers.size() < 4)
layer_indices.first = layers.size() - 2;
else
layer_indices.first = 3;
layer_indices.second = layers.size() - 1;
ALOGD_IF(log_level(DBG_DEBUG), "%s:mix up (%d,%d)",__FUNCTION__,layer_indices.first, layer_indices.second);
bAllMatch = try_mix_policy(drm, crtc, hd->is_interlaced, layers, tmp_layers, iPlaneSize, composition_planes,
layer_indices.first, layer_indices.second, fbSize);
if(bAllMatch)
goto AllMatch;
else
goto FailMatch;
}
else
{
goto FailMatch;
}
AllMatch:
#if 1
/*************************vop band width limit*************************/
for (std::vector<PlaneGroup *> ::const_iterator iter = plane_groups.begin();
iter != plane_groups.end(); ++iter) {
if(GetCrtcSupported(*crtc, (*iter)->possible_crtcs) && (*iter)->bUse)
iUsePlane++;
}
if(iUsePlane >= hd->iPlaneSize && !hd->isHdr)
{
float scale_factor = vop_band_width(hd, layers);
float head_factor = 0.0, tail_factor = 0.0;
if(scale_factor > 4.5)
{
ALOGD_IF(log_level(DBG_DEBUG), "scale_factor=%f is so big",scale_factor);
if(layers.size() >= 4 && !bHasSkipLayer)
{
resore_tmp_layers_except_fb(layers, tmp_layers);
for(int k = 0; k < 2; k++)
{
head_factor += layers[k].h_scale_mul * layers[k].v_scale_mul;
}
for(size_t k = layers.size()-2; k < layers.size(); k++)
{
tail_factor += layers[k].h_scale_mul * layers[k].v_scale_mul;
}
if(head_factor > tail_factor)
{
//mix down
if(hd->mixMode != HWC_MIX_DOWN)
hd->mixMode = HWC_MIX_DOWN;
layer_indices.first = 0;
layer_indices.second = 1;
ALOGD_IF(log_level(DBG_DEBUG), "%s:mix down (%d,%d)",__FUNCTION__,layer_indices.first, layer_indices.second);
bAllMatch = try_mix_policy(drm, crtc, hd->is_interlaced, layers, tmp_layers, iPlaneSize, composition_planes,
layer_indices.first, layer_indices.second, fbSize);
scale_factor = vop_band_width(hd, layers);
if(bAllMatch && scale_factor <= 3.3)
{
return true;
}
else
{
ALOGD_IF(log_level(DBG_DEBUG), "%s:line=%d vop band with is too big,fail match (%d,%d),scale_factor=%f",
__FUNCTION__, __LINE__, layer_indices.first, layer_indices.second, scale_factor);
goto FailMatch;
}
}
else
{
//mix up
if(hd->mixMode != HWC_MIX_UP)
hd->mixMode = HWC_MIX_UP;
layer_indices.first = layers.size() - 2;
layer_indices.second = layers.size() - 1;
ALOGD_IF(log_level(DBG_DEBUG), "%s:mix up (%d,%d)",__FUNCTION__,layer_indices.first, layer_indices.second);
bAllMatch = try_mix_policy(drm, crtc, hd->is_interlaced, layers, tmp_layers, iPlaneSize, composition_planes,
layer_indices.first, layer_indices.second, fbSize);
scale_factor = vop_band_width(hd, layers);
if(bAllMatch && scale_factor <= 3.3)
return true;
else
{
ALOGD_IF(log_level(DBG_DEBUG), "%s:line=%d vop band with is too big,fail match (%d,%d),scale_factor=%f",
__FUNCTION__, __LINE__, layer_indices.first, layer_indices.second, scale_factor);
goto FailMatch;
}
}
}
else
{
ALOGD_IF(log_level(DBG_DEBUG), "%s:line=%d vop band with is too big,fail match layers.size=%zu",__FUNCTION__,__LINE__,layers.size());
goto FailMatch;
}
}
}
#endif
return true;
FailMatch:
ALOGD_IF(log_level(DBG_DEBUG), "%s:line=%d Fail match",__FUNCTION__,__LINE__);
//restore tmp layers to layers.
resore_all_tmp_layers(layers, tmp_layers);
//reset mix mode.
hd->mixMode = HWC_DEFAULT;
return false;
}
#if RK_VIDEO_UI_OPT
void video_ui_optimize(const gralloc_module_t *gralloc, hwc_display_contents_1_t *display_content, hwc_drm_display_t *hd)
{
int ret = 0;
int format = 0;
int num_layers = display_content->numHwLayers;
if(num_layers == 3)
{
hwc_layer_1_t *first_layer = &display_content->hwLayers[0];
if(first_layer->handle)
{
#if (!RK_PER_MODE && RK_DRM_GRALLOC)
format = hwc_get_handle_attibute(gralloc, first_layer->handle, ATT_FORMAT);
#else
format = hwc_get_handle_format(gralloc, first_layer->handle);
#endif
if(format == HAL_PIXEL_FORMAT_YCrCb_NV12 || format == HAL_PIXEL_FORMAT_YCrCb_NV12_10)
{
bool bDiff = true;
int iUiFd = 0;
hwc_layer_1_t * second_layer = &display_content->hwLayers[1];
#if (!RK_PER_MODE && RK_DRM_GRALLOC)
format = hwc_get_handle_attibute(gralloc, second_layer->handle, ATT_FORMAT);
#else
format = hwc_get_handle_format(gralloc, second_layer->handle);
#endif
if(second_layer->handle &&
(format == HAL_PIXEL_FORMAT_RGBA_8888 ||
format == HAL_PIXEL_FORMAT_RGBX_8888 ||
format == HAL_PIXEL_FORMAT_BGRA_8888)
)
{
iUiFd = hwc_get_handle_primefd(gralloc, second_layer->handle);
bDiff = (iUiFd != hd->iUiFd);
if(bDiff)
{
hd->bHideUi = false;
/* Update the backup ui fd */
hd->iUiFd = iUiFd;
}
else if(!hd->bHideUi)
{
#if (!RK_PER_MODE && RK_DRM_GRALLOC)
int iWidth = hwc_get_handle_attibute(gralloc,second_layer->handle,ATT_WIDTH);
int iHeight = hwc_get_handle_attibute(gralloc,second_layer->handle,ATT_HEIGHT);
#else
int iWidth = hwc_get_handle_width(gralloc,second_layer->handle);
int iHeight = hwc_get_handle_height(gralloc,second_layer->handle);
#endif
unsigned int *cpu_addr = NULL;;
#if 0
IMG_native_handle_t * pvHandle = (IMG_native_handle_t *)second_layer->handle;
cpu_addr= (unsigned int *)pvHandle->pvBase;
#else
#if USE_GRALLOC_4
ret = gralloc4::lock(second_layer->handle,
GRALLOC_USAGE_SW_READ_MASK,
0,
0,
iWidth,
iHeight,
(void **)&cpu_addr);
#else // USE_GRALLOC_4
ret = gralloc->lock(gralloc, second_layer->handle, GRALLOC_USAGE_SW_READ_MASK,
0, 0, iWidth, iHeight, (void **)&cpu_addr);
#endif // USE_GRALLOC_4
if( (ret != 0) || (cpu_addr == NULL) || (cpu_addr == MAP_FAILED) )
{
ALOGD("%s:line=%d lock failed w=%d,h=%d,cpu_addr=%p", __FUNCTION__, __LINE__, iWidth, iHeight, cpu_addr);
}
else
#endif
{
ret = DetectValidData((int *)(cpu_addr),iWidth,iHeight);
if(!ret)
{
hd->bHideUi = true;
ALOGD_IF(log_level(DBG_VERBOSE), "@video UI close,iWidth=%d,iHeight=%d",iWidth,iHeight);
}
}
#if USE_GRALLOC_4
gralloc4::unlock(second_layer->handle);
#else // USE_GRALLOC_4
gralloc->unlock(gralloc, second_layer->handle);
#endif // USE_GRALLOC_4
}
if(hd->bHideUi)
{
second_layer->compositionType = HWC_NODRAW;
}
else
{
second_layer->compositionType = HWC_FRAMEBUFFER;
}
}
}
}
}
}
#endif
void hwc_list_nodraw(hwc_display_contents_1_t *list)
{
if (list == NULL)
{
return;
}
for (unsigned int i = 0; i < list->numHwLayers - 1; i++)
{
list->hwLayers[i].compositionType = HWC_NODRAW;
}
return;
}
void hwc_sync_release(hwc_display_contents_1_t *list)
{
for (int i=0; i< (int)list->numHwLayers; i++){
hwc_layer_1_t* layer = &list->hwLayers[i];
if (layer == NULL){
return ;
}
if (layer->acquireFenceFd>0){
close(layer->acquireFenceFd);
list->hwLayers[i].acquireFenceFd = -1;
}
}
if (list->outbufAcquireFenceFd>0){
ALOGV(">>>close outbufAcquireFenceFd:%d",list->outbufAcquireFenceFd);
close(list->outbufAcquireFenceFd);
list->outbufAcquireFenceFd = -1;
}
}
const char* hwc_get_baseparameter_file(void)
{
int i = 0;
while (device_template[i]) {
if (!access(device_template[i], R_OK | W_OK)){
return device_template[i];
}
i++;
}
return NULL;
}
static struct file_base_parameter base_parameter;
static bool enableBaseparameter = false;
#define BASE_OFFSET 8*1024
bool hwc_have_baseparameter(void)
{
ALOGI_IF(log_level(DBG_INFO),"BP: have baseparameter exit (%d)",enableBaseparameter);
return enableBaseparameter;
}
int hwc_get_baseparameter_config(char *parameter, int display, int flag, int type)
{
unsigned int w=0,h=0,hsync_start=0,hsync_end=0,htotal=0;
unsigned int vsync_start=0,vsync_end=0,vtotal=0,flags=0,clock=0;
unsigned int format = 0,depthc =0;
unsigned short brightness = 0,contrast = 0,saturation = 0,hue = 0;
unsigned short leftscale = 0,rightscale = 0,topscale = 0,bottomscale = 0;
int res = 0;
static int bcsh_flag = 0x0;
float vfresh=0;
char value_new[128] = {0};
switch(flag){
case BP_UPDATE:
{
memset(&base_parameter,0x00,sizeof(file_base_parameter));
int file;
const char *baseparameterfile = hwc_get_baseparameter_file();
if (!baseparameterfile) {
ALOGW("BP: baseparamter file cann't be find.");
enableBaseparameter = false;
return -1;
}
file = open(baseparameterfile, O_RDWR);
if (file < 0) {
ALOGW("BP: baseparamter file can not be opened,");
enableBaseparameter = false;
return -1;
}
// caculate file's size and read it
unsigned int length = lseek(file, 0L, SEEK_END);
lseek(file, 0L, SEEK_SET);
if(length < sizeof(base_parameter)) {
ALOGW("BP: baseparamter data's length is error\n");
enableBaseparameter = false;
sync();
close(file);
return -1;
}
read(file, (void*)&(base_parameter.main), sizeof(base_parameter.main));
lseek(file, BASE_OFFSET, SEEK_SET);
read(file, (void*)&(base_parameter.aux), sizeof(base_parameter.aux));
close(file);
enableBaseparameter = true;
break;
}
case BP_RESOLUTION:
{
if(enableBaseparameter == false)
{
ALOGW("BP: RESOLUTION baseparameter is not ready,can't use it !");
return -1;
}
if(display == HWC_DISPLAY_PRIMARY){
int i = 0;
bool type_found = false;
for( i = 0 ; i < SCREEN_LIST_MAX ; i++)
{
if(type == base_parameter.main.screen_list[i].type)
{
type_found = true;
break;
}
}
if(type_found){
ALOGI_IF(log_level(DBG_INFO),"BP: Main screen type %d be found",type);
w = base_parameter.main.screen_list[i].resolution.hdisplay;
h = base_parameter.main.screen_list[i].resolution.vdisplay;
vsync_start = base_parameter.main.screen_list[i].resolution.vsync_start;
hsync_start = base_parameter.main.screen_list[i].resolution.hsync_start;
hsync_end = base_parameter.main.screen_list[i].resolution.hsync_end;
htotal = base_parameter.main.screen_list[i].resolution.htotal;
vsync_end = base_parameter.main.screen_list[i].resolution.vsync_end;
vtotal = base_parameter.main.screen_list[i].resolution.vtotal;
flags = base_parameter.main.screen_list[i].resolution.flags;
clock = base_parameter.main.screen_list[i].resolution.clock;
}else{
ALOGI_IF(log_level(DBG_INFO),"BP: Main screen type %d not found,to use Auto",type);
}
if(flags & DRM_MODE_FLAG_INTERLACE){
vfresh = (float)clock / (htotal*vtotal) * 2;
}else{
vfresh = (float)clock / (htotal*vtotal);
}
if(vfresh < 1)
vfresh = vfresh * 1000;
if( !type_found || base_parameter.main.screen_list[i].feature & RESOLUTION_AUTO ||
w * h <= 0 || w * h > 4096 * 2160 ){
strcpy(parameter,"Auto");
property_set("persist." PROPERTY_TYPE ".resolution.main",parameter);
ALOGI_IF(log_level(DBG_INFO),"BP: resolution main %s",parameter);
}else{
sprintf(parameter,"%dx%d@%f-%d-%d-%d-%d-%d-%d-%x", w, h, vfresh, hsync_start,hsync_end,\
htotal,vsync_start,vsync_end,vtotal, flags);
property_set("persist." PROPERTY_TYPE ".resolution.main",parameter);
ALOGI_IF(log_level(DBG_INFO),"BP: resolution main %s \n",parameter);
}
}else{
int i = 0;
bool type_found = false;
for( i = 0 ; i < 5 ; i++)
{
if(type == base_parameter.aux.screen_list[i].type)
{
type_found = true;
break;
}
}
if(type_found){
ALOGI_IF(log_level(DBG_INFO),"BP: Aux screen type %d found",type);
w = base_parameter.aux.screen_list[i].resolution.hdisplay;
h = base_parameter.aux.screen_list[i].resolution.vdisplay;
vsync_start = base_parameter.aux.screen_list[i].resolution.vsync_start;
hsync_start = base_parameter.aux.screen_list[i].resolution.hsync_start;
hsync_end = base_parameter.aux.screen_list[i].resolution.hsync_end;
htotal = base_parameter.aux.screen_list[i].resolution.htotal;
vsync_end = base_parameter.aux.screen_list[i].resolution.vsync_end;
vtotal = base_parameter.aux.screen_list[i].resolution.vtotal;
flags = base_parameter.aux.screen_list[i].resolution.flags;
clock = base_parameter.aux.screen_list[i].resolution.clock;
}else{
ALOGI_IF(log_level(DBG_INFO),"BP: Aux screen type %d not found,to use Auto",type);
}
if(flags & DRM_MODE_FLAG_INTERLACE){
vfresh = (float)clock / (htotal*vtotal) * 2;
}else{
vfresh = (float)clock / (htotal*vtotal);
}
if(vfresh < 1)
vfresh = vfresh*1000;
if( !type_found || base_parameter.aux.screen_list[i].feature & RESOLUTION_AUTO ||
w * h <= 0 || w * h > 4096 * 2160 ){
strcpy(parameter,"Auto");
property_set("persist." PROPERTY_TYPE ".resolution.aux",parameter);
ALOGI_IF(log_level(DBG_INFO),"BP: resolution aux %s",parameter);
}else{
sprintf(parameter,"%dx%d@%f-%d-%d-%d-%d-%d-%d-%x", w, h, vfresh, hsync_start,hsync_end,\
htotal,vsync_start,vsync_end,vtotal, flags);
property_set("persist." PROPERTY_TYPE ".resolution.aux",parameter);
ALOGI_IF(log_level(DBG_INFO),"BP: resolution aux %s \n",parameter);
}
}
break;
}
case BP_FB_SIZE:
{
if(enableBaseparameter == false)
{
ALOGW("BP: FB_SIZE baseparameter is not ready,can't use it !");
return -1;
}
if(display == HWC_DISPLAY_PRIMARY){
w = base_parameter.main.hwc_info.framebuffer_width;
h = base_parameter.main.hwc_info.framebuffer_height;
vfresh = base_parameter.main.hwc_info.fps;
if( w * h > 0 && w * h <= 4096 * 2160 && vfresh > 0 &&
vfresh <= 120){
sprintf(parameter,"%dx%d@%f", w, h, vfresh);
property_set("persist." PROPERTY_TYPE ".framebuffer.main",parameter);
ALOGI_IF(log_level(DBG_INFO),"BP:main %s \n",parameter);
}else{
#ifdef RK_BOX
strcpy(parameter,"1920x1080@60");
ALOGI_IF(log_level(DBG_INFO),"BP:main fb_size default %s \n",parameter);
property_set("persist." PROPERTY_TYPE ".framebuffer.main",parameter);
#else
ALOGI_IF(log_level(DBG_INFO),"BP:main fb_size=%dx%d@%f err,set 0x0@60",w,h,vfresh);
property_set("persist." PROPERTY_TYPE ".framebuffer.main","0x0@60");
#endif
}
}else{
w = base_parameter.aux.hwc_info.framebuffer_width;
h = base_parameter.aux.hwc_info.framebuffer_height;
vfresh = base_parameter.aux.hwc_info.fps;
if( w * h > 0 && w * h <= 4096 * 2160 && vfresh > 0 &&
vfresh <= 120){
sprintf(parameter,"%dx%d@%f", w, h, vfresh);
property_set("persist." PROPERTY_TYPE ".framebuffer.aux",parameter);
ALOGI_IF(log_level(DBG_INFO),"BP:aux %s \n",parameter);
}else{
#ifdef RK_BOX
strcpy(parameter,"1920x1080@60");
ALOGI_IF(log_level(DBG_INFO),"BP:aux fb_size default %s \n",parameter);
property_set("persist." PROPERTY_TYPE ".framebuffer.aux",parameter);
#else
ALOGI_IF(log_level(DBG_INFO),"BP:aux fb_size=%dx%d@%f err,set 0x0@60",w,h,vfresh);
property_set("persist." PROPERTY_TYPE ".framebuffer.aux","0x0@60");
#endif
}
}
break;
}
case BP_DEVICE:
{
if(enableBaseparameter == false)
{
ALOGW("BP: DEVICE baseparameter is not ready,can't use it !");
return -1;
}
if( display == HWC_DISPLAY_PRIMARY ){
strcpy(parameter,base_parameter.main.hwc_info.device);
ALOGI_IF(log_level(DBG_INFO),"BP: dev_primary = %s",parameter);
}else{
strcpy(parameter,base_parameter.aux.hwc_info.device);
ALOGI_IF(log_level(DBG_INFO),"BP: dev_extend = %s",parameter);
}
break;
}
case BP_BRIGHTNESS:
if(display == HWC_DISPLAY_PRIMARY){
brightness = base_parameter.main.bcsh.brightness;
if(!(bcsh_flag & 0x1) && enableBaseparameter){
bcsh_flag |= 0x1;
sprintf(value_new,"%d",(brightness > 0 && brightness <= 100 ? brightness : 50));
property_set("persist." PROPERTY_TYPE ".brightness.main",value_new);
ALOGI_IF(log_level(DBG_INFO),"BP: first set main brightness: %s",value_new);
}
ALOGI_IF(log_level(DBG_INFO),"BP: main brightness %d",property_get_int32("persist." PROPERTY_TYPE ".brightness.main",
brightness > 0 && brightness <= 100 ? brightness : 50));
return property_get_int32("persist." PROPERTY_TYPE ".brightness.main",
brightness > 0 && brightness <= 100 ? brightness : 50);
}else{
brightness = base_parameter.aux.bcsh.brightness;
if(!(bcsh_flag & 0x10) && enableBaseparameter){
bcsh_flag |= 0x10;
sprintf(value_new,"%d",(brightness > 0 && brightness <= 100 ? brightness : 50));
property_set("persist." PROPERTY_TYPE ".brightness.aux",value_new);
ALOGI_IF(log_level(DBG_INFO),"BP: first set aux brightness: %s",value_new);
}
ALOGI_IF(log_level(DBG_INFO),"BP: aux brightness %d",property_get_int32("persist." PROPERTY_TYPE ".brightness.aux",
brightness > 0 && brightness <= 100 ? brightness : 50));
return property_get_int32("persist." PROPERTY_TYPE ".brightness.aux",
brightness > 0 && brightness <= 100 ? brightness : 50);
}
break;
case BP_CONTRAST:
if(display == HWC_DISPLAY_PRIMARY){
contrast = base_parameter.main.bcsh.contrast;
if(!(bcsh_flag & 0x2) && enableBaseparameter){
bcsh_flag |= 0x2;
sprintf(value_new,"%d",(contrast > 0 && contrast <= 100 ? contrast : 50));
property_set("persist." PROPERTY_TYPE ".contrast.main",value_new);
ALOGI_IF(log_level(DBG_INFO),"BP: first set main contrast: %s",value_new);
}
ALOGI_IF(log_level(DBG_INFO),"BP: main contrast %d",property_get_int32("persist." PROPERTY_TYPE ".contrast.main",
contrast > 0 && contrast <=100 ? contrast : 50));
return property_get_int32("persist." PROPERTY_TYPE ".contrast.main",
contrast > 0 && contrast <=100 ? contrast : 50);
}else{
contrast = base_parameter.aux.bcsh.contrast;
if(!(bcsh_flag & 0x20) && enableBaseparameter){
bcsh_flag |= 0x20;
sprintf(value_new,"%d",(contrast > 0 && contrast <= 100 ? contrast : 50));
property_set("persist." PROPERTY_TYPE ".contrast.aux",value_new);
ALOGI_IF(log_level(DBG_INFO),"BP: first set aux contrast: %s",value_new);
}
ALOGI_IF(log_level(DBG_INFO),"BP: aux contrast %d",property_get_int32("persist." PROPERTY_TYPE ".contrast.aux",
contrast > 0 && contrast <= 100 ? contrast : 50));
return property_get_int32("persist." PROPERTY_TYPE ".contrast.aux",
contrast > 0 && contrast <= 100 ? contrast : 50);
}
break;
case BP_SATURATION:
if(display == HWC_DISPLAY_PRIMARY){
saturation = base_parameter.main.bcsh.saturation;
if(!(bcsh_flag & 0x4) && enableBaseparameter){
bcsh_flag |= 0x4;
sprintf(value_new,"%d",(saturation > 0 && saturation <= 100 ? saturation : 50));
property_set("persist." PROPERTY_TYPE ".saturation.main",value_new);
ALOGI_IF(log_level(DBG_INFO),"BP: first set main saturation: %s",value_new);
}
ALOGI_IF(log_level(DBG_INFO),"BP: main saturation %d",property_get_int32("persist." PROPERTY_TYPE ".saturation.main",
saturation > 0 && saturation <= 100 ? saturation : 50));
return property_get_int32("persist." PROPERTY_TYPE ".saturation.main",
saturation > 0 && saturation <= 100 ? saturation : 50);
}else{
saturation = base_parameter.aux.bcsh.saturation;
if(!(bcsh_flag & 0x40) && enableBaseparameter){
bcsh_flag |= 0x40;
sprintf(value_new,"%d",(saturation > 0 && saturation <= 100 ? saturation : 50));
property_set("persist." PROPERTY_TYPE ".saturation.aux",value_new);
ALOGI_IF(log_level(DBG_INFO),"BP: first set aux saturation: %s",value_new);
}
ALOGI_IF(log_level(DBG_INFO),"BP: aux saturation %d",property_get_int32("persist." PROPERTY_TYPE ".saturation.aux",
saturation > 0 && saturation <= 100 ? saturation : 50));
return property_get_int32("persist." PROPERTY_TYPE ".saturation.aux",
saturation > 0 && saturation <= 100 ? saturation : 50);
}
break;
case BP_HUE:
if(display == HWC_DISPLAY_PRIMARY){
hue = base_parameter.main.bcsh.hue;
if(!(bcsh_flag & 0x8) && enableBaseparameter){
bcsh_flag |= 0x8;
sprintf(value_new,"%d",(hue > 0 && hue <= 100 ? hue : 50));
property_set("persist." PROPERTY_TYPE ".hue.main",value_new);
ALOGI_IF(log_level(DBG_INFO),"BP: first set main hue: %s",value_new);
}
ALOGI_IF(log_level(DBG_INFO),"BP: main hue %d",property_get_int32("persist." PROPERTY_TYPE ".hue.main",
hue > 0 && hue <= 100 ? hue : 50));
return property_get_int32("persist." PROPERTY_TYPE ".hue.main",
hue > 0 && hue <= 100 ? hue : 50);
}else{
hue = base_parameter.aux.bcsh.hue;
if(!(bcsh_flag & 0x80) && enableBaseparameter){
bcsh_flag |= 0x80;
sprintf(value_new,"%d",(hue > 0 && hue <= 100 ? hue : 50));
property_set("persist." PROPERTY_TYPE ".hue.aux",value_new);
ALOGI_IF(log_level(DBG_INFO),"BP: first set aux hue: %s",value_new);
}
ALOGI_IF(log_level(DBG_INFO),"BP: aux hue %d",property_get_int32("persist." PROPERTY_TYPE ".hue.aux",
hue > 0 && hue <= 100 ? hue : 50));
return property_get_int32("persist." PROPERTY_TYPE ".hue.aux",
hue > 0 && hue <= 100 ? hue : 50);
}
break;
case BP_COLOR:
if(display == HWC_DISPLAY_PRIMARY){
int i = 0;
bool type_found = false;
for( i = 0 ; i < SCREEN_LIST_MAX ; i++ )
{
if(type == base_parameter.main.screen_list[i].type)
{
type_found = true;
break;
}
}
if(type_found)
{
ALOGW("BP: Main screen type %d found",type);
format = base_parameter.main.screen_list[i].format;
depthc = base_parameter.main.screen_list[i].depthc;
}else{
ALOGW("BP: Main screen type %d not found,to use default color",type);
}
res = hwc_parse_format_into_prop(display,format,depthc);
if( !type_found || base_parameter.main.screen_list[i].feature & COLOR_AUTO || res){
//Auto:output_ycbcr_high_subsampling - Automatic
hwc_parse_format_into_prop(display,4,0);
strcpy(parameter,"4-0");
}else{
sprintf(parameter,"%u-%u",format,depthc);
}
ALOGI_IF(log_level(DBG_INFO),"BP: main color %s",parameter);
}else{
int i = 0;
bool type_found = false;
for( i = 0 ; i < SCREEN_LIST_MAX ; i++ )
{
if(type == base_parameter.aux.screen_list[i].type)
{
type_found = true;
break;
}
}
if(type_found)
{
ALOGW("BP: Aux screen type %d found",type);
format = base_parameter.aux.screen_list[i].format;
depthc = base_parameter.aux.screen_list[i].depthc;
}else{
ALOGW("BP: Aux screen type %d not found,to use default color",type);
}
res = hwc_parse_format_into_prop(display,format,depthc);
if(!type_found || base_parameter.aux.screen_list[i].feature & COLOR_AUTO || res ){
//Auto:output_ycbcr_high_subsampling - Automatic
hwc_parse_format_into_prop(display,4,0);
strcpy(parameter,"4-0");
}else{
sprintf(parameter,"%u-%u",format,depthc);
}
ALOGI_IF(log_level(DBG_INFO),"BP: aux color %s",parameter);
}
break;
case BP_OVERSCAN:
if(display == HWC_DISPLAY_PRIMARY){
leftscale = base_parameter.main.scan.leftscale;
topscale = base_parameter.main.scan.topscale;
rightscale = base_parameter.main.scan.rightscale;
bottomscale = base_parameter.main.scan.bottomscale;
sprintf(parameter,"overscan %d,%d,%d,%d",
leftscale > 0 && leftscale <= 100 ? leftscale : 100,
topscale > 0 && topscale <= 100 ? topscale : 100,
rightscale > 0 && rightscale <= 100 ? rightscale : 100,
bottomscale > 0 && bottomscale <= 100 ? bottomscale : 100);
property_set("persist." PROPERTY_TYPE ".overscan.main",parameter);
ALOGI_IF(log_level(DBG_INFO),"BP: main overscan %s",parameter);
}else{
leftscale = base_parameter.aux.scan.leftscale;
topscale = base_parameter.aux.scan.topscale;
rightscale = base_parameter.aux.scan.rightscale;
bottomscale = base_parameter.aux.scan.bottomscale;
sprintf(parameter,"overscan %d,%d,%d,%d",
leftscale > 0 && leftscale <= 100 ? leftscale : 100,
topscale > 0 && topscale <= 100 ? topscale : 100,
rightscale > 0 && rightscale <= 100 ? rightscale : 100,
bottomscale > 0 && bottomscale <= 100 ? bottomscale : 100);
property_set("persist." PROPERTY_TYPE ".overscan.aux",parameter);
ALOGI_IF(log_level(DBG_INFO),"BP: aux overscan %s",parameter);
}
break;
default:
ALOGW("BP:The flag is error ,check it !");
return -1;
}
return 0;
}
void hwc_set_baseparameter_config(DrmResources *drm)
{
char save_comfig[PROPERTY_VALUE_MAX];
property_get("persist." PROPERTY_TYPE ".saveconfig",save_comfig,"0");
if(atoi(save_comfig))
{
char buf[256];
bool isMainHdmiConnected = false;
bool isAuxHdmiConnected = false;
int foundMainIdx = -1, foundAuxIdx = -1;
DrmConnector* primary = drm->GetConnectorFromType(HWC_DISPLAY_PRIMARY);
DrmConnector* extend = drm->GetConnectorFromType(HWC_DISPLAY_PRIMARY);
int file;
const char *baseparameterfile = hwc_get_baseparameter_file();
if (!baseparameterfile) {
ALOGW("BP: baseparamter file can not be find");
sync();
return;
}
file = open(baseparameterfile, O_RDWR);
if (file < 0) {
ALOGW("base paramter file can not be opened");
sync();
return;
}
if (primary != NULL) {
std::vector<DrmMode> mModes = primary->modes();
char resolution[PROPERTY_VALUE_MAX];
unsigned int w = 0,h = 0,hsync_start = 0,hsync_end = 0,htotal = 0;
unsigned int vsync_start = 0,vsync_end = 0,vtotal = 0,flags = 0;
float vfresh = 0.0000;
property_get("persist." PROPERTY_TYPE ".resolution.main", resolution, "0x0@0.00-0-0-0-0-0-0-0");
if (strncmp(resolution, "Auto", 4) != 0 && strncmp(resolution, "0x0p0-0", 7) !=0)
sscanf(resolution,"%dx%d@%f-%d-%d-%d-%d-%d-%d-%x", &w, &h, &vfresh, &hsync_start,&hsync_end,
&htotal,&vsync_start,&vsync_end, &vtotal, &flags);
for (size_t c = 0; c < mModes.size(); ++c){
const DrmMode& info = mModes[c];
char curDrmModeRefresh[16];
char curRefresh[16];
float mModeRefresh;
if (info.flags() & DRM_MODE_FLAG_INTERLACE)
mModeRefresh = info.clock() * 2 / (float)(info.v_total() * info.h_total()) * 1000.0f;
else
mModeRefresh = info.clock() / (float)(info.v_total() * info.h_total()) * 1000.0f;
sprintf(curDrmModeRefresh, "%.2f", mModeRefresh);
sprintf(curRefresh, "%.2f", vfresh);
if (info.h_display() == w &&
info.v_display() == h &&
info.h_sync_start() == hsync_start &&
info.h_sync_end() == hsync_end &&
info.h_total() == htotal &&
info.v_sync_start() == vsync_start &&
info.v_sync_end() == vsync_end &&
info.v_total() == vtotal &&
atof(curDrmModeRefresh) == atof(curRefresh)) {
foundMainIdx = c;
sprintf(buf, "display=%d,iface=%d,enable=%d,mode=%s\n",
primary->display(), primary->get_type(), primary->state(), resolution);
break;
}
}
}
if (extend != NULL) {
std::vector<DrmMode> mModes = extend->modes();
char resolution[PROPERTY_VALUE_MAX];
unsigned int w = 0,h = 0,hsync_start = 0,hsync_end = 0,htotal = 0;
unsigned int vsync_start = 0,vsync_end = 0,vtotal = 0,flags = 0;
float vfresh = 0;
property_get("persist." PROPERTY_TYPE ".resolution.aux", resolution, "0x0@0.00-0-0-0-0-0-0-0");
if (strncmp(resolution, "Auto", 4) != 0 && strncmp(resolution, "0x0p0-0", 7) !=0)
sscanf(resolution,"%dx%d@%f-%d-%d-%d-%d-%d-%d-%x", &w, &h, &vfresh, &hsync_start,&hsync_end,&htotal,&vsync_start,&vsync_end,
&vtotal, &flags);
for (size_t c = 0; c < mModes.size(); ++c){
const DrmMode& info = mModes[c];
char curDrmModeRefresh[16];
char curRefresh[16];
float mModeRefresh;
if (info.flags() & DRM_MODE_FLAG_INTERLACE)
mModeRefresh = info.clock() * 2 / (float)(info.v_total()* info.h_total()) * 1000.0f;
else
mModeRefresh = info.clock() / (float)(info.v_total()* info.h_total()) * 1000.0f;
sprintf(curDrmModeRefresh, "%.2f", mModeRefresh);
sprintf(curRefresh, "%.2f", vfresh);
if (info.h_display() == w &&
info.v_display() == h &&
info.h_sync_start() == hsync_start &&
info.h_sync_end() == hsync_end &&
info.h_total() == htotal &&
info.v_sync_start() == vsync_start &&
info.v_sync_end() == vsync_end &&
info.v_total() == vtotal &&
atof(curDrmModeRefresh) == atoi(curRefresh)) {
foundAuxIdx = c;
break;
}
}
}
for (auto &conn : drm->connectors()) {
if (conn->state() == DRM_MODE_CONNECTED
&& (conn->get_type() == DRM_MODE_CONNECTOR_HDMIA)
&& (conn->possible_displays() & HWC_DISPLAY_PRIMARY_BIT))
isMainHdmiConnected = true;
else if(conn->state() == DRM_MODE_CONNECTED
&& (conn->get_type() == DRM_MODE_CONNECTOR_HDMIA)
&& (conn->possible_displays() & HWC_DISPLAY_EXTERNAL_BIT))
isAuxHdmiConnected = true;
}
ALOGI_IF(log_level(DBG_INFO),"BP:nativeSaveConfig: size=%d isMainHdmiConnected=%d", (int)sizeof(base_parameter.main), isMainHdmiConnected);
for (auto &conn : drm->connectors()) {
if (conn->state() == DRM_MODE_CONNECTED
&& (conn->possible_displays() & HWC_DISPLAY_PRIMARY_BIT)) {
char property[PROPERTY_VALUE_MAX];
int w = 0, h = 0, hsync_start = 0, hsync_end = 0, htotal = 0;
int vsync_start = 0, vsync_end = 0, vtotal = 0,flags = 0;
int left = 0, top = 0, right = 0, bottom = 0;
float vfresh = 0;
int slot = hwc_findSuitableInfoSlot(&base_parameter.main, conn->get_type());
if (isMainHdmiConnected && conn->get_type() == DRM_MODE_CONNECTOR_TV)
continue;
base_parameter.main.screen_list[slot].type = conn->get_type();
base_parameter.main.screen_list[slot].feature &= AUTO_BIT_RESET;
property_get("persist." PROPERTY_TYPE ".resolution.main", property, "0x0@0.00-0-0-0-0-0-0-0");
if (strncmp(property, "Auto", 4) != 0 && strncmp(property, "0x0p0-0", 7) !=0) {
ALOGI_IF(log_level(DBG_INFO),"BP:saveConfig resolution = %s", property);
std::vector<DrmMode> mModes = primary->modes();
sscanf(property,"%dx%d@%f-%d-%d-%d-%d-%d-%d-%x", &w, &h, &vfresh, &hsync_start,&hsync_end,&htotal,&vsync_start,&vsync_end,
&vtotal, &flags);
ALOGI_IF(log_level(DBG_INFO),"BP:last base_parameter.main.resolution.hdisplay = %d, vdisplay=%d(%s@%f)",
base_parameter.main.screen_list[slot].resolution.hdisplay,
base_parameter.main.screen_list[slot].resolution.vdisplay,
base_parameter.main.hwc_info.device, base_parameter.main.hwc_info.fps);
base_parameter.main.screen_list[slot].resolution.hdisplay = w;
base_parameter.main.screen_list[slot].resolution.vdisplay = h;
base_parameter.main.screen_list[slot].resolution.hsync_start = hsync_start;
base_parameter.main.screen_list[slot].resolution.hsync_end = hsync_end;
if (foundMainIdx != -1)
base_parameter.main.screen_list[slot].resolution.clock = mModes[foundMainIdx].clock();
else if (flags & DRM_MODE_FLAG_INTERLACE)
base_parameter.main.screen_list[slot].resolution.clock = (htotal*vtotal*vfresh/2)/1000.0f;
else
base_parameter.main.screen_list[slot].resolution.clock = (htotal*vtotal*vfresh)/1000.0f;
base_parameter.main.screen_list[slot].resolution.htotal = htotal;
base_parameter.main.screen_list[slot].resolution.vsync_start = vsync_start;
base_parameter.main.screen_list[slot].resolution.vsync_end = vsync_end;
base_parameter.main.screen_list[slot].resolution.vtotal = vtotal;
base_parameter.main.screen_list[slot].resolution.flags = flags;
ALOGI_IF(log_level(DBG_INFO),"BP:saveBaseParameter foundMainIdx=%d clock=%d", foundMainIdx, base_parameter.main.screen_list[slot].resolution.clock);
} else {
base_parameter.main.screen_list[slot].feature|= RESOLUTION_AUTO;
memset(&base_parameter.main.screen_list[slot].resolution, 0, sizeof(base_parameter.main.screen_list[slot].resolution));
}
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".overscan.main", property, "overscan 100,100,100,100");
sscanf(property, "overscan %d,%d,%d,%d",
&left,
&top,
&right,
&bottom);
base_parameter.main.scan.leftscale = (unsigned short)left;
base_parameter.main.scan.topscale = (unsigned short)top;
base_parameter.main.scan.rightscale = (unsigned short)right;
base_parameter.main.scan.bottomscale = (unsigned short)bottom;
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".color.main", property, "Auto");
if (strncmp(property, "Auto", 4) != 0){
if (strstr(property, "RGB") != 0)
base_parameter.main.screen_list[slot].format = output_rgb;
else if (strstr(property, "YCBCR444") != 0)
base_parameter.main.screen_list[slot].format = output_ycbcr444;
else if (strstr(property, "YCBCR422") != 0)
base_parameter.main.screen_list[slot].format = output_ycbcr422;
else if (strstr(property, "YCBCR420") != 0)
base_parameter.main.screen_list[slot].format = output_ycbcr420;
else {
base_parameter.main.screen_list[slot].feature |= COLOR_AUTO;
base_parameter.main.screen_list[slot].format = output_ycbcr_high_subsampling;
}
if (strstr(property, "8bit") != NULL)
base_parameter.main.screen_list[slot].depthc = depth_24bit;
else if (strstr(property, "10bit") != NULL)
base_parameter.main.screen_list[slot].depthc = depth_30bit;
else
base_parameter.main.screen_list[slot].depthc = Automatic;
ALOGD("saveConfig: color=%d-%d", base_parameter.main.screen_list[slot].format, base_parameter.main.screen_list[slot].depthc);
} else {
base_parameter.main.screen_list[slot].depthc = Automatic;
base_parameter.main.screen_list[slot].format = output_ycbcr_high_subsampling;
base_parameter.main.screen_list[slot].feature |= COLOR_AUTO;
}
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".hdcp1x.main", property, "0");
if (atoi(property) > 0)
base_parameter.main.screen_list[slot].feature |= HDCP1X_EN;
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".resolution_white.main", property, "0");
if (atoi(property) > 0)
base_parameter.main.screen_list[slot].feature |= RESOLUTION_WHITE_EN;
hwc_save_BcshConfig(HWC_DISPLAY_PRIMARY_BIT);
} else if(conn->state() == DRM_MODE_CONNECTED
&& (conn->possible_displays() & HWC_DISPLAY_EXTERNAL_BIT)
&& (conn->encoder() != NULL)) {
char property[PROPERTY_VALUE_MAX];
int w = 0, h = 0, hsync_start = 0, hsync_end = 0, htotal = 0;
int vsync_start = 0, vsync_end = 0, vtotal = 0,flags = 0;
int left = 0, top = 0, right = 0, bottom = 0;
float vfresh = 0;
int slot = hwc_findSuitableInfoSlot(&base_parameter.aux, conn->get_type());
if (isAuxHdmiConnected && conn->get_type() == DRM_MODE_CONNECTOR_TV)
continue;
base_parameter.aux.screen_list[slot].type = conn->get_type();
base_parameter.aux.screen_list[slot].feature &= AUTO_BIT_RESET;
property_get("persist." PROPERTY_TYPE ".resolution.aux", property, "0x0p0-0");
if (strncmp(property, "Auto", 4) != 0 && strncmp(property, "0x0p0-0", 7) !=0) {
std::vector<DrmMode> mModes = extend->modes();
sscanf(property,"%dx%d@%f-%d-%d-%d-%d-%d-%d-%x", &w, &h, &vfresh, &hsync_start,&hsync_end,&htotal,&vsync_start,&vsync_end,
&vtotal, &flags);
base_parameter.aux.screen_list[slot].resolution.hdisplay = w;
base_parameter.aux.screen_list[slot].resolution.vdisplay = h;
if (foundMainIdx != -1)
base_parameter.aux.screen_list[slot].resolution.clock = mModes[foundMainIdx].clock();
else if (flags & DRM_MODE_FLAG_INTERLACE)
base_parameter.aux.screen_list[slot].resolution.clock = (htotal*vtotal*vfresh/2) / 1000.0f;
else
base_parameter.aux.screen_list[slot].resolution.clock = (htotal*vtotal*vfresh) / 1000.0f;
base_parameter.aux.screen_list[slot].resolution.hsync_start = hsync_start;
base_parameter.aux.screen_list[slot].resolution.hsync_end = hsync_end;
base_parameter.aux.screen_list[slot].resolution.htotal = htotal;
base_parameter.aux.screen_list[slot].resolution.vsync_start = vsync_start;
base_parameter.aux.screen_list[slot].resolution.vsync_end = vsync_end;
base_parameter.aux.screen_list[slot].resolution.vtotal = vtotal;
base_parameter.aux.screen_list[slot].resolution.flags = flags;
} else {
base_parameter.aux.screen_list[slot].feature |= RESOLUTION_AUTO;
memset(&base_parameter.aux.screen_list[slot].resolution, 0, sizeof(base_parameter.aux.screen_list[slot].resolution));
}
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".overscan.aux", property, "overscan 100,100,100,100");
sscanf(property, "overscan %d,%d,%d,%d",
&left,
&top,
&right,
&bottom);
base_parameter.aux.scan.leftscale = (unsigned short)left;
base_parameter.aux.scan.topscale = (unsigned short)top;
base_parameter.aux.scan.rightscale = (unsigned short)right;
base_parameter.aux.scan.bottomscale = (unsigned short)bottom;
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".color.aux", property, "Auto");
if (strncmp(property, "Auto", 4) != 0){
char color[16];
char depth[16];
sscanf(property, "%s-%s", color, depth);
if (strncmp(color, "RGB", 3) == 0)
base_parameter.aux.screen_list[slot].format = output_rgb;
else if (strncmp(color, "YCBCR444", 8) == 0)
base_parameter.aux.screen_list[slot].format = output_ycbcr444;
else if (strncmp(color, "YCBCR422", 8) == 0)
base_parameter.aux.screen_list[slot].format = output_ycbcr422;
else if (strncmp(color, "YCBCR420", 8) == 0)
base_parameter.aux.screen_list[slot].format = output_ycbcr420;
else {
base_parameter.aux.screen_list[slot].feature |= COLOR_AUTO;
base_parameter.aux.screen_list[slot].format = output_ycbcr_high_subsampling;
}
if (strncmp(depth, "8bit", 4) == 0)
base_parameter.aux.screen_list[slot].depthc = depth_24bit;
else if (strncmp(depth, "10bit", 5) == 0)
base_parameter.aux.screen_list[slot].depthc = depth_30bit;
else
base_parameter.aux.screen_list[slot].depthc = Automatic;
} else {
base_parameter.aux.screen_list[slot].feature |= COLOR_AUTO;
base_parameter.aux.screen_list[slot].depthc = Automatic;
base_parameter.aux.screen_list[slot].format = output_ycbcr_high_subsampling;
}
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".hdcp1x.aux", property, "0");
if (atoi(property) > 0)
base_parameter.aux.screen_list[slot].feature |= HDCP1X_EN;
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".resolution_white.aux", property, "0");
if (atoi(property) > 0)
base_parameter.aux.screen_list[slot].feature |= RESOLUTION_WHITE_EN;
/*add for BCSH*/
hwc_save_BcshConfig(HWC_DISPLAY_EXTERNAL_BIT);
}
}
lseek(file, 0L, SEEK_SET);
write(file, (char*)(&base_parameter.main), sizeof(base_parameter.main));
lseek(file, BASE_OFFSET, SEEK_SET);
write(file, (char*)(&base_parameter.aux), sizeof(base_parameter.aux));
close(file);
sync();
}
return ;
}
void hwc_save_BcshConfig(int dpy){
if (dpy == HWC_DISPLAY_PRIMARY_BIT){
char property[PROPERTY_VALUE_MAX];
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".brightness.main", property, "0");
if (atoi(property) > 0)
base_parameter.main.bcsh.brightness = atoi(property);
else
base_parameter.main.bcsh.brightness = DEFAULT_BRIGHTNESS;
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".contrast.main", property, "0");
if (atoi(property) > 0)
base_parameter.main.bcsh.contrast = atoi(property);
else
base_parameter.main.bcsh.contrast = DEFAULT_CONTRAST;
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".saturation.main", property, "0");
if (atoi(property) > 0)
base_parameter.main.bcsh.saturation = atoi(property);
else
base_parameter.main.bcsh.saturation = DEFAULT_SATURATION;
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".hue.main", property, "0");
if (atoi(property) > 0)
base_parameter.main.bcsh.hue = atoi(property);
else
base_parameter.main.bcsh.hue = DEFAULT_HUE;
} else {
char property[PROPERTY_VALUE_MAX];
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".brightness.aux", property, "0");
if (atoi(property) > 0)
base_parameter.aux.bcsh.brightness = atoi(property);
else
base_parameter.aux.bcsh.brightness = DEFAULT_BRIGHTNESS;
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".contrast.aux", property, "0");
if (atoi(property) > 0)
base_parameter.aux.bcsh.contrast = atoi(property);
else
base_parameter.aux.bcsh.contrast = DEFAULT_CONTRAST;
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".saturation.aux", property, "0");
if (atoi(property) > 0)
base_parameter.aux.bcsh.saturation = atoi(property);
else
base_parameter.aux.bcsh.saturation = DEFAULT_SATURATION;
memset(property,0,sizeof(property));
property_get("persist." PROPERTY_TYPE ".hue.aux", property, "0");
if (atoi(property) > 0)
base_parameter.aux.bcsh.hue = atoi(property);
else
base_parameter.aux.bcsh.hue = DEFAULT_HUE;
}
}
int hwc_findSuitableInfoSlot(struct disp_info* info, int type)
{
int found=0;
for (int i=0;i<5;i++) {
if (info->screen_list[i].type !=0 && info->screen_list[i].type == type) {
found = i;
break;
} else if (info->screen_list[i].type !=0 && found == false){
found++;
}
}
if (found == -1) {
found = 0;
ALOGI_IF(log_level(DBG_INFO),"BP:noting saved, used the first slot");
}
ALOGI_IF(log_level(DBG_INFO),"BP:findSuitableInfoSlot: %d type=%d", found, type);
return found;
}
int hwc_parse_format_into_prop(int display,unsigned int format,unsigned int depthc) {
if(display == HWC_DISPLAY_PRIMARY){
if (format == DRM_HDMI_OUTPUT_YCBCR_HQ &&
depthc == ROCKCHIP_DEPTH_DEFAULT) {
property_set("persist." PROPERTY_TYPE ".color.main","Auto");
return 0;
}
if (format == DRM_HDMI_OUTPUT_DEFAULT_RGB &&
depthc == ROCKCHIP_HDMI_DEPTH_8) {
property_set("persist." PROPERTY_TYPE ".color.main","RGB-8bit");
return 0;
}
if (format == DRM_HDMI_OUTPUT_DEFAULT_RGB &&
depthc == ROCKCHIP_HDMI_DEPTH_10) {
property_set("persist." PROPERTY_TYPE ".color.main","RGB-10bit");
return 0;
}
if (format == DRM_HDMI_OUTPUT_YCBCR444 &&
depthc == ROCKCHIP_HDMI_DEPTH_8) {
property_set("persist." PROPERTY_TYPE ".color.main","YCBCR444-8bit");
return 0;
}
if (format == DRM_HDMI_OUTPUT_YCBCR444 &&
depthc == ROCKCHIP_HDMI_DEPTH_10) {
property_set("persist." PROPERTY_TYPE ".color.main","YCBCR444-10bit");
return 0;
}
if (format == DRM_HDMI_OUTPUT_YCBCR422 &&
depthc == ROCKCHIP_HDMI_DEPTH_8) {
property_set("persist." PROPERTY_TYPE ".color.main","YCBCR422-8bit");
return 0;
}
if (format == DRM_HDMI_OUTPUT_YCBCR422 &&
depthc == ROCKCHIP_HDMI_DEPTH_10) {
property_set("persist." PROPERTY_TYPE ".color.main","YCBCR422-10bit");
return 0;
}
if (format == DRM_HDMI_OUTPUT_YCBCR420 &&
depthc == ROCKCHIP_HDMI_DEPTH_8) {
property_set("persist." PROPERTY_TYPE ".color.main","YCBCR420-8bit");
return 0;
}
if (format == DRM_HDMI_OUTPUT_YCBCR420 &&
depthc == ROCKCHIP_HDMI_DEPTH_10) {
property_set("persist." PROPERTY_TYPE ".color.main","YCBCR420-10bit");
return 0;
}
}else{
if (format == DRM_HDMI_OUTPUT_YCBCR_HQ &&
depthc == ROCKCHIP_DEPTH_DEFAULT) {
property_set("persist." PROPERTY_TYPE ".color.aux","Auto");
return 0;
}
if (format == DRM_HDMI_OUTPUT_DEFAULT_RGB &&
depthc == ROCKCHIP_HDMI_DEPTH_8) {
property_set("persist." PROPERTY_TYPE ".color.aux","RGB-8bit");
return 0;
}
if (format == DRM_HDMI_OUTPUT_DEFAULT_RGB &&
depthc == ROCKCHIP_HDMI_DEPTH_10) {
property_set("persist." PROPERTY_TYPE ".color.aux","RGB-10bit");
return 0;
}
if (format == DRM_HDMI_OUTPUT_YCBCR444 &&
depthc == ROCKCHIP_HDMI_DEPTH_8) {
property_set("persist." PROPERTY_TYPE ".color.aux","YCBCR444-8bit");
return 0;
}
if (format == DRM_HDMI_OUTPUT_YCBCR444 &&
depthc == ROCKCHIP_HDMI_DEPTH_10) {
property_set("persist." PROPERTY_TYPE ".color.aux","YCBCR444-10bit");
return 0;
}
if (format == DRM_HDMI_OUTPUT_YCBCR422 &&
depthc == ROCKCHIP_HDMI_DEPTH_8) {
property_set("persist." PROPERTY_TYPE ".color.aux","YCBCR422-8bit");
return 0;
}
if (format == DRM_HDMI_OUTPUT_YCBCR422 &&
depthc == ROCKCHIP_HDMI_DEPTH_10) {
property_set("persist." PROPERTY_TYPE ".color.aux","YCBCR422-10bit");
return 0;
}
if (format == DRM_HDMI_OUTPUT_YCBCR420 &&
depthc == ROCKCHIP_HDMI_DEPTH_8) {
property_set("persist." PROPERTY_TYPE ".color.aux","YCBCR420-8bit");
return 0;
}
if (format == DRM_HDMI_OUTPUT_YCBCR420 &&
depthc == ROCKCHIP_HDMI_DEPTH_10) {
property_set("persist." PROPERTY_TYPE ".color.aux","YCBCR420-10bit");
return 0;
}
}
ALOGI_IF(log_level(DBG_INFO),"BP: baseparameter color is invalid.");
return -1;
}
bool hwc_video_to_area(DrmHwcRect<float> &source_yuv,DrmHwcRect<int> &display_yuv,int scaleMode){
float s_letf, s_top, s_right, s_bottom;
float s_width,s_height;
int d_letf, d_top, d_right, d_bottom;
int d_width,d_height;
s_letf = source_yuv.left;
s_top = source_yuv.top;
s_right = source_yuv.right;
s_bottom = source_yuv.bottom;
s_width = s_right - s_letf;
s_height = s_bottom - s_top;
d_letf = display_yuv.left;
d_top = display_yuv.top;
d_right = display_yuv.right;
d_bottom = display_yuv.bottom;
d_width = d_right - d_letf;
d_height = d_bottom - d_top;
switch (scaleMode){
case VIDEO_SCALE_AUTO_SCALE :
if(s_width * d_height > s_height * d_width){
d_top += ( d_height - s_height * d_width / s_width ) / 2;
d_bottom -= ( d_height - s_height * d_width / s_width ) / 2;
}else{
d_letf += ( d_width - s_width * d_height / s_height) / 2;
d_right -= ( d_width - s_width * d_height / s_height) / 2;
}
break;
case VIDEO_SCALE_4_3_SCALE :
if(4 * d_height < 3 * d_width){
d_letf += (d_width - d_height * 4 / 3) / 2;
d_right -= (d_width - d_height * 4 / 3) / 2;
}else if(4 * d_height > 3 * d_width){
d_top += (d_height - d_width * 3 / 4) / 2;
d_bottom -= (d_height - d_width * 3 / 4) / 2;
}
break;
case VIDEO_SCALE_16_9_SCALE :
if(16 * d_height < 9 * d_width){
d_letf += (d_width - d_height * 16 / 9) / 2;
d_right -= (d_width - d_height * 16 / 9) / 2;
}else if(16 * d_height > 9 * d_width){
d_top += (d_width - d_width * 9 / 16) / 2;
d_bottom -= (d_width - d_width * 9 / 16) / 2;
}
break;
case VIDEO_SCALE_ORIGINAL :
if(s_width > d_width){
d_letf = 0;
//d_right = d_right;
}else{
d_letf = (d_width - s_width) / 2;
d_right -= (d_width - s_width) / 2;
}
if(s_height > d_height){
d_top = 0;
//d_bottom = d_bottom;
}else{
d_top = (d_height - s_height) / 2;
d_bottom -= (d_height - s_height ) / 2;
}
break;
default :
ALOGE("ScaleMode[%d] is invalid ",scaleMode);
return false;
}
ALOGD_IF(log_level(DBG_VERBOSE),"Video area change [%d,%d,%d,%d]:[%d,%d,%d,%d] => [%d,%d,%d,%d]",
(int)source_yuv.left,(int)source_yuv.top,(int)source_yuv.right,(int)source_yuv.bottom,
display_yuv.left,display_yuv.top,display_yuv.right,display_yuv.bottom,
d_letf,d_top,d_right,d_bottom);
display_yuv.left = d_letf;
display_yuv.top = d_top;
display_yuv.right = d_right;
display_yuv.bottom = d_bottom;
return true;
}
int hwc_SetGamma(DrmResources *drm)
{
int ret = -1;
if(hwc_have_baseparameter()){
DrmConnector *primary = drm->GetConnectorFromType(HWC_DISPLAY_PRIMARY);
if (primary != NULL && primary->state() == DRM_MODE_CONNECTED) {
int size = base_parameter.main.mlutdata.size;
if(size > 0){
uint16_t* red = (uint16_t*)malloc(size*sizeof(uint16_t));
uint16_t* green = (uint16_t*)malloc(size*sizeof(uint16_t));
uint16_t* blue = (uint16_t*)malloc(size*sizeof(uint16_t));
for (int i = 0; i < size; i++) {
red[i] = base_parameter.main.mlutdata.lred[i];
}
for (int i = 0; i < size; i++) {
green[i] = base_parameter.main.mlutdata.lgreen[i];
}
for (int i = 0; i < size; i++) {
blue[i] = base_parameter.main.mlutdata.lblue[i];
}
if (hwc_isGammaSetEnable(primary->get_type())) {
DrmCrtc *crtc = drm->GetCrtcFromConnector(primary);
if(crtc != NULL){
int mCurCrtcId = crtc->id();
ret = hwc_setGamma(drm->fd(), mCurCrtcId, (int)size, (uint16_t*)red, (uint16_t*)green, (uint16_t*)blue);
if (ret<0){
ALOGW("BP: nativeSetGamma failed: Primary size=%d r[%d %d] rgb_size= %d %d %d red[%d %d]", size,
red[0],red[1],size, size, size ,red[0], red[1]);
}else{
ALOGI_IF(log_level(DBG_INFO),"BP: nativeSetGamma success: Primary size=%d r[%d %d] rgb_size= %d %d %d red[%d %d]", size,
red[0],red[1],size, size, size ,red[0], red[1]);
}
}else{
ALOGW("BP: nativeSetGamma failed: Primary crtc is NULL");
}
}else{
ALOGW("BP: Device type %d is not supprot Gamma",primary->get_type());
}
free(red);
free(green);
free(blue);
red = NULL;
green = NULL;
blue = NULL;
}else{
ALOGW("BP: Gamma size = %d is err",size);
}
}
DrmConnector *extend = drm->GetConnectorFromType(HWC_DISPLAY_EXTERNAL);
if(extend != NULL && extend->state() == DRM_MODE_CONNECTED){
int size = base_parameter.aux.mlutdata.size;
if(size > 0){
uint16_t* red = (uint16_t*)malloc(size*sizeof(uint16_t));
uint16_t* green = (uint16_t*)malloc(size*sizeof(uint16_t));
uint16_t* blue = (uint16_t*)malloc(size*sizeof(uint16_t));
for (int i = 0; i < size; i++) {
red[i] = base_parameter.aux.mlutdata.lred[i];
}
for (int i = 0; i < size; i++) {
green[i] = base_parameter.aux.mlutdata.lgreen[i];
}
for (int i = 0; i < size; i++) {
blue[i] = base_parameter.aux.mlutdata.lblue[i];
}
if (hwc_isGammaSetEnable(extend->get_type())) {
DrmCrtc *crtc = drm->GetCrtcFromConnector(extend);
if(crtc != NULL){
int mCurCrtcId = crtc->id();
ret = hwc_setGamma(drm->fd(), mCurCrtcId, (int)size, (uint16_t*)red, (uint16_t*)green, (uint16_t*)blue);
if (ret<0){
ALOGW("BP: nativeSetGamma failed: Extend size=%d r[%d %d] rgb_size= %d %d %d red[%d %d]",size,
red[0],red[1],size, size, size ,red[0], red[1]);
}else{
ALOGI_IF(log_level(DBG_INFO),"BP: nativeSetGamma success: Extend size=%d r[%d %d] rgb_size= %d %d %d red[%d %d]", size,
red[0],red[1],size, size, size ,red[0], red[1]);
}
}else{
ALOGW("BP: nativeSetGamma failed: Extend crtc is NULL");
}
}else{
ALOGW("BP: Device type %d is not supprot Gamma",extend->get_type());
}
free(red);
free(green);
free(blue);
red = NULL;
green = NULL;
blue = NULL;
}else{
ALOGW("BP: Gamma size = %d is err",size);
}
}
}
return ret;
}
bool hwc_isGammaSetEnable(int type) {
return type == DRM_MODE_CONNECTOR_eDP || type == DRM_MODE_CONNECTOR_LVDS ||
type == DRM_MODE_CONNECTOR_DSI || type == DRM_MODE_CONNECTOR_DPI;
}
int hwc_setGamma(int fd, uint32_t crtc_id, uint32_t size,
uint16_t *red, uint16_t *green, uint16_t *blue)
{
int ret = drmModeCrtcSetGamma(fd, crtc_id, size, red, green, blue);
if (ret < 0)
ALOGE("fail to SetGamma %d(%s)", ret, strerror(errno));
return ret;
}
}