xref: /aosp_15_r20/external/igt-gpu-tools/overlay/chart.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1*d83cc019SAndroid Build Coastguard Worker /*
2*d83cc019SAndroid Build Coastguard Worker  * Copyright © 2013 Intel Corporation
3*d83cc019SAndroid Build Coastguard Worker  *
4*d83cc019SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
5*d83cc019SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
6*d83cc019SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
7*d83cc019SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*d83cc019SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
9*d83cc019SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
10*d83cc019SAndroid Build Coastguard Worker  *
11*d83cc019SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the next
12*d83cc019SAndroid Build Coastguard Worker  * paragraph) shall be included in all copies or substantial portions of the
13*d83cc019SAndroid Build Coastguard Worker  * Software.
14*d83cc019SAndroid Build Coastguard Worker  *
15*d83cc019SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*d83cc019SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*d83cc019SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18*d83cc019SAndroid Build Coastguard Worker  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*d83cc019SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*d83cc019SAndroid Build Coastguard Worker  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21*d83cc019SAndroid Build Coastguard Worker  * IN THE SOFTWARE.
22*d83cc019SAndroid Build Coastguard Worker  *
23*d83cc019SAndroid Build Coastguard Worker  */
24*d83cc019SAndroid Build Coastguard Worker 
25*d83cc019SAndroid Build Coastguard Worker #include <stdlib.h>
26*d83cc019SAndroid Build Coastguard Worker #include <string.h>
27*d83cc019SAndroid Build Coastguard Worker #include <errno.h>
28*d83cc019SAndroid Build Coastguard Worker #include <cairo.h>
29*d83cc019SAndroid Build Coastguard Worker 
30*d83cc019SAndroid Build Coastguard Worker #include <stdio.h>
31*d83cc019SAndroid Build Coastguard Worker 
32*d83cc019SAndroid Build Coastguard Worker #include "chart.h"
33*d83cc019SAndroid Build Coastguard Worker 
chart_init(struct chart * chart,const char * name,int num_samples)34*d83cc019SAndroid Build Coastguard Worker int chart_init(struct chart *chart, const char *name, int num_samples)
35*d83cc019SAndroid Build Coastguard Worker {
36*d83cc019SAndroid Build Coastguard Worker 	memset(chart, 0, sizeof(*chart));
37*d83cc019SAndroid Build Coastguard Worker 	chart->name = name;
38*d83cc019SAndroid Build Coastguard Worker 	chart->samples = malloc(sizeof(*chart->samples)*num_samples);
39*d83cc019SAndroid Build Coastguard Worker 	if (chart->samples == NULL)
40*d83cc019SAndroid Build Coastguard Worker 		return ENOMEM;
41*d83cc019SAndroid Build Coastguard Worker 
42*d83cc019SAndroid Build Coastguard Worker 	chart->num_samples = num_samples;
43*d83cc019SAndroid Build Coastguard Worker 	chart->range_automatic = 1;
44*d83cc019SAndroid Build Coastguard Worker 	chart->stroke_width = 2;
45*d83cc019SAndroid Build Coastguard Worker 	chart->smooth = CHART_CURVE;
46*d83cc019SAndroid Build Coastguard Worker 	return 0;
47*d83cc019SAndroid Build Coastguard Worker }
48*d83cc019SAndroid Build Coastguard Worker 
chart_set_mode(struct chart * chart,enum chart_mode mode)49*d83cc019SAndroid Build Coastguard Worker void chart_set_mode(struct chart *chart, enum chart_mode mode)
50*d83cc019SAndroid Build Coastguard Worker {
51*d83cc019SAndroid Build Coastguard Worker 	chart->mode = mode;
52*d83cc019SAndroid Build Coastguard Worker }
53*d83cc019SAndroid Build Coastguard Worker 
chart_set_smooth(struct chart * chart,enum chart_smooth smooth)54*d83cc019SAndroid Build Coastguard Worker void chart_set_smooth(struct chart *chart, enum chart_smooth smooth)
55*d83cc019SAndroid Build Coastguard Worker {
56*d83cc019SAndroid Build Coastguard Worker 	chart->smooth = smooth;
57*d83cc019SAndroid Build Coastguard Worker }
58*d83cc019SAndroid Build Coastguard Worker 
chart_set_stroke_width(struct chart * chart,float width)59*d83cc019SAndroid Build Coastguard Worker void chart_set_stroke_width(struct chart *chart, float width)
60*d83cc019SAndroid Build Coastguard Worker {
61*d83cc019SAndroid Build Coastguard Worker 	chart->stroke_width = width;
62*d83cc019SAndroid Build Coastguard Worker }
63*d83cc019SAndroid Build Coastguard Worker 
chart_set_stroke_rgba(struct chart * chart,float red,float green,float blue,float alpha)64*d83cc019SAndroid Build Coastguard Worker void chart_set_stroke_rgba(struct chart *chart, float red, float green, float blue, float alpha)
65*d83cc019SAndroid Build Coastguard Worker {
66*d83cc019SAndroid Build Coastguard Worker 	chart->stroke_rgb[0] = red;
67*d83cc019SAndroid Build Coastguard Worker 	chart->stroke_rgb[1] = green;
68*d83cc019SAndroid Build Coastguard Worker 	chart->stroke_rgb[2] = blue;
69*d83cc019SAndroid Build Coastguard Worker 	chart->stroke_rgb[3] = alpha;
70*d83cc019SAndroid Build Coastguard Worker }
71*d83cc019SAndroid Build Coastguard Worker 
chart_set_fill_rgba(struct chart * chart,float red,float green,float blue,float alpha)72*d83cc019SAndroid Build Coastguard Worker void chart_set_fill_rgba(struct chart *chart, float red, float green, float blue, float alpha)
73*d83cc019SAndroid Build Coastguard Worker {
74*d83cc019SAndroid Build Coastguard Worker 	chart->fill_rgb[0] = red;
75*d83cc019SAndroid Build Coastguard Worker 	chart->fill_rgb[1] = green;
76*d83cc019SAndroid Build Coastguard Worker 	chart->fill_rgb[2] = blue;
77*d83cc019SAndroid Build Coastguard Worker 	chart->fill_rgb[3] = alpha;
78*d83cc019SAndroid Build Coastguard Worker }
79*d83cc019SAndroid Build Coastguard Worker 
chart_set_position(struct chart * chart,int x,int y)80*d83cc019SAndroid Build Coastguard Worker void chart_set_position(struct chart *chart, int x, int y)
81*d83cc019SAndroid Build Coastguard Worker {
82*d83cc019SAndroid Build Coastguard Worker 	chart->x = x;
83*d83cc019SAndroid Build Coastguard Worker 	chart->y = y;
84*d83cc019SAndroid Build Coastguard Worker }
85*d83cc019SAndroid Build Coastguard Worker 
chart_set_size(struct chart * chart,int w,int h)86*d83cc019SAndroid Build Coastguard Worker void chart_set_size(struct chart *chart, int w, int h)
87*d83cc019SAndroid Build Coastguard Worker {
88*d83cc019SAndroid Build Coastguard Worker 	chart->w = w;
89*d83cc019SAndroid Build Coastguard Worker 	chart->h = h;
90*d83cc019SAndroid Build Coastguard Worker }
91*d83cc019SAndroid Build Coastguard Worker 
chart_set_range(struct chart * chart,double min,double max)92*d83cc019SAndroid Build Coastguard Worker void chart_set_range(struct chart *chart, double min, double max)
93*d83cc019SAndroid Build Coastguard Worker {
94*d83cc019SAndroid Build Coastguard Worker 	chart->range[0] = min;
95*d83cc019SAndroid Build Coastguard Worker 	chart->range[1] = max;
96*d83cc019SAndroid Build Coastguard Worker 	chart->range_automatic = 0;
97*d83cc019SAndroid Build Coastguard Worker }
98*d83cc019SAndroid Build Coastguard Worker 
chart_get_range(struct chart * chart,double * range)99*d83cc019SAndroid Build Coastguard Worker void chart_get_range(struct chart *chart, double *range)
100*d83cc019SAndroid Build Coastguard Worker {
101*d83cc019SAndroid Build Coastguard Worker 	int n, max = chart->current_sample;
102*d83cc019SAndroid Build Coastguard Worker 	if (max > chart->num_samples)
103*d83cc019SAndroid Build Coastguard Worker 		max = chart->num_samples;
104*d83cc019SAndroid Build Coastguard Worker 	for (n = 0; n < max; n++) {
105*d83cc019SAndroid Build Coastguard Worker 		if (chart->samples[n] < range[0])
106*d83cc019SAndroid Build Coastguard Worker 			range[0] = chart->samples[n];
107*d83cc019SAndroid Build Coastguard Worker 		else if (chart->samples[n] > range[1])
108*d83cc019SAndroid Build Coastguard Worker 			range[1] = chart->samples[n];
109*d83cc019SAndroid Build Coastguard Worker 	}
110*d83cc019SAndroid Build Coastguard Worker }
111*d83cc019SAndroid Build Coastguard Worker 
chart_add_sample(struct chart * chart,double value)112*d83cc019SAndroid Build Coastguard Worker void chart_add_sample(struct chart *chart, double value)
113*d83cc019SAndroid Build Coastguard Worker {
114*d83cc019SAndroid Build Coastguard Worker 	int pos;
115*d83cc019SAndroid Build Coastguard Worker 
116*d83cc019SAndroid Build Coastguard Worker 	if (chart->num_samples == 0)
117*d83cc019SAndroid Build Coastguard Worker 		return;
118*d83cc019SAndroid Build Coastguard Worker 
119*d83cc019SAndroid Build Coastguard Worker 	pos = chart->current_sample++ % chart->num_samples;
120*d83cc019SAndroid Build Coastguard Worker 	chart->samples[pos] = value;
121*d83cc019SAndroid Build Coastguard Worker }
122*d83cc019SAndroid Build Coastguard Worker 
chart_update_range(struct chart * chart)123*d83cc019SAndroid Build Coastguard Worker static void chart_update_range(struct chart *chart)
124*d83cc019SAndroid Build Coastguard Worker {
125*d83cc019SAndroid Build Coastguard Worker 	int n, max = chart->current_sample;
126*d83cc019SAndroid Build Coastguard Worker 	if (max > chart->num_samples)
127*d83cc019SAndroid Build Coastguard Worker 		max = chart->num_samples;
128*d83cc019SAndroid Build Coastguard Worker 	chart->range[0] = chart->range[1] = chart->samples[0];
129*d83cc019SAndroid Build Coastguard Worker 	for (n = 1; n < max; n++) {
130*d83cc019SAndroid Build Coastguard Worker 		if (chart->samples[n] < chart->range[0])
131*d83cc019SAndroid Build Coastguard Worker 			chart->range[0] = chart->samples[n];
132*d83cc019SAndroid Build Coastguard Worker 		else if (chart->samples[n] > chart->range[1])
133*d83cc019SAndroid Build Coastguard Worker 			chart->range[1] = chart->samples[n];
134*d83cc019SAndroid Build Coastguard Worker 	}
135*d83cc019SAndroid Build Coastguard Worker 	if (strcmp(chart->name, "power") == 0)
136*d83cc019SAndroid Build Coastguard Worker 	printf ("chart_update_range [%f, %f]\n", chart->range[0], chart->range[1]);
137*d83cc019SAndroid Build Coastguard Worker }
138*d83cc019SAndroid Build Coastguard Worker 
value_at(struct chart * chart,int n)139*d83cc019SAndroid Build Coastguard Worker static double value_at(struct chart *chart, int n)
140*d83cc019SAndroid Build Coastguard Worker {
141*d83cc019SAndroid Build Coastguard Worker 	if (n < chart->current_sample - chart->num_samples)
142*d83cc019SAndroid Build Coastguard Worker 		n = chart->current_sample;
143*d83cc019SAndroid Build Coastguard Worker 	else if (n >= chart->current_sample)
144*d83cc019SAndroid Build Coastguard Worker 		n = chart->current_sample - 1;
145*d83cc019SAndroid Build Coastguard Worker 
146*d83cc019SAndroid Build Coastguard Worker 	n %= chart->num_samples;
147*d83cc019SAndroid Build Coastguard Worker 	if (n < 0)
148*d83cc019SAndroid Build Coastguard Worker 		n += chart->num_samples;
149*d83cc019SAndroid Build Coastguard Worker 
150*d83cc019SAndroid Build Coastguard Worker 	return chart->samples[n];
151*d83cc019SAndroid Build Coastguard Worker }
152*d83cc019SAndroid Build Coastguard Worker 
gradient_at(struct chart * chart,int n)153*d83cc019SAndroid Build Coastguard Worker static double gradient_at(struct chart *chart, int n)
154*d83cc019SAndroid Build Coastguard Worker {
155*d83cc019SAndroid Build Coastguard Worker 	double y0, y1;
156*d83cc019SAndroid Build Coastguard Worker 
157*d83cc019SAndroid Build Coastguard Worker 	y0 = value_at(chart, n-1);
158*d83cc019SAndroid Build Coastguard Worker 	y1 = value_at(chart, n+1);
159*d83cc019SAndroid Build Coastguard Worker 
160*d83cc019SAndroid Build Coastguard Worker 	return (y1 - y0) / 2.;
161*d83cc019SAndroid Build Coastguard Worker }
162*d83cc019SAndroid Build Coastguard Worker 
chart_draw(struct chart * chart,cairo_t * cr)163*d83cc019SAndroid Build Coastguard Worker void chart_draw(struct chart *chart, cairo_t *cr)
164*d83cc019SAndroid Build Coastguard Worker {
165*d83cc019SAndroid Build Coastguard Worker 	int i, n, max, x;
166*d83cc019SAndroid Build Coastguard Worker 
167*d83cc019SAndroid Build Coastguard Worker 	if (chart->current_sample == 0)
168*d83cc019SAndroid Build Coastguard Worker 		return;
169*d83cc019SAndroid Build Coastguard Worker 
170*d83cc019SAndroid Build Coastguard Worker 	if (chart->range_automatic)
171*d83cc019SAndroid Build Coastguard Worker 		chart_update_range(chart);
172*d83cc019SAndroid Build Coastguard Worker 
173*d83cc019SAndroid Build Coastguard Worker 	if (chart->range[1] <= chart->range[0])
174*d83cc019SAndroid Build Coastguard Worker 		return;
175*d83cc019SAndroid Build Coastguard Worker 
176*d83cc019SAndroid Build Coastguard Worker 	cairo_save(cr);
177*d83cc019SAndroid Build Coastguard Worker 
178*d83cc019SAndroid Build Coastguard Worker 	cairo_translate(cr, chart->x, chart->y + chart->h);
179*d83cc019SAndroid Build Coastguard Worker 	cairo_scale(cr,
180*d83cc019SAndroid Build Coastguard Worker 		    chart->w / (double)(chart->num_samples-1),
181*d83cc019SAndroid Build Coastguard Worker 		    -chart->h / (chart->range[1] - chart->range[0]));
182*d83cc019SAndroid Build Coastguard Worker 
183*d83cc019SAndroid Build Coastguard Worker 	x = 0;
184*d83cc019SAndroid Build Coastguard Worker 	max = chart->current_sample;
185*d83cc019SAndroid Build Coastguard Worker 	if (max >= chart->num_samples) {
186*d83cc019SAndroid Build Coastguard Worker 		max = chart->num_samples;
187*d83cc019SAndroid Build Coastguard Worker 		i = chart->current_sample - max;
188*d83cc019SAndroid Build Coastguard Worker 	} else {
189*d83cc019SAndroid Build Coastguard Worker 		i = 0;
190*d83cc019SAndroid Build Coastguard Worker 		x = chart->num_samples - max;
191*d83cc019SAndroid Build Coastguard Worker 	}
192*d83cc019SAndroid Build Coastguard Worker 	cairo_translate(cr, x, -chart->range[0]);
193*d83cc019SAndroid Build Coastguard Worker 
194*d83cc019SAndroid Build Coastguard Worker 	cairo_new_path(cr);
195*d83cc019SAndroid Build Coastguard Worker 	if (chart->mode != CHART_STROKE)
196*d83cc019SAndroid Build Coastguard Worker 		cairo_move_to(cr, 0, 0);
197*d83cc019SAndroid Build Coastguard Worker 	for (n = 0; n < max; n++) {
198*d83cc019SAndroid Build Coastguard Worker 		switch (chart->smooth) {
199*d83cc019SAndroid Build Coastguard Worker 		case CHART_LINE:
200*d83cc019SAndroid Build Coastguard Worker 			cairo_line_to(cr,
201*d83cc019SAndroid Build Coastguard Worker 				      n, value_at(chart, i + n));
202*d83cc019SAndroid Build Coastguard Worker 			break;
203*d83cc019SAndroid Build Coastguard Worker 		case CHART_CURVE:
204*d83cc019SAndroid Build Coastguard Worker 			cairo_curve_to(cr,
205*d83cc019SAndroid Build Coastguard Worker 				       n-2/3., value_at(chart, i + n -1) + gradient_at(chart, i + n - 1)/3.,
206*d83cc019SAndroid Build Coastguard Worker 				       n-1/3., value_at(chart, i + n) - gradient_at(chart, i + n)/3.,
207*d83cc019SAndroid Build Coastguard Worker 				       n, value_at(chart, i + n));
208*d83cc019SAndroid Build Coastguard Worker 			break;
209*d83cc019SAndroid Build Coastguard Worker 		}
210*d83cc019SAndroid Build Coastguard Worker 	}
211*d83cc019SAndroid Build Coastguard Worker 	if (chart->mode != CHART_STROKE)
212*d83cc019SAndroid Build Coastguard Worker 		cairo_line_to(cr, n-1, 0);
213*d83cc019SAndroid Build Coastguard Worker 
214*d83cc019SAndroid Build Coastguard Worker 	cairo_identity_matrix(cr);
215*d83cc019SAndroid Build Coastguard Worker 	cairo_set_line_width(cr, chart->stroke_width);
216*d83cc019SAndroid Build Coastguard Worker 	switch (chart->mode) {
217*d83cc019SAndroid Build Coastguard Worker 	case CHART_STROKE:
218*d83cc019SAndroid Build Coastguard Worker 		cairo_set_source_rgba(cr, chart->stroke_rgb[0], chart->stroke_rgb[1], chart->stroke_rgb[2], chart->stroke_rgb[3]);
219*d83cc019SAndroid Build Coastguard Worker 		cairo_stroke(cr);
220*d83cc019SAndroid Build Coastguard Worker 		break;
221*d83cc019SAndroid Build Coastguard Worker 	case CHART_FILL:
222*d83cc019SAndroid Build Coastguard Worker 		cairo_set_source_rgba(cr, chart->fill_rgb[0], chart->fill_rgb[1], chart->fill_rgb[2], chart->fill_rgb[3]);
223*d83cc019SAndroid Build Coastguard Worker 		cairo_fill(cr);
224*d83cc019SAndroid Build Coastguard Worker 		break;
225*d83cc019SAndroid Build Coastguard Worker 	case CHART_FILL_STROKE:
226*d83cc019SAndroid Build Coastguard Worker 		cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
227*d83cc019SAndroid Build Coastguard Worker 		cairo_set_source_rgba(cr, chart->fill_rgb[0], chart->fill_rgb[1], chart->fill_rgb[2], chart->fill_rgb[3]);
228*d83cc019SAndroid Build Coastguard Worker 		cairo_fill_preserve(cr);
229*d83cc019SAndroid Build Coastguard Worker 		cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
230*d83cc019SAndroid Build Coastguard Worker 		cairo_set_source_rgba(cr, chart->stroke_rgb[0], chart->stroke_rgb[1], chart->stroke_rgb[2], chart->stroke_rgb[3]);
231*d83cc019SAndroid Build Coastguard Worker 		cairo_stroke(cr);
232*d83cc019SAndroid Build Coastguard Worker 		break;
233*d83cc019SAndroid Build Coastguard Worker 	}
234*d83cc019SAndroid Build Coastguard Worker 	cairo_restore(cr);
235*d83cc019SAndroid Build Coastguard Worker }
236*d83cc019SAndroid Build Coastguard Worker 
chart_fini(struct chart * chart)237*d83cc019SAndroid Build Coastguard Worker void chart_fini(struct chart *chart)
238*d83cc019SAndroid Build Coastguard Worker {
239*d83cc019SAndroid Build Coastguard Worker 	free(chart->samples);
240*d83cc019SAndroid Build Coastguard Worker }
241