xref: /aosp_15_r20/external/igt-gpu-tools/benchmarks/kms_throughput.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1*d83cc019SAndroid Build Coastguard Worker /*
2*d83cc019SAndroid Build Coastguard Worker  * Copyright © 2019 Google LLC
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 /** @file kms_throughput.c
25*d83cc019SAndroid Build Coastguard Worker  */
26*d83cc019SAndroid Build Coastguard Worker 
27*d83cc019SAndroid Build Coastguard Worker #include <drm.h>
28*d83cc019SAndroid Build Coastguard Worker #include <sys/time.h>
29*d83cc019SAndroid Build Coastguard Worker #include <xf86drm.h>
30*d83cc019SAndroid Build Coastguard Worker #include "drmtest.h"
31*d83cc019SAndroid Build Coastguard Worker #include "igt.h"
32*d83cc019SAndroid Build Coastguard Worker #include "ion.h"
33*d83cc019SAndroid Build Coastguard Worker 
make_display(igt_display_t * display)34*d83cc019SAndroid Build Coastguard Worker static void make_display(igt_display_t *display)
35*d83cc019SAndroid Build Coastguard Worker {
36*d83cc019SAndroid Build Coastguard Worker 	display->drm_fd = drm_open_driver_master(DRIVER_ANY);
37*d83cc019SAndroid Build Coastguard Worker 	igt_display_require(display, display->drm_fd);
38*d83cc019SAndroid Build Coastguard Worker 	igt_require(display->is_atomic);
39*d83cc019SAndroid Build Coastguard Worker 	igt_display_require_output(display);
40*d83cc019SAndroid Build Coastguard Worker }
41*d83cc019SAndroid Build Coastguard Worker 
get_output(igt_display_t * display,enum pipe * pipe,igt_output_t ** output)42*d83cc019SAndroid Build Coastguard Worker static bool get_output(igt_display_t *display,
43*d83cc019SAndroid Build Coastguard Worker 		       enum pipe *pipe, igt_output_t **output)
44*d83cc019SAndroid Build Coastguard Worker {
45*d83cc019SAndroid Build Coastguard Worker 	igt_info("Display %p has %d pipes\n", display, display->n_pipes);
46*d83cc019SAndroid Build Coastguard Worker 	for (int i = 0; i < display->n_pipes; ++i)
47*d83cc019SAndroid Build Coastguard Worker 	{
48*d83cc019SAndroid Build Coastguard Worker 		igt_info("Pipe %d (crtc %u) has %d planes\n",
49*d83cc019SAndroid Build Coastguard Worker 			 i, display->pipes[i].crtc_id,
50*d83cc019SAndroid Build Coastguard Worker 			 display->pipes[i].n_planes);
51*d83cc019SAndroid Build Coastguard Worker 	}
52*d83cc019SAndroid Build Coastguard Worker 
53*d83cc019SAndroid Build Coastguard Worker 	for_each_pipe_with_valid_output(display, *pipe, *output)
54*d83cc019SAndroid Build Coastguard Worker 	{
55*d83cc019SAndroid Build Coastguard Worker 		/* we are happy with the first one */
56*d83cc019SAndroid Build Coastguard Worker 		return true;
57*d83cc019SAndroid Build Coastguard Worker 	}
58*d83cc019SAndroid Build Coastguard Worker 
59*d83cc019SAndroid Build Coastguard Worker 	return false;
60*d83cc019SAndroid Build Coastguard Worker }
61*d83cc019SAndroid Build Coastguard Worker 
get_pipe(igt_display_t * display,igt_pipe_t ** p,igt_output_t ** output)62*d83cc019SAndroid Build Coastguard Worker static void get_pipe(igt_display_t *display,
63*d83cc019SAndroid Build Coastguard Worker 		     igt_pipe_t **p, igt_output_t **output)
64*d83cc019SAndroid Build Coastguard Worker {
65*d83cc019SAndroid Build Coastguard Worker 	enum pipe pipe_idx = PIPE_NONE;
66*d83cc019SAndroid Build Coastguard Worker 	*output = NULL;
67*d83cc019SAndroid Build Coastguard Worker 	igt_require(get_output(display, &pipe_idx, output));
68*d83cc019SAndroid Build Coastguard Worker 	igt_info("Using output id %u, name %s\n",
69*d83cc019SAndroid Build Coastguard Worker 		 (*output)->id, (*output)->name);
70*d83cc019SAndroid Build Coastguard Worker 
71*d83cc019SAndroid Build Coastguard Worker 	/* I'd love to call this 'pipe' but pipe(2) is in the way */
72*d83cc019SAndroid Build Coastguard Worker 	*p = &display->pipes[pipe_idx];
73*d83cc019SAndroid Build Coastguard Worker 	igt_require(*p);
74*d83cc019SAndroid Build Coastguard Worker 
75*d83cc019SAndroid Build Coastguard Worker 	igt_info("Chosen pipe (crtc %u) has %d planes\n",
76*d83cc019SAndroid Build Coastguard Worker 		 (*p)->crtc_id, (*p)->n_planes);
77*d83cc019SAndroid Build Coastguard Worker }
78*d83cc019SAndroid Build Coastguard Worker 
prepare(igt_display_t * display,igt_pipe_t * p,igt_output_t * output)79*d83cc019SAndroid Build Coastguard Worker static void prepare(igt_display_t *display, igt_pipe_t *p, igt_output_t *output)
80*d83cc019SAndroid Build Coastguard Worker {
81*d83cc019SAndroid Build Coastguard Worker 	igt_display_reset(display);
82*d83cc019SAndroid Build Coastguard Worker 	igt_output_set_pipe(output, p->pipe);
83*d83cc019SAndroid Build Coastguard Worker }
84*d83cc019SAndroid Build Coastguard Worker 
plane_for_index(igt_pipe_t * p,size_t index)85*d83cc019SAndroid Build Coastguard Worker static igt_plane_t *plane_for_index(igt_pipe_t *p, size_t index)
86*d83cc019SAndroid Build Coastguard Worker {
87*d83cc019SAndroid Build Coastguard Worker 	return &p->planes[index];
88*d83cc019SAndroid Build Coastguard Worker }
89*d83cc019SAndroid Build Coastguard Worker 
90*d83cc019SAndroid Build Coastguard Worker struct histogram
91*d83cc019SAndroid Build Coastguard Worker {
92*d83cc019SAndroid Build Coastguard Worker 	struct timeval last_commit;
93*d83cc019SAndroid Build Coastguard Worker 	size_t num_buckets;
94*d83cc019SAndroid Build Coastguard Worker 	size_t *buckets;
95*d83cc019SAndroid Build Coastguard Worker };
96*d83cc019SAndroid Build Coastguard Worker 
histogram_init(struct histogram * h)97*d83cc019SAndroid Build Coastguard Worker static void histogram_init(struct histogram *h)
98*d83cc019SAndroid Build Coastguard Worker {
99*d83cc019SAndroid Build Coastguard Worker 	gettimeofday(&h->last_commit, NULL);
100*d83cc019SAndroid Build Coastguard Worker 	h->num_buckets = 100;
101*d83cc019SAndroid Build Coastguard Worker 	h->buckets = calloc(h->num_buckets, sizeof(*h->buckets));
102*d83cc019SAndroid Build Coastguard Worker }
103*d83cc019SAndroid Build Coastguard Worker 
histogram_update(struct histogram * h)104*d83cc019SAndroid Build Coastguard Worker static void histogram_update(struct histogram *h)
105*d83cc019SAndroid Build Coastguard Worker {
106*d83cc019SAndroid Build Coastguard Worker 	struct timeval this_commit;
107*d83cc019SAndroid Build Coastguard Worker 	gettimeofday(&this_commit, NULL);
108*d83cc019SAndroid Build Coastguard Worker 
109*d83cc019SAndroid Build Coastguard Worker 	struct timeval diff;
110*d83cc019SAndroid Build Coastguard Worker 	timersub(&this_commit, &h->last_commit, &diff);
111*d83cc019SAndroid Build Coastguard Worker 	const size_t ms = (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
112*d83cc019SAndroid Build Coastguard Worker 	size_t bucket = ms;
113*d83cc019SAndroid Build Coastguard Worker 	if (bucket >= h->num_buckets)
114*d83cc019SAndroid Build Coastguard Worker 	{
115*d83cc019SAndroid Build Coastguard Worker 		// the last bucket is a catch-all
116*d83cc019SAndroid Build Coastguard Worker 		bucket = h->num_buckets - 1;
117*d83cc019SAndroid Build Coastguard Worker 	}
118*d83cc019SAndroid Build Coastguard Worker 	h->buckets[bucket]++;
119*d83cc019SAndroid Build Coastguard Worker 
120*d83cc019SAndroid Build Coastguard Worker 	memcpy(&h->last_commit, &this_commit, sizeof(this_commit));
121*d83cc019SAndroid Build Coastguard Worker }
122*d83cc019SAndroid Build Coastguard Worker 
histogram_print(struct histogram * h)123*d83cc019SAndroid Build Coastguard Worker static void histogram_print(struct histogram *h)
124*d83cc019SAndroid Build Coastguard Worker {
125*d83cc019SAndroid Build Coastguard Worker 	igt_info("Histogram buckets with 1 or more entries:\n");
126*d83cc019SAndroid Build Coastguard Worker 
127*d83cc019SAndroid Build Coastguard Worker 	for (size_t i = 0; i < h->num_buckets; ++i)
128*d83cc019SAndroid Build Coastguard Worker 	{
129*d83cc019SAndroid Build Coastguard Worker 		size_t value = h->buckets[i];
130*d83cc019SAndroid Build Coastguard Worker 
131*d83cc019SAndroid Build Coastguard Worker 		if (value)
132*d83cc019SAndroid Build Coastguard Worker 		{
133*d83cc019SAndroid Build Coastguard Worker 			if (i == h->num_buckets - 1)
134*d83cc019SAndroid Build Coastguard Worker 			{
135*d83cc019SAndroid Build Coastguard Worker 				igt_info("%zu+ ms: %zu\n", i, value);
136*d83cc019SAndroid Build Coastguard Worker 			}
137*d83cc019SAndroid Build Coastguard Worker 			else
138*d83cc019SAndroid Build Coastguard Worker 			{
139*d83cc019SAndroid Build Coastguard Worker 				igt_info("%zu ms: %zu\n", i, value);
140*d83cc019SAndroid Build Coastguard Worker 			}
141*d83cc019SAndroid Build Coastguard Worker 		}
142*d83cc019SAndroid Build Coastguard Worker 	}
143*d83cc019SAndroid Build Coastguard Worker }
144*d83cc019SAndroid Build Coastguard Worker 
histogram_cleanup(struct histogram * h)145*d83cc019SAndroid Build Coastguard Worker static void histogram_cleanup(struct histogram *h)
146*d83cc019SAndroid Build Coastguard Worker {
147*d83cc019SAndroid Build Coastguard Worker 	free(h->buckets);
148*d83cc019SAndroid Build Coastguard Worker }
149*d83cc019SAndroid Build Coastguard Worker 
150*d83cc019SAndroid Build Coastguard Worker static const size_t max_num_fbs = 32;
151*d83cc019SAndroid Build Coastguard Worker 
152*d83cc019SAndroid Build Coastguard Worker struct tuning
153*d83cc019SAndroid Build Coastguard Worker {
154*d83cc019SAndroid Build Coastguard Worker 	drmModeModeInfoPtr mode;
155*d83cc019SAndroid Build Coastguard Worker 	size_t num_iterations;
156*d83cc019SAndroid Build Coastguard Worker 	size_t num_fb_sets;
157*d83cc019SAndroid Build Coastguard Worker 	size_t num_fbs;
158*d83cc019SAndroid Build Coastguard Worker 	struct fbgeom {
159*d83cc019SAndroid Build Coastguard Worker 		size_t width;
160*d83cc019SAndroid Build Coastguard Worker 		size_t height;
161*d83cc019SAndroid Build Coastguard Worker 	} fb_geom[max_num_fbs];
162*d83cc019SAndroid Build Coastguard Worker };
163*d83cc019SAndroid Build Coastguard Worker 
info_timestamp(const char * text)164*d83cc019SAndroid Build Coastguard Worker static void info_timestamp(const char *text)
165*d83cc019SAndroid Build Coastguard Worker {
166*d83cc019SAndroid Build Coastguard Worker 	struct timeval ts;
167*d83cc019SAndroid Build Coastguard Worker 	gettimeofday(&ts, NULL);
168*d83cc019SAndroid Build Coastguard Worker 	igt_debug("%ld: %s\n", ts.tv_usec, text);
169*d83cc019SAndroid Build Coastguard Worker }
170*d83cc019SAndroid Build Coastguard Worker 
flip_overlays(igt_pipe_t * p,struct igt_fb ** fb_sets,const struct tuning * tuning,size_t iter)171*d83cc019SAndroid Build Coastguard Worker static void flip_overlays(igt_pipe_t *p, struct igt_fb **fb_sets,
172*d83cc019SAndroid Build Coastguard Worker 			  const struct tuning *tuning,
173*d83cc019SAndroid Build Coastguard Worker 			  size_t iter)
174*d83cc019SAndroid Build Coastguard Worker {
175*d83cc019SAndroid Build Coastguard Worker 	size_t fb_set = iter % tuning->num_fb_sets;
176*d83cc019SAndroid Build Coastguard Worker 	struct igt_fb *fbs = fb_sets[fb_set];
177*d83cc019SAndroid Build Coastguard Worker 
178*d83cc019SAndroid Build Coastguard Worker 	for (size_t i = 0; i < tuning->num_fbs; ++i)
179*d83cc019SAndroid Build Coastguard Worker 	{
180*d83cc019SAndroid Build Coastguard Worker 		igt_plane_t *plane = plane_for_index(p, i);
181*d83cc019SAndroid Build Coastguard Worker 		igt_plane_set_prop_value(plane, IGT_PLANE_ZPOS, i);
182*d83cc019SAndroid Build Coastguard Worker 		igt_plane_set_fb(plane, &fbs[i]);
183*d83cc019SAndroid Build Coastguard Worker 	}
184*d83cc019SAndroid Build Coastguard Worker 
185*d83cc019SAndroid Build Coastguard Worker 	igt_pipe_obj_set_prop_value(p, IGT_CRTC_ACTIVE, 1);
186*d83cc019SAndroid Build Coastguard Worker 
187*d83cc019SAndroid Build Coastguard Worker 	info_timestamp("start commit");
188*d83cc019SAndroid Build Coastguard Worker 	igt_display_commit2(p->display, COMMIT_ATOMIC);
189*d83cc019SAndroid Build Coastguard Worker 	info_timestamp("end commit");
190*d83cc019SAndroid Build Coastguard Worker }
191*d83cc019SAndroid Build Coastguard Worker 
repeat_flip(igt_pipe_t * p,struct igt_fb ** fb_sets,const struct tuning * tuning)192*d83cc019SAndroid Build Coastguard Worker static void repeat_flip(igt_pipe_t *p, struct igt_fb **fb_sets,
193*d83cc019SAndroid Build Coastguard Worker 			const struct tuning *tuning)
194*d83cc019SAndroid Build Coastguard Worker {
195*d83cc019SAndroid Build Coastguard Worker 	struct histogram h;
196*d83cc019SAndroid Build Coastguard Worker 	histogram_init(&h);
197*d83cc019SAndroid Build Coastguard Worker 
198*d83cc019SAndroid Build Coastguard Worker 	for (size_t iter = 0; iter < tuning->num_iterations; ++iter)
199*d83cc019SAndroid Build Coastguard Worker 	{
200*d83cc019SAndroid Build Coastguard Worker 		igt_debug("Iteration %zu\n", iter);
201*d83cc019SAndroid Build Coastguard Worker 		flip_overlays(p, fb_sets, tuning, iter);
202*d83cc019SAndroid Build Coastguard Worker 		histogram_update(&h);
203*d83cc019SAndroid Build Coastguard Worker 	}
204*d83cc019SAndroid Build Coastguard Worker 
205*d83cc019SAndroid Build Coastguard Worker 	igt_debug("About to clear fbs\n");
206*d83cc019SAndroid Build Coastguard Worker 
207*d83cc019SAndroid Build Coastguard Worker 	for (size_t i = 0; i < tuning->num_fbs; ++i)
208*d83cc019SAndroid Build Coastguard Worker 	{
209*d83cc019SAndroid Build Coastguard Worker 		igt_plane_t *plane = plane_for_index(p, i);
210*d83cc019SAndroid Build Coastguard Worker 		igt_plane_set_fb(plane, NULL);
211*d83cc019SAndroid Build Coastguard Worker 	}
212*d83cc019SAndroid Build Coastguard Worker 
213*d83cc019SAndroid Build Coastguard Worker 	igt_debug("About to flip with no fbs\n");
214*d83cc019SAndroid Build Coastguard Worker 
215*d83cc019SAndroid Build Coastguard Worker 	igt_display_commit2(p->display, COMMIT_ATOMIC);
216*d83cc019SAndroid Build Coastguard Worker 	igt_wait_for_vblank(p->display->drm_fd, p->pipe);
217*d83cc019SAndroid Build Coastguard Worker 
218*d83cc019SAndroid Build Coastguard Worker 	igt_debug("About to deactivate the crtc\n");
219*d83cc019SAndroid Build Coastguard Worker 
220*d83cc019SAndroid Build Coastguard Worker 	igt_pipe_obj_set_prop_value(p, IGT_CRTC_ACTIVE, 0);
221*d83cc019SAndroid Build Coastguard Worker 	igt_display_commit2(p->display, COMMIT_ATOMIC);
222*d83cc019SAndroid Build Coastguard Worker 
223*d83cc019SAndroid Build Coastguard Worker 	histogram_print(&h);
224*d83cc019SAndroid Build Coastguard Worker 	histogram_cleanup(&h);
225*d83cc019SAndroid Build Coastguard Worker }
226*d83cc019SAndroid Build Coastguard Worker 
create_dumb_fb(igt_display_t * display,size_t width,size_t height,struct igt_fb * fb)227*d83cc019SAndroid Build Coastguard Worker static void create_dumb_fb(igt_display_t *display,
228*d83cc019SAndroid Build Coastguard Worker 			   size_t width, size_t height,
229*d83cc019SAndroid Build Coastguard Worker 			   struct igt_fb *fb)
230*d83cc019SAndroid Build Coastguard Worker {
231*d83cc019SAndroid Build Coastguard Worker 	igt_create_fb(display->drm_fd,
232*d83cc019SAndroid Build Coastguard Worker 		      width, height,
233*d83cc019SAndroid Build Coastguard Worker 		      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE, fb);
234*d83cc019SAndroid Build Coastguard Worker }
235*d83cc019SAndroid Build Coastguard Worker 
236*d83cc019SAndroid Build Coastguard Worker 
get_num_planes(igt_display_t * display)237*d83cc019SAndroid Build Coastguard Worker static int get_num_planes(igt_display_t *display)
238*d83cc019SAndroid Build Coastguard Worker {
239*d83cc019SAndroid Build Coastguard Worker 	const int drm_fd = display->drm_fd;
240*d83cc019SAndroid Build Coastguard Worker 	int ret;
241*d83cc019SAndroid Build Coastguard Worker 
242*d83cc019SAndroid Build Coastguard Worker 	drmModePlaneRes *const plane_resources =
243*d83cc019SAndroid Build Coastguard Worker 		drmModeGetPlaneResources(drm_fd);
244*d83cc019SAndroid Build Coastguard Worker 
245*d83cc019SAndroid Build Coastguard Worker 	ret = plane_resources->count_planes;
246*d83cc019SAndroid Build Coastguard Worker 
247*d83cc019SAndroid Build Coastguard Worker 	drmModeFreePlaneResources(plane_resources);
248*d83cc019SAndroid Build Coastguard Worker 
249*d83cc019SAndroid Build Coastguard Worker 	return ret;
250*d83cc019SAndroid Build Coastguard Worker }
251*d83cc019SAndroid Build Coastguard Worker 
get_max_zpos(igt_display_t * display,igt_pipe_t * p)252*d83cc019SAndroid Build Coastguard Worker static int get_max_zpos(igt_display_t *display, igt_pipe_t *p)
253*d83cc019SAndroid Build Coastguard Worker {
254*d83cc019SAndroid Build Coastguard Worker 	igt_plane_t *primary = plane_for_index(p, 0);
255*d83cc019SAndroid Build Coastguard Worker 
256*d83cc019SAndroid Build Coastguard Worker 	drmModePropertyPtr zpos_prop = NULL;
257*d83cc019SAndroid Build Coastguard Worker 
258*d83cc019SAndroid Build Coastguard Worker 	if (kmstest_get_property(display->drm_fd,
259*d83cc019SAndroid Build Coastguard Worker 				 primary->drm_plane->plane_id,
260*d83cc019SAndroid Build Coastguard Worker 				 DRM_MODE_OBJECT_PLANE,
261*d83cc019SAndroid Build Coastguard Worker 				 "zpos", NULL, NULL,
262*d83cc019SAndroid Build Coastguard Worker 				 &zpos_prop) &&
263*d83cc019SAndroid Build Coastguard Worker 	    zpos_prop &&
264*d83cc019SAndroid Build Coastguard Worker 	    zpos_prop->flags & DRM_MODE_PROP_RANGE)
265*d83cc019SAndroid Build Coastguard Worker 	{
266*d83cc019SAndroid Build Coastguard Worker 		return zpos_prop->values[1];
267*d83cc019SAndroid Build Coastguard Worker 	}
268*d83cc019SAndroid Build Coastguard Worker 	else
269*d83cc019SAndroid Build Coastguard Worker 	{
270*d83cc019SAndroid Build Coastguard Worker 		return -1;
271*d83cc019SAndroid Build Coastguard Worker 	}
272*d83cc019SAndroid Build Coastguard Worker }
273*d83cc019SAndroid Build Coastguard Worker 
get_num_fbs(igt_display_t * display,igt_pipe_t * p)274*d83cc019SAndroid Build Coastguard Worker size_t get_num_fbs(igt_display_t *display, igt_pipe_t *p)
275*d83cc019SAndroid Build Coastguard Worker {
276*d83cc019SAndroid Build Coastguard Worker 	const char *NUM_FBS = getenv("NUM_FBS");
277*d83cc019SAndroid Build Coastguard Worker 
278*d83cc019SAndroid Build Coastguard Worker 	if (NUM_FBS)
279*d83cc019SAndroid Build Coastguard Worker 	{
280*d83cc019SAndroid Build Coastguard Worker 		return (size_t)atoi(NUM_FBS);
281*d83cc019SAndroid Build Coastguard Worker 	}
282*d83cc019SAndroid Build Coastguard Worker 	else
283*d83cc019SAndroid Build Coastguard Worker 	{
284*d83cc019SAndroid Build Coastguard Worker 		const int num_planes = get_num_planes(display);
285*d83cc019SAndroid Build Coastguard Worker 		const int max_zpos = get_max_zpos(display, p);
286*d83cc019SAndroid Build Coastguard Worker 
287*d83cc019SAndroid Build Coastguard Worker 		if (max_zpos >= 0 && max_zpos + 1 < num_planes)
288*d83cc019SAndroid Build Coastguard Worker 		{
289*d83cc019SAndroid Build Coastguard Worker 			return (size_t)max_zpos + 1;
290*d83cc019SAndroid Build Coastguard Worker 		}
291*d83cc019SAndroid Build Coastguard Worker 		else
292*d83cc019SAndroid Build Coastguard Worker 		{
293*d83cc019SAndroid Build Coastguard Worker 			return (size_t)num_planes;
294*d83cc019SAndroid Build Coastguard Worker 		}
295*d83cc019SAndroid Build Coastguard Worker 	}
296*d83cc019SAndroid Build Coastguard Worker }
297*d83cc019SAndroid Build Coastguard Worker 
calculate_complexity(const drmModeModeInfoPtr mode)298*d83cc019SAndroid Build Coastguard Worker size_t calculate_complexity(const drmModeModeInfoPtr mode)
299*d83cc019SAndroid Build Coastguard Worker {
300*d83cc019SAndroid Build Coastguard Worker 	return (size_t)mode->hdisplay * (size_t)mode->vdisplay * (size_t)mode->vrefresh;
301*d83cc019SAndroid Build Coastguard Worker }
302*d83cc019SAndroid Build Coastguard Worker 
get_peak_mode(igt_output_t * output)303*d83cc019SAndroid Build Coastguard Worker drmModeModeInfoPtr get_peak_mode(igt_output_t *output)
304*d83cc019SAndroid Build Coastguard Worker {
305*d83cc019SAndroid Build Coastguard Worker 	drmModeConnector *const connector = output->config.connector;
306*d83cc019SAndroid Build Coastguard Worker 	if (!connector || connector->count_modes == 0)
307*d83cc019SAndroid Build Coastguard Worker 	{
308*d83cc019SAndroid Build Coastguard Worker 		return NULL;
309*d83cc019SAndroid Build Coastguard Worker 	}
310*d83cc019SAndroid Build Coastguard Worker 
311*d83cc019SAndroid Build Coastguard Worker 	drmModeModeInfoPtr peak_mode = &connector->modes[0];
312*d83cc019SAndroid Build Coastguard Worker 	size_t peak_complexity = calculate_complexity(peak_mode);
313*d83cc019SAndroid Build Coastguard Worker 
314*d83cc019SAndroid Build Coastguard Worker 	for (drmModeModeInfoPtr mode = &connector->modes[0];
315*d83cc019SAndroid Build Coastguard Worker 	     mode < &connector->modes[connector->count_modes]; ++mode)
316*d83cc019SAndroid Build Coastguard Worker 	{
317*d83cc019SAndroid Build Coastguard Worker 		const size_t complexity = calculate_complexity(mode);
318*d83cc019SAndroid Build Coastguard Worker 		igt_debug("Mode %zu is %hux%hu@%u\n",
319*d83cc019SAndroid Build Coastguard Worker 			  (size_t)(mode - connector->modes),
320*d83cc019SAndroid Build Coastguard Worker 			  mode->hdisplay, mode->vdisplay, mode->vrefresh);
321*d83cc019SAndroid Build Coastguard Worker 		if (complexity > peak_complexity)
322*d83cc019SAndroid Build Coastguard Worker 		{
323*d83cc019SAndroid Build Coastguard Worker 			peak_mode = mode;
324*d83cc019SAndroid Build Coastguard Worker 			peak_complexity = complexity;
325*d83cc019SAndroid Build Coastguard Worker 		}
326*d83cc019SAndroid Build Coastguard Worker 	}
327*d83cc019SAndroid Build Coastguard Worker 
328*d83cc019SAndroid Build Coastguard Worker 	return peak_mode;
329*d83cc019SAndroid Build Coastguard Worker }
330*d83cc019SAndroid Build Coastguard Worker 
get_tuning(struct tuning * tuning,igt_display_t * display,igt_pipe_t * p,igt_output_t * output)331*d83cc019SAndroid Build Coastguard Worker void get_tuning(struct tuning *tuning,
332*d83cc019SAndroid Build Coastguard Worker 		igt_display_t *display, igt_pipe_t *p,
333*d83cc019SAndroid Build Coastguard Worker 		igt_output_t *output)
334*d83cc019SAndroid Build Coastguard Worker {
335*d83cc019SAndroid Build Coastguard Worker 	tuning->mode = get_peak_mode(output);
336*d83cc019SAndroid Build Coastguard Worker 	igt_require(tuning->mode);
337*d83cc019SAndroid Build Coastguard Worker 
338*d83cc019SAndroid Build Coastguard Worker 	if (igt_output_get_mode(output) != tuning->mode)
339*d83cc019SAndroid Build Coastguard Worker 	{
340*d83cc019SAndroid Build Coastguard Worker 		igt_output_override_mode(output, tuning->mode);
341*d83cc019SAndroid Build Coastguard Worker 		igt_display_commit2(p->display, COMMIT_ATOMIC);
342*d83cc019SAndroid Build Coastguard Worker 	}
343*d83cc019SAndroid Build Coastguard Worker 
344*d83cc019SAndroid Build Coastguard Worker 	igt_info("Chosen mode:\n");
345*d83cc019SAndroid Build Coastguard Worker 	kmstest_dump_mode(tuning->mode);
346*d83cc019SAndroid Build Coastguard Worker 
347*d83cc019SAndroid Build Coastguard Worker 	tuning->num_iterations = 1000;
348*d83cc019SAndroid Build Coastguard Worker 	tuning->num_fb_sets = 2;
349*d83cc019SAndroid Build Coastguard Worker 
350*d83cc019SAndroid Build Coastguard Worker 	tuning->num_fbs = get_num_fbs(display, p);
351*d83cc019SAndroid Build Coastguard Worker 	igt_require(tuning->num_fbs <= max_num_fbs);
352*d83cc019SAndroid Build Coastguard Worker 
353*d83cc019SAndroid Build Coastguard Worker 	drmModeModeInfo *mode = igt_output_get_mode(output);
354*d83cc019SAndroid Build Coastguard Worker 	const char *FB_WIDTH = getenv("FB_WIDTH");
355*d83cc019SAndroid Build Coastguard Worker 	const char *FB_HEIGHT = getenv("FB_HEIGHT");
356*d83cc019SAndroid Build Coastguard Worker 
357*d83cc019SAndroid Build Coastguard Worker 	const size_t requested_fb_width = FB_WIDTH ?
358*d83cc019SAndroid Build Coastguard Worker 		(size_t)atoi(FB_WIDTH) :
359*d83cc019SAndroid Build Coastguard Worker 		mode->hdisplay;
360*d83cc019SAndroid Build Coastguard Worker 
361*d83cc019SAndroid Build Coastguard Worker 	const size_t requested_fb_height = FB_HEIGHT ?
362*d83cc019SAndroid Build Coastguard Worker 		(size_t)atoi(FB_HEIGHT) :
363*d83cc019SAndroid Build Coastguard Worker 		mode->vdisplay;
364*d83cc019SAndroid Build Coastguard Worker 
365*d83cc019SAndroid Build Coastguard Worker 	igt_display_commit2(p->display, COMMIT_ATOMIC);
366*d83cc019SAndroid Build Coastguard Worker 
367*d83cc019SAndroid Build Coastguard Worker 	struct igt_fb fb;
368*d83cc019SAndroid Build Coastguard Worker 	create_dumb_fb(p->display, requested_fb_width, requested_fb_height, &fb);
369*d83cc019SAndroid Build Coastguard Worker 
370*d83cc019SAndroid Build Coastguard Worker 	for (size_t i = 0; i < tuning->num_fbs; ++i)
371*d83cc019SAndroid Build Coastguard Worker 	{
372*d83cc019SAndroid Build Coastguard Worker 		igt_plane_t *const plane = plane_for_index(p, i);
373*d83cc019SAndroid Build Coastguard Worker 		igt_plane_set_prop_value(plane, IGT_PLANE_ZPOS, i);
374*d83cc019SAndroid Build Coastguard Worker 		igt_plane_set_fb(plane, &fb);
375*d83cc019SAndroid Build Coastguard Worker 
376*d83cc019SAndroid Build Coastguard Worker 		int ret = igt_display_try_commit_atomic(p->display,
377*d83cc019SAndroid Build Coastguard Worker 							DRM_MODE_ATOMIC_TEST_ONLY,
378*d83cc019SAndroid Build Coastguard Worker 							NULL);
379*d83cc019SAndroid Build Coastguard Worker 
380*d83cc019SAndroid Build Coastguard Worker 		if (ret)
381*d83cc019SAndroid Build Coastguard Worker 		{
382*d83cc019SAndroid Build Coastguard Worker 			tuning->fb_geom[i].width = mode->hdisplay;
383*d83cc019SAndroid Build Coastguard Worker 			tuning->fb_geom[i].height = mode->vdisplay;
384*d83cc019SAndroid Build Coastguard Worker 		}
385*d83cc019SAndroid Build Coastguard Worker 		else
386*d83cc019SAndroid Build Coastguard Worker 		{
387*d83cc019SAndroid Build Coastguard Worker 			tuning->fb_geom[i].width = requested_fb_width;
388*d83cc019SAndroid Build Coastguard Worker 			tuning->fb_geom[i].height = requested_fb_height;
389*d83cc019SAndroid Build Coastguard Worker 		}
390*d83cc019SAndroid Build Coastguard Worker 
391*d83cc019SAndroid Build Coastguard Worker 		igt_info("Plane %zu is %zux%zu\n", i,
392*d83cc019SAndroid Build Coastguard Worker 			 tuning->fb_geom[i].width,
393*d83cc019SAndroid Build Coastguard Worker 			 tuning->fb_geom[i].height);
394*d83cc019SAndroid Build Coastguard Worker 
395*d83cc019SAndroid Build Coastguard Worker 		igt_plane_set_fb(plane, NULL);
396*d83cc019SAndroid Build Coastguard Worker 	}
397*d83cc019SAndroid Build Coastguard Worker 
398*d83cc019SAndroid Build Coastguard Worker 	igt_remove_fb(p->display->drm_fd, &fb);
399*d83cc019SAndroid Build Coastguard Worker }
400*d83cc019SAndroid Build Coastguard Worker 
401*d83cc019SAndroid Build Coastguard Worker igt_main
402*d83cc019SAndroid Build Coastguard Worker {
403*d83cc019SAndroid Build Coastguard Worker 	igt_display_t display = {};
404*d83cc019SAndroid Build Coastguard Worker 	make_display(&display);
405*d83cc019SAndroid Build Coastguard Worker 
406*d83cc019SAndroid Build Coastguard Worker 	igt_pipe_t *p = NULL;
407*d83cc019SAndroid Build Coastguard Worker 	igt_output_t *output = NULL;
408*d83cc019SAndroid Build Coastguard Worker 	get_pipe(&display, &p, &output);
409*d83cc019SAndroid Build Coastguard Worker 
410*d83cc019SAndroid Build Coastguard Worker 	do_or_die(drmSetClientCap(
411*d83cc019SAndroid Build Coastguard Worker 		display.drm_fd,
412*d83cc019SAndroid Build Coastguard Worker 		DRM_CLIENT_CAP_ATOMIC,
413*d83cc019SAndroid Build Coastguard Worker 		1));
414*d83cc019SAndroid Build Coastguard Worker 
415*d83cc019SAndroid Build Coastguard Worker 	do_or_die(drmSetClientCap(
416*d83cc019SAndroid Build Coastguard Worker 		display.drm_fd,
417*d83cc019SAndroid Build Coastguard Worker 		DRM_CLIENT_CAP_UNIVERSAL_PLANES,
418*d83cc019SAndroid Build Coastguard Worker 		1));
419*d83cc019SAndroid Build Coastguard Worker 
420*d83cc019SAndroid Build Coastguard Worker 	igt_pipe_refresh(&display, p->pipe, true);
421*d83cc019SAndroid Build Coastguard Worker 
422*d83cc019SAndroid Build Coastguard Worker 	prepare(&display, p, output);
423*d83cc019SAndroid Build Coastguard Worker 
424*d83cc019SAndroid Build Coastguard Worker 	drmModeModeInfoPtr orig_mode = igt_output_get_mode(output);
425*d83cc019SAndroid Build Coastguard Worker 
426*d83cc019SAndroid Build Coastguard Worker 	struct tuning tuning;
427*d83cc019SAndroid Build Coastguard Worker 	get_tuning(&tuning, &display, p, output);
428*d83cc019SAndroid Build Coastguard Worker 
429*d83cc019SAndroid Build Coastguard Worker 	{
430*d83cc019SAndroid Build Coastguard Worker 		struct igt_fb **fb_sets =
431*d83cc019SAndroid Build Coastguard Worker 				malloc(sizeof(struct igt_fb*[tuning.num_fb_sets]));
432*d83cc019SAndroid Build Coastguard Worker 
433*d83cc019SAndroid Build Coastguard Worker 		for (size_t i = 0; i < tuning.num_fb_sets; ++i)
434*d83cc019SAndroid Build Coastguard Worker 		{
435*d83cc019SAndroid Build Coastguard Worker 			fb_sets[i] = malloc(sizeof(struct igt_fb[tuning.num_fbs]));
436*d83cc019SAndroid Build Coastguard Worker 			struct igt_fb *fbs = fb_sets[i];
437*d83cc019SAndroid Build Coastguard Worker 			for (size_t j = 0; j < tuning.num_fbs; ++j)
438*d83cc019SAndroid Build Coastguard Worker 			{
439*d83cc019SAndroid Build Coastguard Worker 				create_dumb_fb(&display,
440*d83cc019SAndroid Build Coastguard Worker 					       tuning.fb_geom[j].width,
441*d83cc019SAndroid Build Coastguard Worker 					       tuning.fb_geom[j].height,
442*d83cc019SAndroid Build Coastguard Worker 					       &fbs[j]);
443*d83cc019SAndroid Build Coastguard Worker 			};
444*d83cc019SAndroid Build Coastguard Worker 		}
445*d83cc019SAndroid Build Coastguard Worker 
446*d83cc019SAndroid Build Coastguard Worker 
447*d83cc019SAndroid Build Coastguard Worker 		repeat_flip(p, fb_sets, &tuning);
448*d83cc019SAndroid Build Coastguard Worker 
449*d83cc019SAndroid Build Coastguard Worker 		for (size_t i = 0; i < tuning.num_fb_sets; ++i)
450*d83cc019SAndroid Build Coastguard Worker 		{
451*d83cc019SAndroid Build Coastguard Worker 			struct igt_fb *fbs = fb_sets[i];
452*d83cc019SAndroid Build Coastguard Worker 			for (size_t j = 0; j < tuning.num_fbs; ++j)
453*d83cc019SAndroid Build Coastguard Worker 			{
454*d83cc019SAndroid Build Coastguard Worker 				igt_remove_fb(display.drm_fd, &fbs[j]);
455*d83cc019SAndroid Build Coastguard Worker 			};
456*d83cc019SAndroid Build Coastguard Worker 			free(fbs);
457*d83cc019SAndroid Build Coastguard Worker 		}
458*d83cc019SAndroid Build Coastguard Worker 		free(fb_sets);
459*d83cc019SAndroid Build Coastguard Worker 	}
460*d83cc019SAndroid Build Coastguard Worker 
461*d83cc019SAndroid Build Coastguard Worker 	if (orig_mode != tuning.mode)
462*d83cc019SAndroid Build Coastguard Worker 	{
463*d83cc019SAndroid Build Coastguard Worker 		igt_output_override_mode(output, orig_mode);
464*d83cc019SAndroid Build Coastguard Worker 		igt_display_commit2(&display, COMMIT_ATOMIC);
465*d83cc019SAndroid Build Coastguard Worker 	}
466*d83cc019SAndroid Build Coastguard Worker 
467*d83cc019SAndroid Build Coastguard Worker 	igt_info("Success\n");
468*d83cc019SAndroid Build Coastguard Worker }
469