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