From ec3a63d8964886a5178828bc6ff9575135f7d84a Mon Sep 17 00:00:00 2001 From: "hyesoo.yu" Date: Wed, 9 Aug 2017 18:37:08 +0900 Subject: [PATCH] [COMMON] g2d: fix formula based on measured value H/W performance varies depending on scaling ratio, size, rotation and format. Based on the measured times, PPC is calculated again. Change-Id: I6fcfef745ec83eda26647a5d4bad9c994cff4a3f Signed-off-by: hyesoo.yu --- drivers/gpu/exynos/g2d/g2d.h | 40 +++++---- drivers/gpu/exynos/g2d/g2d_drv.c | 23 +++--- drivers/gpu/exynos/g2d/g2d_perf.c | 129 +++++++++++++----------------- drivers/gpu/exynos/g2d/g2d_perf.h | 11 +-- drivers/gpu/exynos/g2d/g2d_uapi.h | 14 +++- 5 files changed, 110 insertions(+), 107 deletions(-) diff --git a/drivers/gpu/exynos/g2d/g2d.h b/drivers/gpu/exynos/g2d/g2d.h index 77bb8903e8ea..50bf4b2db70f 100644 --- a/drivers/gpu/exynos/g2d/g2d.h +++ b/drivers/gpu/exynos/g2d/g2d.h @@ -47,20 +47,32 @@ enum g2d_priority { #define G2D_DEVICE_STATE_SUSPEND 1 #define G2D_DEVICE_STATE_IOVMM_DISABLED 2 +enum g2d_hw_ppc_rot { + PPC_NO_ROTATE, + PPC_ROTATE, + PPC_ROT, +}; + +enum g2d_hw_ppc_fmt { + PPC_RGB, + PPC_YUV2P, + PPC_YUV2P_82, + PPC_FMT, +}; + +enum g2d_hw_ppc_sc { + PPC_NO_SCALE, + PPC_SC_UP, + PPC_SC_DOWN_1, + PPC_SC_DOWN_4, + PPC_SC_DOWN_9, + PPC_SC_DOWN_16, + PPC_SC, +}; + enum g2d_hw_ppc { - G2D_PPC_DEFAULT, - G2D_PPC_SCALE, - G2D_PPC_ROTATE, - G2D_PPC_SCALE_ROTATE, - G2D_PPC_YUV2P, - G2D_PPC_YUV2P_SCALE, - G2D_PPC_YUV2P_ROTATE, - G2D_PPC_YUV2P_SCALE_ROTATE, - G2D_PPC_COLORFILL, - G2D_PPC_DST_DEFAULT, - G2D_PPC_DST_YUV2P, - G2D_PPC_DST_ROT, - G2D_PPC_END, + PPC_COLORFILL = PPC_FMT * PPC_ROT * PPC_SC, + PPC_END, }; struct g2d_dvfs_table { @@ -100,7 +112,7 @@ struct g2d_device { struct mutex lock_qos; struct list_head qos_contexts; - u32 hw_ppc[G2D_PPC_END]; + u32 hw_ppc[PPC_END]; struct g2d_dvfs_table *dvfs_table; u32 dvfs_table_cnt; diff --git a/drivers/gpu/exynos/g2d/g2d_drv.c b/drivers/gpu/exynos/g2d/g2d_drv.c index eb93763c6b6e..5ef0fabb5209 100644 --- a/drivers/gpu/exynos/g2d/g2d_drv.c +++ b/drivers/gpu/exynos/g2d/g2d_drv.c @@ -667,10 +667,16 @@ static int g2d_notifier_event(struct notifier_block *this, return NOTIFY_OK; } -static unsigned int g2d_default_ppc[G2D_PPC_END] = - {3500, 3200, 3500, 3000, - 3500, 3100, 3000, 2800, - 3800, 3500, 2800, 2500}; +static unsigned int g2d_default_ppc[] = { + /* none sc_up x1 x1/4 x1/9 x1/16 */ + 3100, 3400, 2200, 3600, 5100, 7000, //rgb32 non-rotated + 2700, 3300, 2000, 3000, 5200, 6500, //rgb32 rotated + 2900, 3000, 2600, 3400, 5100, 11900, //yuv2p non-rotated + 2000, 3200, 1900, 3300, 5200, 7000, //yuv2p rotated + 1900, 2400, 1900, 2700, 3100, 4100, //8+2 non-rotated + 900, 2500, 900, 2200, 2900, 3700, //8+2 rotated + 3800, //colorfill +}; static struct g2d_dvfs_table g2d_default_dvfs_table[] = { {534000, 711000}, @@ -684,15 +690,14 @@ static struct g2d_dvfs_table g2d_default_dvfs_table[] = { static int g2d_parse_dt(struct g2d_device *g2d_dev) { struct device *dev = g2d_dev->dev; - int i, len; + int len; if (of_property_read_u32_array(dev->of_node, "hw_ppc", - (u32 *)g2d_dev->hw_ppc, - (size_t)(ARRAY_SIZE(g2d_dev->hw_ppc)))) { + (u32 *)g2d_dev->hw_ppc, PPC_END)) { dev_err(dev, "Failed to parse device tree for hw ppc"); - for (i = 0; i < G2D_PPC_END; i++) - g2d_dev->hw_ppc[i] = g2d_default_ppc[i]; + memcpy(g2d_dev->hw_ppc, g2d_default_ppc, + sizeof(g2d_default_ppc[0]) * PPC_END); } len = of_property_count_u32_elems(dev->of_node, "g2d_dvfs_table"); diff --git a/drivers/gpu/exynos/g2d/g2d_perf.c b/drivers/gpu/exynos/g2d/g2d_perf.c index 0f9183d7a39d..1d409afb8934 100644 --- a/drivers/gpu/exynos/g2d/g2d_perf.c +++ b/drivers/gpu/exynos/g2d/g2d_perf.c @@ -59,109 +59,82 @@ static bool g2d_still_need_perf(struct g2d_device *g2d_dev) return false; } +static inline char perf_index_sc(struct g2d_performance_layer_data *layer) +{ + u32 basis = 1000; + u32 ratio = ((u64)layer->window_width * + layer->window_height * basis) / + (layer->crop_width * layer->crop_height); + int i; + + if (ratio == basis) + return PPC_NO_SCALE; + + if (ratio > basis) + return PPC_SC_UP; + + for (i = PPC_SC_DOWN_1; i < PPC_SC_DOWN_16; i++) { + if (ratio > basis / i / i) + return i; + } + + return PPC_SC_DOWN_16; +} + static void g2d_set_device_frequency(struct g2d_context *g2d_ctx, struct g2d_performance_data *data) { struct g2d_device *g2d_dev = g2d_ctx->g2d_dev; struct g2d_performance_frame_data *frame; - struct g2d_performance_layer_data *layer, *pair; - unsigned int cycle, cycle_src, cycle_dst, ip_clock; - unsigned int rot_size, no_rot_size; - unsigned int dst_ppc, ppc[G2D_MAX_IMAGES]; + struct g2d_performance_layer_data *layer; + u32 (*ppc)[PPC_SC] = (u32 (*)[PPC_SC])g2d_dev->hw_ppc; + unsigned int cycle, ip_clock, crop, window; int i, j; - char sc, yuv2p, rot, rot_skip, gap; + int sc, fmt, rot; cycle = 0; - gap = false; for (i = 0; i < data->num_frame; i++) { frame = &data->frame[i]; - rot_size = 0; - no_rot_size = 0; - cycle_src = 0; - - /* - * The rotate variable means that the rotated layers and - * non-rotated layers are mixed. - * If all layers are rotated or are non rotated, that is - * excluded. - */ rot = 0; for (j = 0; j < frame->num_layers; j++) { - if (is_perf_layer_rotate(&frame->layer[j])) + if (perf_index_rotate(&frame->layer[j])) { rot++; + break; + } } - rot_skip = (rot == frame->num_layers) ? 1 : 0; for (j = 0; j < frame->num_layers; j++) { layer = &frame->layer[j]; - yuv2p = is_perf_layer_yuv2p(layer) ? 1 : 0; - sc = is_perf_layer_scaling(layer) ? 1 : 0; - rot = !rot_skip && is_perf_layer_rotate(layer) ? 1 : 0; + crop = (u32)layer->crop_width * layer->crop_height; + window = (u32)layer->window_width * layer->window_height; - ppc[j] = - g2d_dev->hw_ppc[(yuv2p << 2) | (rot << 1) | sc]; + fmt = perf_index_fmt(layer); + sc = perf_index_sc(layer); - cycle_src += layer->pixelcount / ppc[j]; + if (fmt == PPC_FMT) + return; - /* - * check rotated size for cycle_dst. rotated size is - * bigger than non-rotated size, g2d write direction - * is vertical, and it affects performance. - */ - if (is_perf_layer_rotate(layer)) - rot_size += layer->pixelcount; - else - no_rot_size += layer->pixelcount; + cycle += max(crop, window) / ppc[fmt * PPC_ROT + rot][sc]; /* - * The rotated layer affects the pair layer, - * so we add the cycle using gap_ppc between pair - * N layer and N+1 layer. The gap ppc is calculated - * on odd layer and gap_pixelcount is pair layer's - * nested region from 2 layers that means - * the smaller region. + * If frame has colorfill layer on the bottom, + * upper layaer is treated as opaque. + * In this case, colorfill is not be processed + * as much as the overlapping area. */ - if (rot && (yuv2p || sc)) - gap = true; + if (!j && is_perf_frame_colorfill(frame)) { + unsigned int pixelcount; - if (gap && (j & 0x1)) { - unsigned int gap_pixelcount, gap_ppc; + pixelcount = frame->target_pixelcount - + layer->window_width * layer->window_height; + if (pixelcount > 0) + cycle += pixelcount / g2d_dev->hw_ppc[PPC_COLORFILL]; - pair = &frame->layer[j - 1]; - gap = false; - - gap_ppc = (ppc[j] > ppc[j - 1]) ? - (ppc[j] - ppc[j - 1]) : - (ppc[j - 1] - ppc[j]); - if (!gap_ppc) - continue; - - gap_ppc = (ppc[j] * ppc[j - 1]) / gap_ppc; - - gap_pixelcount = min(layer->pixelcount, pair->pixelcount); - - cycle_src += gap_pixelcount / gap_ppc; } } - - rot = (rot_size > no_rot_size) ? 1 : 0; - if (!rot && is_perf_frame_yuv2p(frame)) - dst_ppc = g2d_dev->hw_ppc[G2D_PPC_DST_YUV2P]; - else if (!rot) - dst_ppc = g2d_dev->hw_ppc[G2D_PPC_DST_DEFAULT]; - else - dst_ppc = g2d_dev->hw_ppc[G2D_PPC_DST_ROT]; - - cycle_dst = frame->target_pixelcount / dst_ppc; - - cycle += max(cycle_src, cycle_dst); - - if (is_perf_frame_colorfill(frame)) - cycle += frame->target_pixelcount / - g2d_dev->hw_ppc[G2D_PPC_COLORFILL]; } /* ip_clock(Mhz) = cycles / time_in_ms * 1000 */ @@ -272,6 +245,16 @@ static void g2d_set_qos_frequency(struct g2d_context *g2d_ctx, void g2d_set_performance(struct g2d_context *ctx, struct g2d_performance_data *data) { + int i; + + if (data->num_frame > G2D_PERF_MAX_FRAMES) + return; + + for (i = 0; i < data->num_frame; i++) { + if (data->frame[i].num_layers > G2D_MAX_IMAGES) + return; + } + g2d_set_qos_frequency(ctx, data); g2d_set_device_frequency(ctx, data); } diff --git a/drivers/gpu/exynos/g2d/g2d_perf.h b/drivers/gpu/exynos/g2d/g2d_perf.h index a437824f81dc..58fcb74b660a 100644 --- a/drivers/gpu/exynos/g2d/g2d_perf.h +++ b/drivers/gpu/exynos/g2d/g2d_perf.h @@ -19,15 +19,10 @@ struct g2d_context; struct g2d_performance_data; -#define is_perf_layer_yuv2p(layer) \ - (((layer)->layer_attr) & G2D_PERF_LAYER_YUV2P) -#define is_perf_layer_scaling(layer) \ - (((layer)->layer_attr) & G2D_PERF_LAYER_SCALING) -#define is_perf_layer_rotate(layer) \ +#define perf_index_fmt(layer) \ + ((((layer)->layer_attr) & G2D_PERF_LAYER_FMTMASK) >> 4) +#define perf_index_rotate(layer) \ (((layer)->layer_attr) & G2D_PERF_LAYER_ROTATE) - -#define is_perf_frame_yuv2p(frame) \ - (((frame)->frame_attr) & G2D_PERF_FRAME_YUV2P) #define is_perf_frame_colorfill(frame) \ (((frame)->frame_attr) & G2D_PERF_FRAME_SOLIDCOLORFILL) diff --git a/drivers/gpu/exynos/g2d/g2d_uapi.h b/drivers/gpu/exynos/g2d/g2d_uapi.h index f57600b7a782..6a56ce2b0f90 100644 --- a/drivers/gpu/exynos/g2d/g2d_uapi.h +++ b/drivers/gpu/exynos/g2d/g2d_uapi.h @@ -212,15 +212,23 @@ struct g2d_task_data { /* flags of g2d_performance_layer_data.layer_attr */ #define G2D_PERF_LAYER_ROTATE (1 << 0) #define G2D_PERF_LAYER_SCALING (1 << 1) -#define G2D_PERF_LAYER_YUV2P (1 << 2) +#define G2D_PERF_LAYER_YUV2P (1 << 4) +#define G2D_PERF_LAYER_YUV2P_82 (1 << 5) +#define G2D_PERF_LAYER_FMTMASK (3 << 4) /* * struct g2d_performance_frame_data - description of needed performance. - * @pixelcount : the pixecount of layer, is used to calculate the frequency. + * @crop_width/height : the width and height of the image that + * participates in the image processing + * @window_width/height : the width and height of valid rectangle, + * the region is drawn on target * @layer_attr : attribute of layer affecting performance. */ struct g2d_performance_layer_data { - __u32 pixelcount; + __u16 crop_width; + __u16 crop_height; + __u16 window_width; + __u16 window_height; __u32 layer_attr; }; -- 2.20.1