android_hardware_aw/hwc/tulip/hwc_mem_ctrl.cpp
2019-04-02 13:08:18 +01:00

352 lines
11 KiB
C++
Executable file

/*
* Copyright (C) Allwinner Tech All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "hwc.h"
AssignDUETO_T calculate_memthruput(HwcDisContext_t *Localctx, layer_info_t *hwLayer,
float WscalFac, float HscaleFac, int channel, bool isFB, bool isvideo)
{
int memoflayer = 0, whilecnt = 0, fb_mem = 0, need_mem = 0;
SUNXI_hwcdev_context_t *Globctx = &gSunxiHwcDevice;
hwc_layer_1_t *psLayer = hwLayer->psLayer;
ChannelInfo_t *channelinfo;
hwc_rect_t rectx = {0,0,0,0};
hwc_rect_t rectx2 = {0,0,0,0};
hwc_rect_t *psdiplay = &psLayer->displayFrame;
int prememvideo;
prememvideo = Localctx->prememvideo;
channelinfo = &Localctx->ChannelInfo[channel];
if(check_swap_w_h(psLayer->transform))
{
float tmp = WscalFac;
WscalFac = HscaleFac;
HscaleFac = tmp;
}
memoflayer = (psdiplay->right - psdiplay->left) /WscalFac
* (psdiplay->bottom - psdiplay->top) / HscaleFac
* hwLayer->form_info.bpp / 8;
/*here is a round count,the channel has a same scalefactor,so is ok*/
if(check_3d_video(Localctx->psDisplayInfo, psLayer))
{
memoflayer *= 2;
}
if(isvideo)
{
prememvideo -= memoflayer;
if(prememvideo <= 0)
{
prememvideo = 0;
}
}
if(Localctx->unasignedVideo <= 0 || isFB)
{
prememvideo = 0;
Localctx->prememvideo = 0;
}
for(whilecnt = 0; whilecnt < channelinfo->HwLayerCnt; whilecnt++)
{
if(channelinfo->HwLayer[whilecnt] != NULL
&& hwc_region_intersect(psdiplay, &channelinfo->HwLayer[whilecnt]->psLayer->displayFrame, &rectx))
{
memoflayer -= (rectx.right - rectx.left) / WscalFac
* (rectx.bottom - rectx.top) / HscaleFac * hwLayer->form_info.bpp / 8;
if(memoflayer <= 0)
{
memoflayer = 0;
}
}
}
if(channelinfo->HwLayerCnt > 1)
{
whilecnt = channelinfo->HwLayerCnt - 1;
while(whilecnt)
{
if(hwc_region_intersect(psdiplay, &channelinfo->rectx[whilecnt - 1], &rectx2))
{
memoflayer += (rectx2.right - rectx2.left) / WscalFac
* (rectx2.bottom - rectx2.top) / HscaleFac
* hwLayer->form_info.bpp / 8;
}
whilecnt--;
}
}
if(channelinfo->HwLayerCnt == 3)
{
if(hwc_region_intersect(&channelinfo->rectx[1], &channelinfo->rectx[0], &channelinfo->rectx[2]))
{
if(hwc_region_intersect(psdiplay, &channelinfo->rectx[2], &rectx2))
{
memoflayer -= (rectx2.right - rectx2.left) / WscalFac
* (rectx2.bottom - rectx2.top) / HscaleFac
* hwLayer->form_info.bpp / 8;
}
}
}
if(memoflayer <= 0)
{
memoflayer = 0;
}
if(psLayer->transform != 0)
{
memoflayer += 2 * cal_layer_mem(hwLayer);
}
if(!isFB && Localctx->UsedFB)
{
fb_mem = Localctx->cur_fb_thruput;
}
need_mem = Globctx->currentmem + memoflayer + prememvideo + fb_mem
+ Globctx->fb_pre_mem - Globctx->memlimit;
if(need_mem <= 0)
{
if(channelinfo->HwLayerCnt > 0)
{
channelinfo->rectx[channelinfo->HwLayerCnt - 1] = rectx;
}
if(isvideo)
{
Localctx->prememvideo -= memoflayer;
if(Localctx->prememvideo <= 0)
{
Localctx->prememvideo = 0;
}
}
}else{
goto overflow;
}
Localctx->cur_de_thruput += memoflayer;
channelinfo->memthruput += memoflayer;
Globctx->currentmem += memoflayer;
return I_OVERLAY;
overflow:
return D_NO_MEM;
}
void hwc_down_limit(SUNXI_hwcdev_context_t *Globctx, int local_mem[NUMBEROFDISPLAY], bool force_gpu)
{
HWC_UNREFERENCED_PARAMETER(local_mem);
int i = 0, tmp_mem_thruput0 = 0;
if((Globctx->has_secure != 0) || (Globctx->has_3D != 0))
{
Globctx->memlimit = Globctx->max_mem_limit;
return;
}
if(Globctx->ForceGPUComp[0] == 0 && Globctx->CanForceGPUCom && force_gpu)
{
if(Globctx->psHwcProcs != NULL
&& Globctx->psHwcProcs->invalidate != NULL)
{
Globctx->ForceGPUComp[0] = 1;
Globctx->ForceGPUComp[1] = 1;
Globctx->psHwcProcs->invalidate(Globctx->psHwcProcs);
}
}
for (i = 0; i < Globctx->NumberofDisp; i++)
{
if(Globctx->SunxiDisplay[i].VirtualToHWDisplay != -EINVAL)
{
tmp_mem_thruput0 += Globctx->SunxiDisplay[i].InitDisplayHeight
* Globctx->SunxiDisplay[i].InitDisplayWidth
* 4;
}
}
Globctx->memlimit = tmp_mem_thruput0;
Globctx->tr_mem_limit = 0;
}
void mem_adjust_moment(SUNXI_hwcdev_context_t *Globctx,
int diff_all, int lower_limit, int high_limit, bool updata)
{
static int mem_cnt_cap;
int max = Globctx->max_mem_limit;
int memlimit_val = 0, mem_lock_tmp = 0;
int try_cnt = 2;
int low = 0, i = 0;
while(i < Globctx->NumberofDisp)
{
if(Globctx->SunxiDisplay[i].VirtualToHWDisplay != -EINVAL)
{
low += Globctx->SunxiDisplay[i].InitDisplayHeight
* Globctx->SunxiDisplay[i].InitDisplayWidth
* 4;
}
i++;
}
if(high_limit < low)
{
goto updata;
}
try_agaign:
mem_lock_tmp = Globctx->memlimit;
if(low > lower_limit)
{
lower_limit = low;
}
if((mem_lock_tmp + diff_all) < lower_limit)
{
memlimit_val = lower_limit;
}
if(high_limit < max)
{
max = high_limit;
}
if((mem_lock_tmp + diff_all) > max)
{
memlimit_val = max;
}
/* down the probability, but not avoid mutex, not importance */
if(mem_lock_tmp == Globctx->memlimit)
{
if(memlimit_val == 0)
{
Globctx->memlimit += diff_all;
}else{
Globctx->memlimit = memlimit_val;
}
}else{
if(--try_cnt)
{
goto try_agaign;
}
}
updata:
if(!updata)
{
return;
}
if(mem_cnt_cap != Globctx->updata_mem_cnt)
{
Globctx->cur_all_diff = 0;
mem_cnt_cap = Globctx->updata_mem_cnt;
}else{
Globctx->cur_all_diff += diff_all;
}
}
void hwc_updata_limit(SUNXI_hwcdev_context_t *Globctx,
hwc_dispc_data_t *DisplayData, int local_mem[NUMBEROFDISPLAY], unsigned int start_count)
{
timeval tv = {0, 0};
double starttime = 0.0;
unsigned int diff_sync_count;
int i = 0;
static double fps_time[3];//0 for 20st time, 1 for 40st time, 2 for 60st time
diff_sync_count = DisplayData->sync_count - start_count;
i = 0;
static int de_mem_all = 0;
while(i < NUMBEROFDISPLAY)
{
local_mem[i] = DisplayData->local_mem[i];
de_mem_all += DisplayData->local_mem[i];
i++;
}
/* ddr dvf interval 256ms */
if(diff_sync_count < SETUP_TIMES)
{
/* open the memory source by setup */
if(Globctx->tr_fd >= 0)
{
if(Globctx->tr_max_mem_limit > Globctx->tr_mem_limit)
{
Globctx->tr_mem_limit += SETUP_INTERVAL_TR;
}else{
Globctx->tr_mem_limit = Globctx->tr_max_mem_limit;
}
}else{
Globctx->tr_mem_limit = 0;
}
if(Globctx->memlimit < Globctx->max_mem_limit)
{
Globctx->memlimit += SETUP_INTERVAL_DE;
}else{
Globctx->memlimit = Globctx->max_mem_limit;
}
Globctx->in_stabilization = 0;
Globctx->cur_all_diff = 0;
de_mem_all = 0;
}
if(diff_sync_count > 4)
{
Globctx->ForceGPUComp[0] = Globctx->stop_hwc;
Globctx->ForceGPUComp[1] = Globctx->stop_hwc;
}
if(diff_sync_count >= SETUP_TIMES)
{
Globctx->in_stabilization = 1;
Globctx->tr_mem_limit = Globctx->tr_max_mem_limit;
Globctx->memlimit = Globctx->max_mem_limit;
if(diff_sync_count%60 == 0)
{
gettimeofday(&tv, NULL);
starttime = tv.tv_sec + tv.tv_usec / 1.0e6;
if(starttime - fps_time[1] > 0 && diff_sync_count != SETUP_TIMES)
{
Globctx->fps[2] = 20.0/(starttime - fps_time[1]);
Globctx->last_fps20 = Globctx->fps[2];
}
fps_time[2] = starttime;
}
if(diff_sync_count%60 == 20)
{
gettimeofday(&tv, NULL);
starttime = tv.tv_sec + tv.tv_usec / 1.0e6;
if(starttime - fps_time[2] > 0)
{
Globctx->fps[0] = 20.0/(starttime - fps_time[2]);
Globctx->last_fps20 = Globctx->fps[0];
}
fps_time[0] = starttime;
}
if(diff_sync_count%60 == 40)
{
gettimeofday(&tv, NULL);
starttime = tv.tv_sec + tv.tv_usec / 1.0e6;
if(starttime - fps_time[0] > 0)
{
Globctx->fps[1] = 20.0/(starttime - fps_time[0]);
Globctx->last_fps20 = Globctx->fps[1];
}
fps_time[1] = starttime;
}
}
}
bool mem_ctrl_power_policy(SUNXI_hwcdev_context_t *Globctx, HwcDisContext_t *localctx)
{
long long gpu_mem_fps_power = 0;
long long de_mem_60_power = 0;
float power_factor = DE_GPU_PW_FACTOR; // for the de and gpu power_factor xchange
if(Globctx->in_stabilization)
{
/* if GPU high usage,hwo to get the gpu usage,wait for AL5,
and low memory thurput then use de composit */
gpu_mem_fps_power = (double)Globctx->last_fps20 * localctx->cur_all_thruput * power_factor
+ localctx->cur_fb_thruput * 60;
de_mem_60_power = (double)Globctx->last_fps20 * localctx->cur_gpu_thruput * power_factor
+ localctx->cur_de_thruput * 60;
if(de_mem_60_power - gpu_mem_fps_power > 0)
{
goto gpu_composite;
}
}
return 0;
gpu_composite:
return 1;
}