xref: /aosp_15_r20/external/igt-gpu-tools/tests/prime_mmap_kms.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1*d83cc019SAndroid Build Coastguard Worker /*
2*d83cc019SAndroid Build Coastguard Worker  * Copyright © 2016 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  * Authors:
24*d83cc019SAndroid Build Coastguard Worker  *    Tiago Vignatti <tiago.vignatti at intel.com>
25*d83cc019SAndroid Build Coastguard Worker  */
26*d83cc019SAndroid Build Coastguard Worker 
27*d83cc019SAndroid Build Coastguard Worker /*
28*d83cc019SAndroid Build Coastguard Worker  * Testcase: show case dma-buf new API and processes restrictions. Most likely
29*d83cc019SAndroid Build Coastguard Worker  * you want to run like ./prime_mmap_kms --interactive-debug=paint, to see the
30*d83cc019SAndroid Build Coastguard Worker  * actual rectangle painted on the screen.
31*d83cc019SAndroid Build Coastguard Worker  */
32*d83cc019SAndroid Build Coastguard Worker 
33*d83cc019SAndroid Build Coastguard Worker #include "igt.h"
34*d83cc019SAndroid Build Coastguard Worker 
35*d83cc019SAndroid Build Coastguard Worker IGT_TEST_DESCRIPTION(
36*d83cc019SAndroid Build Coastguard Worker    "Efficiently sharing CPU and GPU buffers");
37*d83cc019SAndroid Build Coastguard Worker 
38*d83cc019SAndroid Build Coastguard Worker /*
39*d83cc019SAndroid Build Coastguard Worker  * render_process_t:
40*d83cc019SAndroid Build Coastguard Worker  *
41*d83cc019SAndroid Build Coastguard Worker  * Render is basically a user-space regular client. It's the unprivileged
42*d83cc019SAndroid Build Coastguard Worker  * process with limited system accesses.
43*d83cc019SAndroid Build Coastguard Worker  *
44*d83cc019SAndroid Build Coastguard Worker  * Worth note the vendor-independent characteristic, meaning that the
45*d83cc019SAndroid Build Coastguard Worker  * client doesn't need to perform any vendor specific calls for buffer
46*d83cc019SAndroid Build Coastguard Worker  * handling. Mesa GBM library is a counter-example because, even though its API
47*d83cc019SAndroid Build Coastguard Worker  * is vendor-independent, under-the-hood the library actually calls vendor
48*d83cc019SAndroid Build Coastguard Worker  * specific ioctls, which is not really sandboxable and not the goal here.
49*d83cc019SAndroid Build Coastguard Worker  */
50*d83cc019SAndroid Build Coastguard Worker typedef struct {
51*d83cc019SAndroid Build Coastguard Worker 	int prime_fd;
52*d83cc019SAndroid Build Coastguard Worker 	size_t size;
53*d83cc019SAndroid Build Coastguard Worker 	int width;
54*d83cc019SAndroid Build Coastguard Worker 	int height;
55*d83cc019SAndroid Build Coastguard Worker } render_process_t;
56*d83cc019SAndroid Build Coastguard Worker 
57*d83cc019SAndroid Build Coastguard Worker typedef struct {
58*d83cc019SAndroid Build Coastguard Worker 	int x;
59*d83cc019SAndroid Build Coastguard Worker 	int y;
60*d83cc019SAndroid Build Coastguard Worker 	int w;
61*d83cc019SAndroid Build Coastguard Worker 	int h;
62*d83cc019SAndroid Build Coastguard Worker } rect_t;
63*d83cc019SAndroid Build Coastguard Worker 
64*d83cc019SAndroid Build Coastguard Worker /* set ptr in a linear view */
set_pixel(void * _ptr,int index,uint32_t color,int bpp)65*d83cc019SAndroid Build Coastguard Worker static void set_pixel(void *_ptr, int index, uint32_t color, int bpp)
66*d83cc019SAndroid Build Coastguard Worker {
67*d83cc019SAndroid Build Coastguard Worker 	if (bpp == 16) {
68*d83cc019SAndroid Build Coastguard Worker 		uint16_t *ptr = _ptr;
69*d83cc019SAndroid Build Coastguard Worker 		ptr[index] = color;
70*d83cc019SAndroid Build Coastguard Worker 	} else if (bpp == 32) {
71*d83cc019SAndroid Build Coastguard Worker 		uint32_t *ptr = _ptr;
72*d83cc019SAndroid Build Coastguard Worker 		ptr[index] = color;
73*d83cc019SAndroid Build Coastguard Worker 	} else {
74*d83cc019SAndroid Build Coastguard Worker 		igt_assert_f(false, "bpp: %d\n", bpp);
75*d83cc019SAndroid Build Coastguard Worker 	}
76*d83cc019SAndroid Build Coastguard Worker }
77*d83cc019SAndroid Build Coastguard Worker 
paint(render_process_t * render)78*d83cc019SAndroid Build Coastguard Worker static void paint(render_process_t *render)
79*d83cc019SAndroid Build Coastguard Worker {
80*d83cc019SAndroid Build Coastguard Worker 	void *frame;
81*d83cc019SAndroid Build Coastguard Worker 	rect_t rect = {
82*d83cc019SAndroid Build Coastguard Worker 		.x = 200,
83*d83cc019SAndroid Build Coastguard Worker 		.y = 200,
84*d83cc019SAndroid Build Coastguard Worker 		.w = render->width / 4,
85*d83cc019SAndroid Build Coastguard Worker 		.h = render->height / 4,
86*d83cc019SAndroid Build Coastguard Worker 	};
87*d83cc019SAndroid Build Coastguard Worker 	uint32_t color = 0xFF;
88*d83cc019SAndroid Build Coastguard Worker 	int stride, bpp;
89*d83cc019SAndroid Build Coastguard Worker 	int x, y, line_begin;
90*d83cc019SAndroid Build Coastguard Worker 
91*d83cc019SAndroid Build Coastguard Worker 	frame = mmap(NULL, render->size, PROT_READ | PROT_WRITE, MAP_SHARED,
92*d83cc019SAndroid Build Coastguard Worker 		     render->prime_fd, 0);
93*d83cc019SAndroid Build Coastguard Worker 	igt_assert(frame != MAP_FAILED);
94*d83cc019SAndroid Build Coastguard Worker 
95*d83cc019SAndroid Build Coastguard Worker 	/* TODO: what's the mmap'ed buffer semantics on tiling, format etc. How
96*d83cc019SAndroid Build Coastguard Worker 	 * does the client know whether that the BO was created X-tiled,
97*d83cc019SAndroid Build Coastguard Worker 	 * Y-tiled and how it will map back? This is something we need to
98*d83cc019SAndroid Build Coastguard Worker 	 * address in this API still. */
99*d83cc019SAndroid Build Coastguard Worker 	stride = render->width * 4;
100*d83cc019SAndroid Build Coastguard Worker 	bpp = 32;
101*d83cc019SAndroid Build Coastguard Worker 
102*d83cc019SAndroid Build Coastguard Worker 	/* ioctls to keep up the GPU <-> CPU coherency */
103*d83cc019SAndroid Build Coastguard Worker 	prime_sync_start(render->prime_fd, true);
104*d83cc019SAndroid Build Coastguard Worker 
105*d83cc019SAndroid Build Coastguard Worker 	/* the actual painting phase happens here */
106*d83cc019SAndroid Build Coastguard Worker 	for (y = rect.y; y < rect.y + rect.h; y++) {
107*d83cc019SAndroid Build Coastguard Worker 		line_begin = y * stride / (bpp / 8);
108*d83cc019SAndroid Build Coastguard Worker 		for (x = rect.x; x < rect.x + rect.w; x++)
109*d83cc019SAndroid Build Coastguard Worker 			set_pixel(frame, line_begin + x, color, bpp);
110*d83cc019SAndroid Build Coastguard Worker 	}
111*d83cc019SAndroid Build Coastguard Worker 
112*d83cc019SAndroid Build Coastguard Worker 	prime_sync_end(render->prime_fd, true);
113*d83cc019SAndroid Build Coastguard Worker 	munmap(frame, render->size);
114*d83cc019SAndroid Build Coastguard Worker }
115*d83cc019SAndroid Build Coastguard Worker 
init_renderer(int prime_fd,int fb_size,int width,int height)116*d83cc019SAndroid Build Coastguard Worker static void init_renderer(int prime_fd, int fb_size, int width, int height)
117*d83cc019SAndroid Build Coastguard Worker {
118*d83cc019SAndroid Build Coastguard Worker 	render_process_t render;
119*d83cc019SAndroid Build Coastguard Worker 
120*d83cc019SAndroid Build Coastguard Worker 	render.prime_fd = prime_fd;
121*d83cc019SAndroid Build Coastguard Worker 	render.size = fb_size;
122*d83cc019SAndroid Build Coastguard Worker 	render.width = width;
123*d83cc019SAndroid Build Coastguard Worker 	render.height = height;
124*d83cc019SAndroid Build Coastguard Worker 	paint(&render);
125*d83cc019SAndroid Build Coastguard Worker }
126*d83cc019SAndroid Build Coastguard Worker 
127*d83cc019SAndroid Build Coastguard Worker /*
128*d83cc019SAndroid Build Coastguard Worker  * gpu_process_t:
129*d83cc019SAndroid Build Coastguard Worker  *
130*d83cc019SAndroid Build Coastguard Worker  * GPU process is the privileged process and has access to the system graphics
131*d83cc019SAndroid Build Coastguard Worker  * routines, like DRM, display management and driver accesses.
132*d83cc019SAndroid Build Coastguard Worker  */
133*d83cc019SAndroid Build Coastguard Worker typedef struct {
134*d83cc019SAndroid Build Coastguard Worker 	int drm_fd;
135*d83cc019SAndroid Build Coastguard Worker 	igt_display_t display;
136*d83cc019SAndroid Build Coastguard Worker 	struct igt_fb fb;
137*d83cc019SAndroid Build Coastguard Worker 	igt_output_t *output;
138*d83cc019SAndroid Build Coastguard Worker 	igt_plane_t *primary;
139*d83cc019SAndroid Build Coastguard Worker 	enum pipe pipe;
140*d83cc019SAndroid Build Coastguard Worker } gpu_process_t;
141*d83cc019SAndroid Build Coastguard Worker 
cleanup_crtc(gpu_process_t * gpu)142*d83cc019SAndroid Build Coastguard Worker static void cleanup_crtc(gpu_process_t *gpu)
143*d83cc019SAndroid Build Coastguard Worker {
144*d83cc019SAndroid Build Coastguard Worker 	igt_display_t *display = &gpu->display;
145*d83cc019SAndroid Build Coastguard Worker 	igt_output_t *output = gpu->output;
146*d83cc019SAndroid Build Coastguard Worker 
147*d83cc019SAndroid Build Coastguard Worker 	igt_plane_set_fb(gpu->primary, NULL);
148*d83cc019SAndroid Build Coastguard Worker 
149*d83cc019SAndroid Build Coastguard Worker 	igt_output_set_pipe(output, PIPE_ANY);
150*d83cc019SAndroid Build Coastguard Worker 	igt_display_commit(display);
151*d83cc019SAndroid Build Coastguard Worker 
152*d83cc019SAndroid Build Coastguard Worker 	igt_remove_fb(gpu->drm_fd, &gpu->fb);
153*d83cc019SAndroid Build Coastguard Worker }
154*d83cc019SAndroid Build Coastguard Worker 
prepare_crtc(gpu_process_t * gpu)155*d83cc019SAndroid Build Coastguard Worker static void prepare_crtc(gpu_process_t *gpu)
156*d83cc019SAndroid Build Coastguard Worker {
157*d83cc019SAndroid Build Coastguard Worker 	igt_display_t *display = &gpu->display;
158*d83cc019SAndroid Build Coastguard Worker 	igt_output_t *output = gpu->output;
159*d83cc019SAndroid Build Coastguard Worker 	drmModeModeInfo *mode;
160*d83cc019SAndroid Build Coastguard Worker 
161*d83cc019SAndroid Build Coastguard Worker 	/* select the pipe we want to use */
162*d83cc019SAndroid Build Coastguard Worker 	igt_output_set_pipe(output, gpu->pipe);
163*d83cc019SAndroid Build Coastguard Worker 
164*d83cc019SAndroid Build Coastguard Worker 	mode = igt_output_get_mode(output);
165*d83cc019SAndroid Build Coastguard Worker 
166*d83cc019SAndroid Build Coastguard Worker 	/* create a white fb and flip to it */
167*d83cc019SAndroid Build Coastguard Worker 	igt_create_color_fb(gpu->drm_fd, mode->hdisplay, mode->vdisplay,
168*d83cc019SAndroid Build Coastguard Worker 			DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
169*d83cc019SAndroid Build Coastguard Worker 			1.0, 1.0, 1.0, &gpu->fb);
170*d83cc019SAndroid Build Coastguard Worker 
171*d83cc019SAndroid Build Coastguard Worker 	gpu->primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
172*d83cc019SAndroid Build Coastguard Worker 
173*d83cc019SAndroid Build Coastguard Worker 	igt_plane_set_fb(gpu->primary, &gpu->fb);
174*d83cc019SAndroid Build Coastguard Worker 	igt_display_commit(display);
175*d83cc019SAndroid Build Coastguard Worker }
176*d83cc019SAndroid Build Coastguard Worker 
177*d83cc019SAndroid Build Coastguard Worker /*
178*d83cc019SAndroid Build Coastguard Worker  * The idea is to create a BO (in this case the framebuffer's) in one process,
179*d83cc019SAndroid Build Coastguard Worker  * export and pass its prime fd to another process, which in turn uses the fd
180*d83cc019SAndroid Build Coastguard Worker  * to map and write. This is Chrome-like architectures, where the Web content
181*d83cc019SAndroid Build Coastguard Worker  * (a "tab" or the "unprivileged process") maps and CPU-paints a buffer, which
182*d83cc019SAndroid Build Coastguard Worker  * was previously allocated in the GPU process ("privileged process").
183*d83cc019SAndroid Build Coastguard Worker  */
run_test(gpu_process_t * gpu)184*d83cc019SAndroid Build Coastguard Worker static void run_test(gpu_process_t *gpu)
185*d83cc019SAndroid Build Coastguard Worker {
186*d83cc019SAndroid Build Coastguard Worker 	igt_display_t *display = &gpu->display;
187*d83cc019SAndroid Build Coastguard Worker 	igt_output_t *output;
188*d83cc019SAndroid Build Coastguard Worker 	enum pipe pipe;
189*d83cc019SAndroid Build Coastguard Worker 	int prime_fd;
190*d83cc019SAndroid Build Coastguard Worker 
191*d83cc019SAndroid Build Coastguard Worker 	for_each_pipe_with_valid_output(display, pipe, output) {
192*d83cc019SAndroid Build Coastguard Worker 		gpu->output = output;
193*d83cc019SAndroid Build Coastguard Worker 		gpu->pipe = pipe;
194*d83cc019SAndroid Build Coastguard Worker 
195*d83cc019SAndroid Build Coastguard Worker 		prepare_crtc(gpu);
196*d83cc019SAndroid Build Coastguard Worker 
197*d83cc019SAndroid Build Coastguard Worker 		prime_fd = prime_handle_to_fd_for_mmap(gpu->drm_fd,
198*d83cc019SAndroid Build Coastguard Worker 							gpu->fb.gem_handle);
199*d83cc019SAndroid Build Coastguard Worker 		igt_skip_on(prime_fd == -1 && errno == EINVAL);
200*d83cc019SAndroid Build Coastguard Worker 
201*d83cc019SAndroid Build Coastguard Worker 		/* Note that it only shares the dma-buf fd and some
202*d83cc019SAndroid Build Coastguard Worker 		  * other basic info */
203*d83cc019SAndroid Build Coastguard Worker 		igt_fork(renderer_no, 1) {
204*d83cc019SAndroid Build Coastguard Worker 			init_renderer(prime_fd, gpu->fb.size, gpu->fb.width,
205*d83cc019SAndroid Build Coastguard Worker 				      gpu->fb.height);
206*d83cc019SAndroid Build Coastguard Worker 		}
207*d83cc019SAndroid Build Coastguard Worker 		igt_waitchildren();
208*d83cc019SAndroid Build Coastguard Worker 
209*d83cc019SAndroid Build Coastguard Worker 		igt_debug_wait_for_keypress("paint");
210*d83cc019SAndroid Build Coastguard Worker 		cleanup_crtc(gpu);
211*d83cc019SAndroid Build Coastguard Worker 
212*d83cc019SAndroid Build Coastguard Worker 		/* once is enough */
213*d83cc019SAndroid Build Coastguard Worker 		return;
214*d83cc019SAndroid Build Coastguard Worker 	}
215*d83cc019SAndroid Build Coastguard Worker 
216*d83cc019SAndroid Build Coastguard Worker 	igt_skip("no valid crtc/connector combinations found\n");
217*d83cc019SAndroid Build Coastguard Worker }
218*d83cc019SAndroid Build Coastguard Worker 
219*d83cc019SAndroid Build Coastguard Worker static int
check_for_dma_buf_mmap(int fd)220*d83cc019SAndroid Build Coastguard Worker check_for_dma_buf_mmap(int fd)
221*d83cc019SAndroid Build Coastguard Worker {
222*d83cc019SAndroid Build Coastguard Worker 	int dma_buf_fd;
223*d83cc019SAndroid Build Coastguard Worker 	char *ptr;
224*d83cc019SAndroid Build Coastguard Worker 	uint32_t handle;
225*d83cc019SAndroid Build Coastguard Worker 	int ret = 1;
226*d83cc019SAndroid Build Coastguard Worker 
227*d83cc019SAndroid Build Coastguard Worker 	handle = gem_create(fd, 4096);
228*d83cc019SAndroid Build Coastguard Worker 	dma_buf_fd = prime_handle_to_fd(fd, handle);
229*d83cc019SAndroid Build Coastguard Worker 	ptr = mmap(NULL, 4096, PROT_READ, MAP_SHARED, dma_buf_fd, 0);
230*d83cc019SAndroid Build Coastguard Worker 	if (ptr != MAP_FAILED)
231*d83cc019SAndroid Build Coastguard Worker 		ret = 0;
232*d83cc019SAndroid Build Coastguard Worker 	munmap(ptr, 4096);
233*d83cc019SAndroid Build Coastguard Worker 	gem_close(fd, handle);
234*d83cc019SAndroid Build Coastguard Worker 	close(dma_buf_fd);
235*d83cc019SAndroid Build Coastguard Worker 	return ret;
236*d83cc019SAndroid Build Coastguard Worker }
237*d83cc019SAndroid Build Coastguard Worker 
238*d83cc019SAndroid Build Coastguard Worker igt_main
239*d83cc019SAndroid Build Coastguard Worker {
240*d83cc019SAndroid Build Coastguard Worker 	gpu_process_t gpu;
241*d83cc019SAndroid Build Coastguard Worker 
242*d83cc019SAndroid Build Coastguard Worker 	igt_skip_on_simulation();
243*d83cc019SAndroid Build Coastguard Worker 
244*d83cc019SAndroid Build Coastguard Worker 	igt_fixture {
245*d83cc019SAndroid Build Coastguard Worker 		gpu.drm_fd = drm_open_driver_master(DRIVER_INTEL);
246*d83cc019SAndroid Build Coastguard Worker 		igt_skip_on((check_for_dma_buf_mmap(gpu.drm_fd) != 0));
247*d83cc019SAndroid Build Coastguard Worker 		kmstest_set_vt_graphics_mode();
248*d83cc019SAndroid Build Coastguard Worker 
249*d83cc019SAndroid Build Coastguard Worker 		igt_require_pipe_crc(gpu.drm_fd);
250*d83cc019SAndroid Build Coastguard Worker 
251*d83cc019SAndroid Build Coastguard Worker 		igt_display_require(&gpu.display, gpu.drm_fd);
252*d83cc019SAndroid Build Coastguard Worker 	}
253*d83cc019SAndroid Build Coastguard Worker 
254*d83cc019SAndroid Build Coastguard Worker 	igt_subtest("buffer-sharing")
255*d83cc019SAndroid Build Coastguard Worker 		run_test(&gpu);
256*d83cc019SAndroid Build Coastguard Worker 
257*d83cc019SAndroid Build Coastguard Worker 	igt_fixture {
258*d83cc019SAndroid Build Coastguard Worker 		igt_display_fini(&gpu.display);
259*d83cc019SAndroid Build Coastguard Worker 		close(gpu.drm_fd);
260*d83cc019SAndroid Build Coastguard Worker 	}
261*d83cc019SAndroid Build Coastguard Worker }
262