[COMMON] g2d: fix formula based on measured value
authorhyesoo.yu <hyesoo.yu@samsung.com>
Wed, 9 Aug 2017 09:37:08 +0000 (18:37 +0900)
committerCosmin Tanislav <demonsingur@gmail.com>
Mon, 22 Apr 2024 17:22:14 +0000 (20:22 +0300)
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 <hyesoo.yu@samsung.com>
drivers/gpu/exynos/g2d/g2d.h
drivers/gpu/exynos/g2d/g2d_drv.c
drivers/gpu/exynos/g2d/g2d_perf.c
drivers/gpu/exynos/g2d/g2d_perf.h
drivers/gpu/exynos/g2d/g2d_uapi.h

index 77bb8903e8ea828f8748b350d67151fc186f1007..50bf4b2db70fce21dc950887952c0e2074194693 100644 (file)
@@ -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;
index eb93763c6b6eb70a9ba90841d942718713206c50..5ef0fabb52096e037f29ba5655d78b93dcc00941 100644 (file)
@@ -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");
index 0f9183d7a39dd25dfe99a3e88086c48b66463a5b..1d409afb893411536b67311948e4265b40e906db 100644 (file)
@@ -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);
 }
index a437824f81dc4d406cb112de2269f8958d634628..58fcb74b660a9b9be43bad2d92bc23a80e980ef2 100644 (file)
 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)
 
index f57600b7a78248442a2bc2583ec249b719be49d4..6a56ce2b0f908b7f508f5fdc89083979283a6d7c 100644 (file)
@@ -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;
 };