xref: /aosp_15_r20/external/minigbm/virtgpu_cross_domain.c (revision d95af8df99a05bcb8679a54dc3ab8e5cd312b38e)
1*d95af8dfSAndroid Build Coastguard Worker /*
2*d95af8dfSAndroid Build Coastguard Worker  * Copyright 2021 The Chromium OS Authors. All rights reserved.
3*d95af8dfSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
4*d95af8dfSAndroid Build Coastguard Worker  * found in the LICENSE file.
5*d95af8dfSAndroid Build Coastguard Worker  */
6*d95af8dfSAndroid Build Coastguard Worker 
7*d95af8dfSAndroid Build Coastguard Worker #include <errno.h>
8*d95af8dfSAndroid Build Coastguard Worker #include <string.h>
9*d95af8dfSAndroid Build Coastguard Worker #include <sys/mman.h>
10*d95af8dfSAndroid Build Coastguard Worker #include <xf86drm.h>
11*d95af8dfSAndroid Build Coastguard Worker 
12*d95af8dfSAndroid Build Coastguard Worker #include "drv_helpers.h"
13*d95af8dfSAndroid Build Coastguard Worker #include "drv_priv.h"
14*d95af8dfSAndroid Build Coastguard Worker #include "external/virtgpu_cross_domain_protocol.h"
15*d95af8dfSAndroid Build Coastguard Worker #include "external/virtgpu_drm.h"
16*d95af8dfSAndroid Build Coastguard Worker #include "util.h"
17*d95af8dfSAndroid Build Coastguard Worker #include "virtgpu.h"
18*d95af8dfSAndroid Build Coastguard Worker 
19*d95af8dfSAndroid Build Coastguard Worker #define CAPSET_CROSS_FAKE 30
20*d95af8dfSAndroid Build Coastguard Worker 
21*d95af8dfSAndroid Build Coastguard Worker static const uint32_t scanout_render_formats[] = { DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888,
22*d95af8dfSAndroid Build Coastguard Worker 						   DRM_FORMAT_RGB565, DRM_FORMAT_XBGR8888,
23*d95af8dfSAndroid Build Coastguard Worker 						   DRM_FORMAT_XRGB8888 };
24*d95af8dfSAndroid Build Coastguard Worker 
25*d95af8dfSAndroid Build Coastguard Worker static const uint32_t texture_only_formats[] = {
26*d95af8dfSAndroid Build Coastguard Worker 	DRM_FORMAT_R8,		 DRM_FORMAT_NV12,	    DRM_FORMAT_P010,
27*d95af8dfSAndroid Build Coastguard Worker 	DRM_FORMAT_YVU420,	 DRM_FORMAT_YVU420_ANDROID, DRM_FORMAT_ABGR2101010,
28*d95af8dfSAndroid Build Coastguard Worker 	DRM_FORMAT_ARGB2101010,	 DRM_FORMAT_XBGR2101010,    DRM_FORMAT_XRGB2101010,
29*d95af8dfSAndroid Build Coastguard Worker 	DRM_FORMAT_ABGR16161616F
30*d95af8dfSAndroid Build Coastguard Worker };
31*d95af8dfSAndroid Build Coastguard Worker 
32*d95af8dfSAndroid Build Coastguard Worker extern struct virtgpu_param params[];
33*d95af8dfSAndroid Build Coastguard Worker 
34*d95af8dfSAndroid Build Coastguard Worker struct cross_domain_private {
35*d95af8dfSAndroid Build Coastguard Worker 	uint32_t ring_handle;
36*d95af8dfSAndroid Build Coastguard Worker 	void *ring_addr;
37*d95af8dfSAndroid Build Coastguard Worker 	struct drv_array *metadata_cache;
38*d95af8dfSAndroid Build Coastguard Worker 	pthread_mutex_t metadata_cache_lock;
39*d95af8dfSAndroid Build Coastguard Worker 	bool mt8183_camera_quirk_;
40*d95af8dfSAndroid Build Coastguard Worker };
41*d95af8dfSAndroid Build Coastguard Worker 
cross_domain_release_private(struct driver * drv)42*d95af8dfSAndroid Build Coastguard Worker static void cross_domain_release_private(struct driver *drv)
43*d95af8dfSAndroid Build Coastguard Worker {
44*d95af8dfSAndroid Build Coastguard Worker 	int ret;
45*d95af8dfSAndroid Build Coastguard Worker 	struct cross_domain_private *priv = drv->priv;
46*d95af8dfSAndroid Build Coastguard Worker 	struct drm_gem_close gem_close = { 0 };
47*d95af8dfSAndroid Build Coastguard Worker 
48*d95af8dfSAndroid Build Coastguard Worker 	if (priv->ring_addr != MAP_FAILED)
49*d95af8dfSAndroid Build Coastguard Worker 		munmap(priv->ring_addr, PAGE_SIZE);
50*d95af8dfSAndroid Build Coastguard Worker 
51*d95af8dfSAndroid Build Coastguard Worker 	if (priv->ring_handle) {
52*d95af8dfSAndroid Build Coastguard Worker 		gem_close.handle = priv->ring_handle;
53*d95af8dfSAndroid Build Coastguard Worker 
54*d95af8dfSAndroid Build Coastguard Worker 		ret = drmIoctl(drv->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
55*d95af8dfSAndroid Build Coastguard Worker 		if (ret) {
56*d95af8dfSAndroid Build Coastguard Worker 			drv_loge("DRM_IOCTL_GEM_CLOSE failed (handle=%x) error %d\n",
57*d95af8dfSAndroid Build Coastguard Worker 				 priv->ring_handle, ret);
58*d95af8dfSAndroid Build Coastguard Worker 		}
59*d95af8dfSAndroid Build Coastguard Worker 	}
60*d95af8dfSAndroid Build Coastguard Worker 
61*d95af8dfSAndroid Build Coastguard Worker 	if (priv->metadata_cache)
62*d95af8dfSAndroid Build Coastguard Worker 		drv_array_destroy(priv->metadata_cache);
63*d95af8dfSAndroid Build Coastguard Worker 
64*d95af8dfSAndroid Build Coastguard Worker 	pthread_mutex_destroy(&priv->metadata_cache_lock);
65*d95af8dfSAndroid Build Coastguard Worker 
66*d95af8dfSAndroid Build Coastguard Worker 	free(priv);
67*d95af8dfSAndroid Build Coastguard Worker }
68*d95af8dfSAndroid Build Coastguard Worker 
add_combinations(struct driver * drv)69*d95af8dfSAndroid Build Coastguard Worker static void add_combinations(struct driver *drv)
70*d95af8dfSAndroid Build Coastguard Worker {
71*d95af8dfSAndroid Build Coastguard Worker 	struct format_metadata metadata;
72*d95af8dfSAndroid Build Coastguard Worker 
73*d95af8dfSAndroid Build Coastguard Worker 	// Linear metadata always supported.
74*d95af8dfSAndroid Build Coastguard Worker 	metadata.tiling = 0;
75*d95af8dfSAndroid Build Coastguard Worker 	metadata.priority = 1;
76*d95af8dfSAndroid Build Coastguard Worker 	metadata.modifier = DRM_FORMAT_MOD_LINEAR;
77*d95af8dfSAndroid Build Coastguard Worker 
78*d95af8dfSAndroid Build Coastguard Worker 	drv_add_combinations(drv, scanout_render_formats, ARRAY_SIZE(scanout_render_formats),
79*d95af8dfSAndroid Build Coastguard Worker 			     &metadata, BO_USE_RENDER_MASK | BO_USE_SCANOUT);
80*d95af8dfSAndroid Build Coastguard Worker 
81*d95af8dfSAndroid Build Coastguard Worker 	drv_add_combinations(drv, texture_only_formats, ARRAY_SIZE(texture_only_formats), &metadata,
82*d95af8dfSAndroid Build Coastguard Worker 			     BO_USE_TEXTURE_MASK);
83*d95af8dfSAndroid Build Coastguard Worker 
84*d95af8dfSAndroid Build Coastguard Worker 	/* Android CTS tests require this. */
85*d95af8dfSAndroid Build Coastguard Worker 	drv_add_combination(drv, DRM_FORMAT_BGR888, &metadata, BO_USE_SW_MASK);
86*d95af8dfSAndroid Build Coastguard Worker 
87*d95af8dfSAndroid Build Coastguard Worker 	drv_modify_combination(drv, DRM_FORMAT_YVU420, &metadata, BO_USE_HW_VIDEO_ENCODER);
88*d95af8dfSAndroid Build Coastguard Worker 	drv_modify_combination(drv, DRM_FORMAT_NV12, &metadata,
89*d95af8dfSAndroid Build Coastguard Worker 			       BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER |
90*d95af8dfSAndroid Build Coastguard Worker 				   BO_USE_SCANOUT | BO_USE_HW_VIDEO_ENCODER);
91*d95af8dfSAndroid Build Coastguard Worker 
92*d95af8dfSAndroid Build Coastguard Worker 	/*
93*d95af8dfSAndroid Build Coastguard Worker 	 * R8 format is used for Android's HAL_PIXEL_FORMAT_BLOB and is used for JPEG snapshots
94*d95af8dfSAndroid Build Coastguard Worker 	 * from camera, input/output from hardware decoder/encoder and sensors, and
95*d95af8dfSAndroid Build Coastguard Worker 	 * AHBs used as SSBOs/UBOs.
96*d95af8dfSAndroid Build Coastguard Worker 	 */
97*d95af8dfSAndroid Build Coastguard Worker 	drv_modify_combination(drv, DRM_FORMAT_R8, &metadata,
98*d95af8dfSAndroid Build Coastguard Worker 			       BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER |
99*d95af8dfSAndroid Build Coastguard Worker 				   BO_USE_HW_VIDEO_ENCODER | BO_USE_SENSOR_DIRECT_DATA |
100*d95af8dfSAndroid Build Coastguard Worker 				   BO_USE_GPU_DATA_BUFFER);
101*d95af8dfSAndroid Build Coastguard Worker 
102*d95af8dfSAndroid Build Coastguard Worker 	drv_modify_linear_combinations(drv);
103*d95af8dfSAndroid Build Coastguard Worker }
104*d95af8dfSAndroid Build Coastguard Worker 
cross_domain_submit_cmd(struct driver * drv,uint32_t * cmd,uint32_t cmd_size,bool wait)105*d95af8dfSAndroid Build Coastguard Worker static int cross_domain_submit_cmd(struct driver *drv, uint32_t *cmd, uint32_t cmd_size, bool wait)
106*d95af8dfSAndroid Build Coastguard Worker {
107*d95af8dfSAndroid Build Coastguard Worker 	int ret;
108*d95af8dfSAndroid Build Coastguard Worker 	struct drm_virtgpu_3d_wait wait_3d = { 0 };
109*d95af8dfSAndroid Build Coastguard Worker 	struct drm_virtgpu_execbuffer exec = { 0 };
110*d95af8dfSAndroid Build Coastguard Worker 	struct cross_domain_private *priv = drv->priv;
111*d95af8dfSAndroid Build Coastguard Worker 
112*d95af8dfSAndroid Build Coastguard Worker 	exec.flags = VIRTGPU_EXECBUF_RING_IDX;
113*d95af8dfSAndroid Build Coastguard Worker 	exec.command = (uint64_t)&cmd[0];
114*d95af8dfSAndroid Build Coastguard Worker 	exec.size = cmd_size;
115*d95af8dfSAndroid Build Coastguard Worker 	if (wait) {
116*d95af8dfSAndroid Build Coastguard Worker 		exec.bo_handles = (uint64_t)&priv->ring_handle;
117*d95af8dfSAndroid Build Coastguard Worker 		exec.num_bo_handles = 1;
118*d95af8dfSAndroid Build Coastguard Worker 	}
119*d95af8dfSAndroid Build Coastguard Worker 
120*d95af8dfSAndroid Build Coastguard Worker 	ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_EXECBUFFER, &exec);
121*d95af8dfSAndroid Build Coastguard Worker 	if (ret < 0) {
122*d95af8dfSAndroid Build Coastguard Worker 		drv_loge("DRM_IOCTL_VIRTGPU_EXECBUFFER failed with %s\n", strerror(errno));
123*d95af8dfSAndroid Build Coastguard Worker 		return -EINVAL;
124*d95af8dfSAndroid Build Coastguard Worker 	}
125*d95af8dfSAndroid Build Coastguard Worker 
126*d95af8dfSAndroid Build Coastguard Worker 	ret = -EAGAIN;
127*d95af8dfSAndroid Build Coastguard Worker 	while (ret == -EAGAIN) {
128*d95af8dfSAndroid Build Coastguard Worker 		wait_3d.handle = priv->ring_handle;
129*d95af8dfSAndroid Build Coastguard Worker 		ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_WAIT, &wait_3d);
130*d95af8dfSAndroid Build Coastguard Worker 	}
131*d95af8dfSAndroid Build Coastguard Worker 
132*d95af8dfSAndroid Build Coastguard Worker 	if (ret < 0) {
133*d95af8dfSAndroid Build Coastguard Worker 		drv_loge("DRM_IOCTL_VIRTGPU_WAIT failed with %s\n", strerror(errno));
134*d95af8dfSAndroid Build Coastguard Worker 		return ret;
135*d95af8dfSAndroid Build Coastguard Worker 	}
136*d95af8dfSAndroid Build Coastguard Worker 
137*d95af8dfSAndroid Build Coastguard Worker 	return 0;
138*d95af8dfSAndroid Build Coastguard Worker }
139*d95af8dfSAndroid Build Coastguard Worker 
metadata_equal(struct bo_metadata * current,struct bo_metadata * cached)140*d95af8dfSAndroid Build Coastguard Worker static bool metadata_equal(struct bo_metadata *current, struct bo_metadata *cached)
141*d95af8dfSAndroid Build Coastguard Worker {
142*d95af8dfSAndroid Build Coastguard Worker 	if ((current->width == cached->width) && (current->height == cached->height) &&
143*d95af8dfSAndroid Build Coastguard Worker 	    (current->format == cached->format) && (current->use_flags == cached->use_flags))
144*d95af8dfSAndroid Build Coastguard Worker 		return true;
145*d95af8dfSAndroid Build Coastguard Worker 	return false;
146*d95af8dfSAndroid Build Coastguard Worker }
147*d95af8dfSAndroid Build Coastguard Worker 
cross_domain_metadata_query(struct driver * drv,struct bo_metadata * metadata)148*d95af8dfSAndroid Build Coastguard Worker static int cross_domain_metadata_query(struct driver *drv, struct bo_metadata *metadata)
149*d95af8dfSAndroid Build Coastguard Worker {
150*d95af8dfSAndroid Build Coastguard Worker 	int ret = 0;
151*d95af8dfSAndroid Build Coastguard Worker 	struct bo_metadata *cached_data = NULL;
152*d95af8dfSAndroid Build Coastguard Worker 	struct cross_domain_private *priv = drv->priv;
153*d95af8dfSAndroid Build Coastguard Worker 	struct CrossDomainGetImageRequirements cmd_get_reqs;
154*d95af8dfSAndroid Build Coastguard Worker 	uint32_t *addr = (uint32_t *)priv->ring_addr;
155*d95af8dfSAndroid Build Coastguard Worker 	uint32_t plane;
156*d95af8dfSAndroid Build Coastguard Worker 
157*d95af8dfSAndroid Build Coastguard Worker 	memset(&cmd_get_reqs, 0, sizeof(cmd_get_reqs));
158*d95af8dfSAndroid Build Coastguard Worker 	pthread_mutex_lock(&priv->metadata_cache_lock);
159*d95af8dfSAndroid Build Coastguard Worker 	for (uint32_t i = 0; i < drv_array_size(priv->metadata_cache); i++) {
160*d95af8dfSAndroid Build Coastguard Worker 		cached_data = (struct bo_metadata *)drv_array_at_idx(priv->metadata_cache, i);
161*d95af8dfSAndroid Build Coastguard Worker 		if (!metadata_equal(metadata, cached_data))
162*d95af8dfSAndroid Build Coastguard Worker 			continue;
163*d95af8dfSAndroid Build Coastguard Worker 
164*d95af8dfSAndroid Build Coastguard Worker 		memcpy(metadata, cached_data, sizeof(*cached_data));
165*d95af8dfSAndroid Build Coastguard Worker 		goto out_unlock;
166*d95af8dfSAndroid Build Coastguard Worker 	}
167*d95af8dfSAndroid Build Coastguard Worker 
168*d95af8dfSAndroid Build Coastguard Worker 	cmd_get_reqs.hdr.cmd = CROSS_DOMAIN_CMD_GET_IMAGE_REQUIREMENTS;
169*d95af8dfSAndroid Build Coastguard Worker 	cmd_get_reqs.hdr.cmd_size = sizeof(struct CrossDomainGetImageRequirements);
170*d95af8dfSAndroid Build Coastguard Worker 
171*d95af8dfSAndroid Build Coastguard Worker 	cmd_get_reqs.width = metadata->width;
172*d95af8dfSAndroid Build Coastguard Worker 	cmd_get_reqs.height = metadata->height;
173*d95af8dfSAndroid Build Coastguard Worker 	cmd_get_reqs.drm_format = metadata->format;
174*d95af8dfSAndroid Build Coastguard Worker 	cmd_get_reqs.flags = metadata->use_flags;
175*d95af8dfSAndroid Build Coastguard Worker 
176*d95af8dfSAndroid Build Coastguard Worker 	// HACK(b/360937659): see also: b/172389166,  for history
177*d95af8dfSAndroid Build Coastguard Worker 	// host minigbm has a hack that recognizes DRM_FORMAT_YVU420 + BO_USE_LINEAR and replaces
178*d95af8dfSAndroid Build Coastguard Worker 	// the format internally back to DRM_FORMAT_YVU420_ANDROID to use the approrpriate layout
179*d95af8dfSAndroid Build Coastguard Worker 	// rules.
180*d95af8dfSAndroid Build Coastguard Worker 	if (cmd_get_reqs.drm_format == DRM_FORMAT_YVU420_ANDROID) {
181*d95af8dfSAndroid Build Coastguard Worker 		cmd_get_reqs.drm_format = DRM_FORMAT_YVU420;
182*d95af8dfSAndroid Build Coastguard Worker 		cmd_get_reqs.flags |= BO_USE_LINEAR;
183*d95af8dfSAndroid Build Coastguard Worker 	}
184*d95af8dfSAndroid Build Coastguard Worker 
185*d95af8dfSAndroid Build Coastguard Worker 	/*
186*d95af8dfSAndroid Build Coastguard Worker 	 * It is possible to avoid blocking other bo_create() calls by unlocking before
187*d95af8dfSAndroid Build Coastguard Worker 	 * cross_domain_submit_cmd() and re-locking afterwards.  However, that would require
188*d95af8dfSAndroid Build Coastguard Worker 	 * another scan of the metadata cache before drv_array_append in case two bo_create() calls
189*d95af8dfSAndroid Build Coastguard Worker 	 * do the same metadata query.  Until cross_domain functionality is more widely tested,
190*d95af8dfSAndroid Build Coastguard Worker 	 * leave this optimization out for now.
191*d95af8dfSAndroid Build Coastguard Worker 	 */
192*d95af8dfSAndroid Build Coastguard Worker 	ret = cross_domain_submit_cmd(drv, (uint32_t *)&cmd_get_reqs, cmd_get_reqs.hdr.cmd_size,
193*d95af8dfSAndroid Build Coastguard Worker 				      true);
194*d95af8dfSAndroid Build Coastguard Worker 	if (ret < 0)
195*d95af8dfSAndroid Build Coastguard Worker 		goto out_unlock;
196*d95af8dfSAndroid Build Coastguard Worker 
197*d95af8dfSAndroid Build Coastguard Worker 	memcpy(&metadata->strides, &addr[0], 4 * sizeof(uint32_t));
198*d95af8dfSAndroid Build Coastguard Worker 	memcpy(&metadata->offsets, &addr[4], 4 * sizeof(uint32_t));
199*d95af8dfSAndroid Build Coastguard Worker 	memcpy(&metadata->format_modifier, &addr[8], sizeof(uint64_t));
200*d95af8dfSAndroid Build Coastguard Worker 	memcpy(&metadata->total_size, &addr[10], sizeof(uint64_t));
201*d95af8dfSAndroid Build Coastguard Worker 	memcpy(&metadata->blob_id, &addr[12], sizeof(uint32_t));
202*d95af8dfSAndroid Build Coastguard Worker 
203*d95af8dfSAndroid Build Coastguard Worker 	metadata->map_info = addr[13];
204*d95af8dfSAndroid Build Coastguard Worker 	metadata->memory_idx = addr[14];
205*d95af8dfSAndroid Build Coastguard Worker 	metadata->physical_device_idx = addr[15];
206*d95af8dfSAndroid Build Coastguard Worker 
207*d95af8dfSAndroid Build Coastguard Worker 	for (plane = 1; plane < metadata->num_planes; plane++) {
208*d95af8dfSAndroid Build Coastguard Worker 		metadata->sizes[plane - 1] =
209*d95af8dfSAndroid Build Coastguard Worker 		    metadata->offsets[plane] - metadata->offsets[plane - 1];
210*d95af8dfSAndroid Build Coastguard Worker 	}
211*d95af8dfSAndroid Build Coastguard Worker 	metadata->sizes[plane - 1] = metadata->total_size - metadata->offsets[plane - 1];
212*d95af8dfSAndroid Build Coastguard Worker 
213*d95af8dfSAndroid Build Coastguard Worker 	drv_array_append(priv->metadata_cache, metadata);
214*d95af8dfSAndroid Build Coastguard Worker 
215*d95af8dfSAndroid Build Coastguard Worker out_unlock:
216*d95af8dfSAndroid Build Coastguard Worker 	pthread_mutex_unlock(&priv->metadata_cache_lock);
217*d95af8dfSAndroid Build Coastguard Worker 	return ret;
218*d95af8dfSAndroid Build Coastguard Worker }
219*d95af8dfSAndroid Build Coastguard Worker 
220*d95af8dfSAndroid Build Coastguard Worker /* Fill out metadata for guest buffers, used only for CPU access: */
cross_domain_get_emulated_metadata(struct bo_metadata * metadata)221*d95af8dfSAndroid Build Coastguard Worker void cross_domain_get_emulated_metadata(struct bo_metadata *metadata)
222*d95af8dfSAndroid Build Coastguard Worker {
223*d95af8dfSAndroid Build Coastguard Worker 	uint32_t offset = 0;
224*d95af8dfSAndroid Build Coastguard Worker 
225*d95af8dfSAndroid Build Coastguard Worker 	for (size_t i = 0; i < metadata->num_planes; i++) {
226*d95af8dfSAndroid Build Coastguard Worker 		metadata->strides[i] = drv_stride_from_format(metadata->format, metadata->width, i);
227*d95af8dfSAndroid Build Coastguard Worker 		metadata->sizes[i] = drv_size_from_format(metadata->format, metadata->strides[i],
228*d95af8dfSAndroid Build Coastguard Worker 							  metadata->height, i);
229*d95af8dfSAndroid Build Coastguard Worker 		metadata->offsets[i] = offset;
230*d95af8dfSAndroid Build Coastguard Worker 		offset += metadata->sizes[i];
231*d95af8dfSAndroid Build Coastguard Worker 	}
232*d95af8dfSAndroid Build Coastguard Worker 
233*d95af8dfSAndroid Build Coastguard Worker 	metadata->total_size = offset;
234*d95af8dfSAndroid Build Coastguard Worker }
235*d95af8dfSAndroid Build Coastguard Worker 
cross_domain_init(struct driver * drv)236*d95af8dfSAndroid Build Coastguard Worker static int cross_domain_init(struct driver *drv)
237*d95af8dfSAndroid Build Coastguard Worker {
238*d95af8dfSAndroid Build Coastguard Worker 	int ret;
239*d95af8dfSAndroid Build Coastguard Worker 	struct cross_domain_private *priv;
240*d95af8dfSAndroid Build Coastguard Worker 	struct drm_virtgpu_map map = { 0 };
241*d95af8dfSAndroid Build Coastguard Worker 	struct drm_virtgpu_get_caps args = { 0 };
242*d95af8dfSAndroid Build Coastguard Worker 	struct drm_virtgpu_context_init init = { 0 };
243*d95af8dfSAndroid Build Coastguard Worker 	struct drm_virtgpu_resource_create_blob drm_rc_blob = { 0 };
244*d95af8dfSAndroid Build Coastguard Worker 	struct drm_virtgpu_context_set_param ctx_set_params[2] = { { 0 } };
245*d95af8dfSAndroid Build Coastguard Worker 
246*d95af8dfSAndroid Build Coastguard Worker 	struct CrossDomainInit cmd_init;
247*d95af8dfSAndroid Build Coastguard Worker 	struct CrossDomainCapabilities cross_domain_caps;
248*d95af8dfSAndroid Build Coastguard Worker 
249*d95af8dfSAndroid Build Coastguard Worker 	memset(&cmd_init, 0, sizeof(cmd_init));
250*d95af8dfSAndroid Build Coastguard Worker 	if (!params[param_context_init].value)
251*d95af8dfSAndroid Build Coastguard Worker 		return -ENOTSUP;
252*d95af8dfSAndroid Build Coastguard Worker 
253*d95af8dfSAndroid Build Coastguard Worker 	if ((params[param_supported_capset_ids].value & (1 << VIRTIO_GPU_CAPSET_CROSS_DOMAIN)) == 0)
254*d95af8dfSAndroid Build Coastguard Worker 		return -ENOTSUP;
255*d95af8dfSAndroid Build Coastguard Worker 
256*d95af8dfSAndroid Build Coastguard Worker 	if (!params[param_resource_blob].value)
257*d95af8dfSAndroid Build Coastguard Worker 		return -ENOTSUP;
258*d95af8dfSAndroid Build Coastguard Worker 
259*d95af8dfSAndroid Build Coastguard Worker 	/// Need zero copy memory
260*d95af8dfSAndroid Build Coastguard Worker 	if (!params[param_host_visible].value && !params[param_create_guest_handle].value)
261*d95af8dfSAndroid Build Coastguard Worker 		return -ENOTSUP;
262*d95af8dfSAndroid Build Coastguard Worker 
263*d95af8dfSAndroid Build Coastguard Worker 	priv = calloc(1, sizeof(*priv));
264*d95af8dfSAndroid Build Coastguard Worker 	if (!priv)
265*d95af8dfSAndroid Build Coastguard Worker 		return -ENOMEM;
266*d95af8dfSAndroid Build Coastguard Worker 
267*d95af8dfSAndroid Build Coastguard Worker 	ret = pthread_mutex_init(&priv->metadata_cache_lock, NULL);
268*d95af8dfSAndroid Build Coastguard Worker 	if (ret) {
269*d95af8dfSAndroid Build Coastguard Worker 		free(priv);
270*d95af8dfSAndroid Build Coastguard Worker 		return ret;
271*d95af8dfSAndroid Build Coastguard Worker 	}
272*d95af8dfSAndroid Build Coastguard Worker 
273*d95af8dfSAndroid Build Coastguard Worker 	priv->metadata_cache = drv_array_init(sizeof(struct bo_metadata));
274*d95af8dfSAndroid Build Coastguard Worker 	if (!priv->metadata_cache) {
275*d95af8dfSAndroid Build Coastguard Worker 		ret = -ENOMEM;
276*d95af8dfSAndroid Build Coastguard Worker 		goto free_private;
277*d95af8dfSAndroid Build Coastguard Worker 	}
278*d95af8dfSAndroid Build Coastguard Worker 
279*d95af8dfSAndroid Build Coastguard Worker 	priv->ring_addr = MAP_FAILED;
280*d95af8dfSAndroid Build Coastguard Worker 	drv->priv = priv;
281*d95af8dfSAndroid Build Coastguard Worker 
282*d95af8dfSAndroid Build Coastguard Worker 	args.cap_set_id = VIRTIO_GPU_CAPSET_CROSS_DOMAIN;
283*d95af8dfSAndroid Build Coastguard Worker 	args.size = sizeof(struct CrossDomainCapabilities);
284*d95af8dfSAndroid Build Coastguard Worker 	args.addr = (unsigned long long)&cross_domain_caps;
285*d95af8dfSAndroid Build Coastguard Worker 
286*d95af8dfSAndroid Build Coastguard Worker 	ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_GET_CAPS, &args);
287*d95af8dfSAndroid Build Coastguard Worker 	if (ret) {
288*d95af8dfSAndroid Build Coastguard Worker 		drv_loge("DRM_IOCTL_VIRTGPU_GET_CAPS failed with %s\n", strerror(errno));
289*d95af8dfSAndroid Build Coastguard Worker 		goto free_private;
290*d95af8dfSAndroid Build Coastguard Worker 	}
291*d95af8dfSAndroid Build Coastguard Worker 
292*d95af8dfSAndroid Build Coastguard Worker 	// When 3D features are avilable, but the host does not support external memory, fall back
293*d95af8dfSAndroid Build Coastguard Worker 	// to the virgl minigbm backend.  This typically means the guest side minigbm resource will
294*d95af8dfSAndroid Build Coastguard Worker 	// be backed by a host OpenGL texture.
295*d95af8dfSAndroid Build Coastguard Worker 	if (!cross_domain_caps.supports_external_gpu_memory && params[param_3d].value) {
296*d95af8dfSAndroid Build Coastguard Worker 		ret = -ENOTSUP;
297*d95af8dfSAndroid Build Coastguard Worker 		goto free_private;
298*d95af8dfSAndroid Build Coastguard Worker 	}
299*d95af8dfSAndroid Build Coastguard Worker 
300*d95af8dfSAndroid Build Coastguard Worker 	// Intialize the cross domain context.  Create one fence context to wait for metadata
301*d95af8dfSAndroid Build Coastguard Worker 	// queries.
302*d95af8dfSAndroid Build Coastguard Worker 	ctx_set_params[0].param = VIRTGPU_CONTEXT_PARAM_CAPSET_ID;
303*d95af8dfSAndroid Build Coastguard Worker 	ctx_set_params[0].value = VIRTIO_GPU_CAPSET_CROSS_DOMAIN;
304*d95af8dfSAndroid Build Coastguard Worker 	ctx_set_params[1].param = VIRTGPU_CONTEXT_PARAM_NUM_RINGS;
305*d95af8dfSAndroid Build Coastguard Worker 	ctx_set_params[1].value = 1;
306*d95af8dfSAndroid Build Coastguard Worker 
307*d95af8dfSAndroid Build Coastguard Worker 	init.ctx_set_params = (unsigned long long)&ctx_set_params[0];
308*d95af8dfSAndroid Build Coastguard Worker 	init.num_params = 2;
309*d95af8dfSAndroid Build Coastguard Worker 	ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_CONTEXT_INIT, &init);
310*d95af8dfSAndroid Build Coastguard Worker 	if (ret) {
311*d95af8dfSAndroid Build Coastguard Worker 		drv_loge("DRM_IOCTL_VIRTGPU_CONTEXT_INIT failed with %s\n", strerror(errno));
312*d95af8dfSAndroid Build Coastguard Worker 		goto free_private;
313*d95af8dfSAndroid Build Coastguard Worker 	}
314*d95af8dfSAndroid Build Coastguard Worker 
315*d95af8dfSAndroid Build Coastguard Worker 	// Create a shared ring buffer to read metadata queries.
316*d95af8dfSAndroid Build Coastguard Worker 	drm_rc_blob.size = PAGE_SIZE;
317*d95af8dfSAndroid Build Coastguard Worker 	drm_rc_blob.blob_mem = VIRTGPU_BLOB_MEM_GUEST;
318*d95af8dfSAndroid Build Coastguard Worker 	drm_rc_blob.blob_flags = VIRTGPU_BLOB_FLAG_USE_MAPPABLE;
319*d95af8dfSAndroid Build Coastguard Worker 
320*d95af8dfSAndroid Build Coastguard Worker 	ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB, &drm_rc_blob);
321*d95af8dfSAndroid Build Coastguard Worker 	if (ret < 0) {
322*d95af8dfSAndroid Build Coastguard Worker 		drv_loge("DRM_VIRTGPU_RESOURCE_CREATE_BLOB failed with %s\n", strerror(errno));
323*d95af8dfSAndroid Build Coastguard Worker 		goto free_private;
324*d95af8dfSAndroid Build Coastguard Worker 	}
325*d95af8dfSAndroid Build Coastguard Worker 
326*d95af8dfSAndroid Build Coastguard Worker 	priv->ring_handle = drm_rc_blob.bo_handle;
327*d95af8dfSAndroid Build Coastguard Worker 
328*d95af8dfSAndroid Build Coastguard Worker 	// Map shared ring buffer.
329*d95af8dfSAndroid Build Coastguard Worker 	map.handle = priv->ring_handle;
330*d95af8dfSAndroid Build Coastguard Worker 	ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_MAP, &map);
331*d95af8dfSAndroid Build Coastguard Worker 	if (ret < 0) {
332*d95af8dfSAndroid Build Coastguard Worker 		drv_loge("DRM_IOCTL_VIRTGPU_MAP failed with %s\n", strerror(errno));
333*d95af8dfSAndroid Build Coastguard Worker 		goto free_private;
334*d95af8dfSAndroid Build Coastguard Worker 	}
335*d95af8dfSAndroid Build Coastguard Worker 
336*d95af8dfSAndroid Build Coastguard Worker 	priv->ring_addr =
337*d95af8dfSAndroid Build Coastguard Worker 	    mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, drv->fd, map.offset);
338*d95af8dfSAndroid Build Coastguard Worker 
339*d95af8dfSAndroid Build Coastguard Worker 	if (priv->ring_addr == MAP_FAILED) {
340*d95af8dfSAndroid Build Coastguard Worker 		drv_loge("mmap failed with %s\n", strerror(errno));
341*d95af8dfSAndroid Build Coastguard Worker 		goto free_private;
342*d95af8dfSAndroid Build Coastguard Worker 	}
343*d95af8dfSAndroid Build Coastguard Worker 
344*d95af8dfSAndroid Build Coastguard Worker 	// Notify host about ring buffer
345*d95af8dfSAndroid Build Coastguard Worker 	cmd_init.hdr.cmd = CROSS_DOMAIN_CMD_INIT;
346*d95af8dfSAndroid Build Coastguard Worker 	cmd_init.hdr.cmd_size = sizeof(struct CrossDomainInit);
347*d95af8dfSAndroid Build Coastguard Worker 	cmd_init.ring_id = drm_rc_blob.res_handle;
348*d95af8dfSAndroid Build Coastguard Worker 	ret = cross_domain_submit_cmd(drv, (uint32_t *)&cmd_init, cmd_init.hdr.cmd_size, false);
349*d95af8dfSAndroid Build Coastguard Worker 	if (ret < 0)
350*d95af8dfSAndroid Build Coastguard Worker 		goto free_private;
351*d95af8dfSAndroid Build Coastguard Worker 
352*d95af8dfSAndroid Build Coastguard Worker 	const char *name;
353*d95af8dfSAndroid Build Coastguard Worker 	name = drv_get_os_option("ro.product.name");
354*d95af8dfSAndroid Build Coastguard Worker 	priv->mt8183_camera_quirk_ = name && !strcmp(name, "kukui");
355*d95af8dfSAndroid Build Coastguard Worker 
356*d95af8dfSAndroid Build Coastguard Worker 	// minigbm bookkeeping
357*d95af8dfSAndroid Build Coastguard Worker 	add_combinations(drv);
358*d95af8dfSAndroid Build Coastguard Worker 	return 0;
359*d95af8dfSAndroid Build Coastguard Worker 
360*d95af8dfSAndroid Build Coastguard Worker free_private:
361*d95af8dfSAndroid Build Coastguard Worker 	cross_domain_release_private(drv);
362*d95af8dfSAndroid Build Coastguard Worker 	return ret;
363*d95af8dfSAndroid Build Coastguard Worker }
364*d95af8dfSAndroid Build Coastguard Worker 
cross_domain_close(struct driver * drv)365*d95af8dfSAndroid Build Coastguard Worker static void cross_domain_close(struct driver *drv)
366*d95af8dfSAndroid Build Coastguard Worker {
367*d95af8dfSAndroid Build Coastguard Worker 	cross_domain_release_private(drv);
368*d95af8dfSAndroid Build Coastguard Worker }
369*d95af8dfSAndroid Build Coastguard Worker 
cross_domain_bo_create(struct bo * bo,uint32_t width,uint32_t height,uint32_t format,uint64_t use_flags)370*d95af8dfSAndroid Build Coastguard Worker static int cross_domain_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
371*d95af8dfSAndroid Build Coastguard Worker 				  uint64_t use_flags)
372*d95af8dfSAndroid Build Coastguard Worker {
373*d95af8dfSAndroid Build Coastguard Worker 	int ret;
374*d95af8dfSAndroid Build Coastguard Worker 	uint32_t blob_flags = VIRTGPU_BLOB_FLAG_USE_SHAREABLE;
375*d95af8dfSAndroid Build Coastguard Worker 	struct drm_virtgpu_resource_create_blob drm_rc_blob = { 0 };
376*d95af8dfSAndroid Build Coastguard Worker 
377*d95af8dfSAndroid Build Coastguard Worker 	if (use_flags & (BO_USE_SW_MASK | BO_USE_GPU_DATA_BUFFER))
378*d95af8dfSAndroid Build Coastguard Worker 		blob_flags |= VIRTGPU_BLOB_FLAG_USE_MAPPABLE;
379*d95af8dfSAndroid Build Coastguard Worker 
380*d95af8dfSAndroid Build Coastguard Worker 	if (!(use_flags & BO_USE_HW_MASK)) {
381*d95af8dfSAndroid Build Coastguard Worker 		cross_domain_get_emulated_metadata(&bo->meta);
382*d95af8dfSAndroid Build Coastguard Worker 		drm_rc_blob.blob_mem = VIRTGPU_BLOB_MEM_GUEST;
383*d95af8dfSAndroid Build Coastguard Worker 	} else {
384*d95af8dfSAndroid Build Coastguard Worker 		ret = cross_domain_metadata_query(bo->drv, &bo->meta);
385*d95af8dfSAndroid Build Coastguard Worker 		if (ret < 0) {
386*d95af8dfSAndroid Build Coastguard Worker 			drv_loge("Metadata query failed");
387*d95af8dfSAndroid Build Coastguard Worker 			return ret;
388*d95af8dfSAndroid Build Coastguard Worker 		}
389*d95af8dfSAndroid Build Coastguard Worker 
390*d95af8dfSAndroid Build Coastguard Worker 		if (params[param_cross_device].value)
391*d95af8dfSAndroid Build Coastguard Worker 			blob_flags |= VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE;
392*d95af8dfSAndroid Build Coastguard Worker 
393*d95af8dfSAndroid Build Coastguard Worker 		/// It may be possible to have host3d blobs and handles from guest memory at the
394*d95af8dfSAndroid Build Coastguard Worker 		/// same time. But for the immediate use cases, we will either have one or the
395*d95af8dfSAndroid Build Coastguard Worker 		/// other.  For now, just prefer guest memory since adding that feature is more
396*d95af8dfSAndroid Build Coastguard Worker 		/// involved (requires --udmabuf flag to crosvm), so developers would likely test
397*d95af8dfSAndroid Build Coastguard Worker 		/// that.
398*d95af8dfSAndroid Build Coastguard Worker 		if (params[param_create_guest_handle].value) {
399*d95af8dfSAndroid Build Coastguard Worker 			drm_rc_blob.blob_mem = VIRTGPU_BLOB_MEM_GUEST;
400*d95af8dfSAndroid Build Coastguard Worker 			blob_flags |= VIRTGPU_BLOB_FLAG_CREATE_GUEST_HANDLE;
401*d95af8dfSAndroid Build Coastguard Worker 		} else if (params[param_host_visible].value) {
402*d95af8dfSAndroid Build Coastguard Worker 			drm_rc_blob.blob_mem = VIRTGPU_BLOB_MEM_HOST3D;
403*d95af8dfSAndroid Build Coastguard Worker 		}
404*d95af8dfSAndroid Build Coastguard Worker 		drm_rc_blob.blob_id = (uint64_t)bo->meta.blob_id;
405*d95af8dfSAndroid Build Coastguard Worker 	}
406*d95af8dfSAndroid Build Coastguard Worker 
407*d95af8dfSAndroid Build Coastguard Worker 	drm_rc_blob.size = bo->meta.total_size;
408*d95af8dfSAndroid Build Coastguard Worker 	drm_rc_blob.blob_flags = blob_flags;
409*d95af8dfSAndroid Build Coastguard Worker 
410*d95af8dfSAndroid Build Coastguard Worker 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB, &drm_rc_blob);
411*d95af8dfSAndroid Build Coastguard Worker 	if (ret < 0) {
412*d95af8dfSAndroid Build Coastguard Worker 		drv_loge("DRM_VIRTGPU_RESOURCE_CREATE_BLOB failed with %s\n", strerror(errno));
413*d95af8dfSAndroid Build Coastguard Worker 		return -errno;
414*d95af8dfSAndroid Build Coastguard Worker 	}
415*d95af8dfSAndroid Build Coastguard Worker 
416*d95af8dfSAndroid Build Coastguard Worker 	bo->handle.u32 = drm_rc_blob.bo_handle;
417*d95af8dfSAndroid Build Coastguard Worker 
418*d95af8dfSAndroid Build Coastguard Worker 	return 0;
419*d95af8dfSAndroid Build Coastguard Worker }
420*d95af8dfSAndroid Build Coastguard Worker 
cross_domain_bo_map(struct bo * bo,struct vma * vma,uint32_t map_flags)421*d95af8dfSAndroid Build Coastguard Worker static void *cross_domain_bo_map(struct bo *bo, struct vma *vma, uint32_t map_flags)
422*d95af8dfSAndroid Build Coastguard Worker {
423*d95af8dfSAndroid Build Coastguard Worker 	int ret;
424*d95af8dfSAndroid Build Coastguard Worker 	struct drm_virtgpu_map gem_map = { 0 };
425*d95af8dfSAndroid Build Coastguard Worker 
426*d95af8dfSAndroid Build Coastguard Worker 	gem_map.handle = bo->handle.u32;
427*d95af8dfSAndroid Build Coastguard Worker 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_MAP, &gem_map);
428*d95af8dfSAndroid Build Coastguard Worker 	if (ret) {
429*d95af8dfSAndroid Build Coastguard Worker 		drv_loge("DRM_IOCTL_VIRTGPU_MAP failed with %s\n", strerror(errno));
430*d95af8dfSAndroid Build Coastguard Worker 		return MAP_FAILED;
431*d95af8dfSAndroid Build Coastguard Worker 	}
432*d95af8dfSAndroid Build Coastguard Worker 
433*d95af8dfSAndroid Build Coastguard Worker 	vma->length = bo->meta.total_size;
434*d95af8dfSAndroid Build Coastguard Worker 	return mmap(0, bo->meta.total_size, drv_get_prot(map_flags), MAP_SHARED, bo->drv->fd,
435*d95af8dfSAndroid Build Coastguard Worker 		    gem_map.offset);
436*d95af8dfSAndroid Build Coastguard Worker }
437*d95af8dfSAndroid Build Coastguard Worker 
cross_domain_resolve_format_and_use_flags(struct driver * drv,uint32_t format,uint64_t use_flags,uint32_t * out_format,uint64_t * out_use_flags)438*d95af8dfSAndroid Build Coastguard Worker static void cross_domain_resolve_format_and_use_flags(struct driver *drv, uint32_t format,
439*d95af8dfSAndroid Build Coastguard Worker 						      uint64_t use_flags, uint32_t *out_format,
440*d95af8dfSAndroid Build Coastguard Worker 						      uint64_t *out_use_flags)
441*d95af8dfSAndroid Build Coastguard Worker {
442*d95af8dfSAndroid Build Coastguard Worker 	struct cross_domain_private *priv = drv->priv;
443*d95af8dfSAndroid Build Coastguard Worker 	*out_format = format;
444*d95af8dfSAndroid Build Coastguard Worker 	*out_use_flags = use_flags;
445*d95af8dfSAndroid Build Coastguard Worker 
446*d95af8dfSAndroid Build Coastguard Worker 	switch (format) {
447*d95af8dfSAndroid Build Coastguard Worker 	case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED:
448*d95af8dfSAndroid Build Coastguard Worker 		if (priv->mt8183_camera_quirk_ && (use_flags & BO_USE_CAMERA_READ) &&
449*d95af8dfSAndroid Build Coastguard Worker 		    !(use_flags & BO_USE_SCANOUT)) {
450*d95af8dfSAndroid Build Coastguard Worker 			*out_format = DRM_FORMAT_MTISP_SXYZW10;
451*d95af8dfSAndroid Build Coastguard Worker 			break;
452*d95af8dfSAndroid Build Coastguard Worker 		}
453*d95af8dfSAndroid Build Coastguard Worker 		/* Common camera implementation defined format. */
454*d95af8dfSAndroid Build Coastguard Worker 		if (use_flags & (BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE)) {
455*d95af8dfSAndroid Build Coastguard Worker 			*out_format = DRM_FORMAT_NV12;
456*d95af8dfSAndroid Build Coastguard Worker 		} else {
457*d95af8dfSAndroid Build Coastguard Worker 			/* HACK: See b/28671744 */
458*d95af8dfSAndroid Build Coastguard Worker 			*out_format = DRM_FORMAT_XBGR8888;
459*d95af8dfSAndroid Build Coastguard Worker 			*out_use_flags &= ~BO_USE_HW_VIDEO_ENCODER;
460*d95af8dfSAndroid Build Coastguard Worker 		}
461*d95af8dfSAndroid Build Coastguard Worker 		break;
462*d95af8dfSAndroid Build Coastguard Worker 	case DRM_FORMAT_FLEX_YCbCr_420_888:
463*d95af8dfSAndroid Build Coastguard Worker 		/* Common flexible video format. */
464*d95af8dfSAndroid Build Coastguard Worker 		*out_format = DRM_FORMAT_NV12;
465*d95af8dfSAndroid Build Coastguard Worker 		break;
466*d95af8dfSAndroid Build Coastguard Worker 	case DRM_FORMAT_YVU420_ANDROID:
467*d95af8dfSAndroid Build Coastguard Worker 		*out_use_flags &= ~BO_USE_SCANOUT;
468*d95af8dfSAndroid Build Coastguard Worker 		break;
469*d95af8dfSAndroid Build Coastguard Worker 	default:
470*d95af8dfSAndroid Build Coastguard Worker 		break;
471*d95af8dfSAndroid Build Coastguard Worker 	}
472*d95af8dfSAndroid Build Coastguard Worker }
473*d95af8dfSAndroid Build Coastguard Worker 
474*d95af8dfSAndroid Build Coastguard Worker const struct backend virtgpu_cross_domain = {
475*d95af8dfSAndroid Build Coastguard Worker 	.name = "virtgpu_cross_domain",
476*d95af8dfSAndroid Build Coastguard Worker 	.init = cross_domain_init,
477*d95af8dfSAndroid Build Coastguard Worker 	.close = cross_domain_close,
478*d95af8dfSAndroid Build Coastguard Worker 	.bo_create = cross_domain_bo_create,
479*d95af8dfSAndroid Build Coastguard Worker 	.bo_import = drv_prime_bo_import,
480*d95af8dfSAndroid Build Coastguard Worker 	.bo_destroy = drv_gem_bo_destroy,
481*d95af8dfSAndroid Build Coastguard Worker 	.bo_map = cross_domain_bo_map,
482*d95af8dfSAndroid Build Coastguard Worker 	.bo_unmap = drv_bo_munmap,
483*d95af8dfSAndroid Build Coastguard Worker 	.resolve_format_and_use_flags = cross_domain_resolve_format_and_use_flags,
484*d95af8dfSAndroid Build Coastguard Worker };
485