[Intel-gfx] [PATCH v4] prime_mmap_kms: show case dma-buf new API and processes restrictions

Marius Vlad marius.c.vlad at intel.com
Mon May 9 11:49:07 UTC 2016


Pushed. Thanks!
On Fri, May 06, 2016 at 04:51:29PM -0300, Tiago Vignatti wrote:
> dma-buf new API consists of:
> 
> - mmap(dma_buf_fd, ...): the ability to map a dma-buf file-descriptor of a
> graphics buffer to the userspace, and more importantly, to actually write on
> the mapped pointer (which was not possible before). It’s worth noting that the
> Direct Rendering Manager (DRM) and the hardware driver implementation are
> fundamentally important to safely export the graphics handle to be mapped.
> 
> - ioctl(dma_buf_fd, DMA_BUF_IOCTL_SYNC, &args): cache coherency management in
> cases where the CPU and GPU devices are being accessed through dma-buf at the
> same time. Coherency markers, which forward directly to existing dma-buf
> device drivers vfunc hooks, are exposed to the userspace through the
> DMA_BUF_IOCTL_SYNC ioctl and have to be used before and after the mapped area
> is accessed. This is fundamentally important in hardware architectures where
> the graphics engine and the CPU cores don't share caches but also important in
> other type of hardware where the memory hierarchy is (most of the time)
> coherent. More details can be found in this patch set:
> 
> http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c11e391da2a8fe973c3c2398452000bed505851e
> 
> v2: use uint32_t for color type, increment the variable and add
> --interactive-debug=paint
> v3: use igt_display_commit() to mode set the crtc so the rectangle is shown
> painted; also added Testcase description on the beginning of the file.
> v4: remove crtc actually which seems superfluous; add a igt_skip_on in case
> support for dma-buf mmap is nonexistent.
> 
> Signed-off-by: Tiago Vignatti <tiago.vignatti at intel.com>
> ---
>  tests/Makefile.sources |   1 +
>  tests/prime_mmap_kms.c | 275 +++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 276 insertions(+)
>  create mode 100644 tests/prime_mmap_kms.c
> 
> diff --git a/tests/Makefile.sources b/tests/Makefile.sources
> index 9ea9b5b..7b5f316 100644
> --- a/tests/Makefile.sources
> +++ b/tests/Makefile.sources
> @@ -113,6 +113,7 @@ TESTS_progs_M = \
>  	pm_sseu \
>  	prime_mmap \
>  	prime_mmap_coherency \
> +	prime_mmap_kms \
>  	prime_self_import \
>  	template \
>  	$(NULL)
> diff --git a/tests/prime_mmap_kms.c b/tests/prime_mmap_kms.c
> new file mode 100644
> index 0000000..8e14b25
> --- /dev/null
> +++ b/tests/prime_mmap_kms.c
> @@ -0,0 +1,275 @@
> +/*
> + * Copyright © 2016 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Tiago Vignatti <tiago.vignatti at intel.com>
> + */
> +
> +/*
> + * Testcase: show case dma-buf new API and processes restrictions. Most likely
> + * you want to run like ./prime_mmap_kms --interactive-debug=paint, to see the
> + * actual rectangle painted on the screen.
> + */
> +
> +#include "igt.h"
> +
> +IGT_TEST_DESCRIPTION(
> +   "Efficiently sharing CPU and GPU buffers");
> +
> +/*
> + * render_process_t:
> + *
> + * Render is basically a user-space regular client. It's the unprivileged
> + * process with limited system accesses.
> + *
> + * Worth note the vendor-independent characteristic, meaning that the
> + * client doesn't need to perform any vendor specific calls for buffer
> + * handling. Mesa GBM library is a counter-example because, even though its API
> + * is vendor-independent, under-the-hood the library actually calls vendor
> + * specific ioctls, which is not really sandboxable and not the goal here.
> + */
> +typedef struct {
> +	int prime_fd;
> +	size_t size;
> +	int width;
> +	int height;
> +} render_process_t;
> +
> +typedef struct {
> +	int x;
> +	int y;
> +	int w;
> +	int h;
> +} rect_t;
> +
> +/* set ptr in a linear view */
> +static void set_pixel(void *_ptr, int index, uint32_t color, int bpp)
> +{
> +	if (bpp == 16) {
> +		uint16_t *ptr = _ptr;
> +		ptr[index] = color;
> +	} else if (bpp == 32) {
> +		uint32_t *ptr = _ptr;
> +		ptr[index] = color;
> +	} else {
> +		igt_assert_f(false, "bpp: %d\n", bpp);
> +	}
> +}
> +
> +static void paint(render_process_t *render)
> +{
> +	void *frame;
> +	rect_t rect = {
> +		.x = 200,
> +		.y = 200,
> +		.w = render->width / 4,
> +		.h = render->height / 4,
> +	};
> +	uint32_t color = 0xFF;
> +	int stride, bpp;
> +	int x, y, line_begin;
> +
> +	frame = mmap(NULL, render->size, PROT_READ | PROT_WRITE, MAP_SHARED,
> +		     render->prime_fd, 0);
> +	igt_assert(frame != MAP_FAILED);
> +
> +	/* TODO: what's the mmap'ed buffer semantics on tiling, format etc. How
> +	 * does the client know whether that the BO was created X-tiled,
> +	 * Y-tiled and how it will map back? This is something we need to
> +	 * address in this API still. */
> +	stride = render->width * 4;
> +	bpp = 32;
> +
> +	/* ioctls to keep up the GPU <-> CPU coherency */
> +	prime_sync_start(render->prime_fd, true);
> +
> +	/* the actual painting phase happens here */
> +	for (y = rect.y; y < rect.y + rect.h; y++) {
> +		line_begin = y * stride / (bpp / 8);
> +		for (x = rect.x; x < rect.x + rect.w; x++)
> +			set_pixel(frame, line_begin + x, color, bpp);
> +	}
> +
> +	prime_sync_end(render->prime_fd, true);
> +	munmap(frame, render->size);
> +}
> +
> +static void init_renderer(int prime_fd, int fb_size, int width, int height)
> +{
> +	render_process_t render;
> +
> +	render.prime_fd = prime_fd;
> +	render.size = fb_size;
> +	render.width = width;
> +	render.height = height;
> +	paint(&render);
> +}
> +
> +/*
> + * gpu_process_t:
> + *
> + * GPU process is the privileged process and has access to the system graphics
> + * routines, like DRM, display management and driver accesses.
> + */
> +typedef struct {
> +	int drm_fd;
> +	igt_display_t display;
> +	struct igt_fb fb;
> +	igt_output_t *output;
> +	igt_plane_t *primary;
> +	enum pipe pipe;
> +} gpu_process_t;
> +
> +static void cleanup_crtc(gpu_process_t *gpu)
> +{
> +	igt_display_t *display = &gpu->display;
> +	igt_output_t *output = gpu->output;
> +
> +	igt_plane_set_fb(gpu->primary, NULL);
> +
> +	igt_output_set_pipe(output, PIPE_ANY);
> +	igt_display_commit(display);
> +
> +	igt_remove_fb(gpu->drm_fd, &gpu->fb);
> +}
> +
> +static bool prepare_crtc(gpu_process_t *gpu)
> +{
> +	igt_display_t *display = &gpu->display;
> +	igt_output_t *output = gpu->output;
> +	drmModeModeInfo *mode;
> +
> +	/* select the pipe we want to use */
> +	igt_output_set_pipe(output, gpu->pipe);
> +	igt_display_commit(display);
> +
> +	if (!output->valid) {
> +		igt_output_set_pipe(output, PIPE_ANY);
> +		igt_display_commit(display);
> +		return false;
> +	}
> +
> +	mode = igt_output_get_mode(output);
> +
> +	/* create a white fb and flip to it */
> +	igt_create_color_fb(gpu->drm_fd, mode->hdisplay, mode->vdisplay,
> +			DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
> +			1.0, 1.0, 1.0, &gpu->fb);
> +
> +	gpu->primary = igt_output_get_plane(output, IGT_PLANE_PRIMARY);
> +
> +	igt_plane_set_fb(gpu->primary, &gpu->fb);
> +	igt_display_commit(display);
> +
> +	return true;
> +}
> +
> +/*
> + * The idea is to create a BO (in this case the framebuffer's) in one process,
> + * export and pass its prime fd to another process, which in turn uses the fd
> + * to map and write. This is Chrome-like architectures, where the Web content
> + * (a "tab" or the "unprivileged process") maps and CPU-paints a buffer, which
> + * was previously allocated in the GPU process ("privileged process").
> + */
> +static void run_test(gpu_process_t *gpu)
> +{
> +	igt_display_t *display = &gpu->display;
> +	igt_output_t *output;
> +	enum pipe pipe;
> +	int prime_fd;
> +
> +	for_each_connected_output(display, output) {
> +		gpu->output = output;
> +		for_each_pipe(display, pipe) {
> +			gpu->pipe = pipe;
> +
> +			if (!prepare_crtc(gpu))
> +				continue;
> +
> +			prime_fd = prime_handle_to_fd_for_mmap(gpu->drm_fd,
> +			                                       gpu->fb.gem_handle);
> +			igt_skip_on(prime_fd == -1 && errno == EINVAL);
> +
> +			/* Note that it only shares the dma-buf fd and some
> +			 * other basic info */
> +			igt_fork(renderer_no, 1) {
> +				init_renderer(prime_fd, gpu->fb.size, gpu->fb.width,
> +					      gpu->fb.height);
> +			}
> +			igt_waitchildren();
> +
> +			igt_debug_wait_for_keypress("paint");
> +			cleanup_crtc(gpu);
> +
> +			/* once is enough */
> +			return;
> +		}
> +	}
> +
> +	igt_skip("no valid crtc/connector combinations found\n");
> +}
> +
> +static int
> +check_for_dma_buf_mmap(int fd)
> +{
> +	int dma_buf_fd;
> +	char *ptr;
> +	uint32_t handle;
> +	int ret = 1;
> +
> +	handle = gem_create(fd, 4096);
> +	dma_buf_fd = prime_handle_to_fd(fd, handle);
> +	ptr = mmap(NULL, 4096, PROT_READ, MAP_SHARED, dma_buf_fd, 0);
> +	if (ptr != MAP_FAILED)
> +		ret = 0;
> +	munmap(ptr, 4096);
> +	gem_close(fd, handle);
> +	close(dma_buf_fd);
> +	return ret;
> +}
> +
> +igt_main
> +{
> +	gpu_process_t gpu;
> +
> +	igt_skip_on_simulation();
> +
> +	igt_fixture {
> +		gpu.drm_fd = drm_open_driver_master(DRIVER_INTEL);
> +		igt_skip_on((check_for_dma_buf_mmap(gpu.drm_fd) != 0));
> +		kmstest_set_vt_graphics_mode();
> +
> +		igt_require_pipe_crc();
> +
> +		igt_display_init(&gpu.display, gpu.drm_fd);
> +	}
> +
> +	igt_subtest("buffer-sharing")
> +		run_test(&gpu);
> +
> +	igt_fixture {
> +		igt_display_fini(&gpu.display);
> +		close(gpu.drm_fd);
> +	}
> +
> +	igt_exit();
> +}
> -- 
> 2.7.4
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: Digital signature
URL: <https://lists.freedesktop.org/archives/intel-gfx/attachments/20160509/b6cc1cbb/attachment-0001.sig>


More information about the Intel-gfx mailing list