1 /*
2  * Copyright 2017 The Chromium OS Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6 
7 #include "cros_gralloc_driver.h"
8 #include "../util.h"
9 
10 #include <cstdlib>
11 #include <fcntl.h>
12 #include <xf86drm.h>
13 
cros_gralloc_driver()14 cros_gralloc_driver::cros_gralloc_driver() : drv_(nullptr)
15 {
16 }
17 
~cros_gralloc_driver()18 cros_gralloc_driver::~cros_gralloc_driver()
19 {
20 	buffers_.clear();
21 	handles_.clear();
22 
23 	if (drv_) {
24 		int fd = drv_get_fd(drv_);
25 		drv_destroy(drv_);
26 		drv_ = nullptr;
27 		close(fd);
28 	}
29 }
30 
init()31 int32_t cros_gralloc_driver::init()
32 {
33 	/*
34 	 * Create a driver from rendernode while filtering out
35 	 * the specified undesired driver.
36 	 *
37 	 * TODO(gsingh): Enable render nodes on udl/evdi.
38 	 */
39 
40 	int fd;
41 	drmVersionPtr version;
42 	char const *str = "%s/renderD%d";
43 	const char *undesired[2] = { "vgem", nullptr };
44 	uint32_t num_nodes = 63;
45 	uint32_t min_node = 128;
46 	uint32_t max_node = (min_node + num_nodes);
47 
48 	for (uint32_t i = 0; i < ARRAY_SIZE(undesired); i++) {
49 		for (uint32_t j = min_node; j < max_node; j++) {
50 			char *node;
51 			if (asprintf(&node, str, DRM_DIR_NAME, j) < 0)
52 				continue;
53 
54 			fd = open(node, O_RDWR, 0);
55 			free(node);
56 
57 			if (fd < 0)
58 				continue;
59 
60 			version = drmGetVersion(fd);
61 			if (!version) {
62 				close(fd);
63 				continue;
64 			}
65 
66 			if (undesired[i] && !strcmp(version->name, undesired[i])) {
67 				close(fd);
68 				drmFreeVersion(version);
69 				continue;
70 			}
71 
72 			drmFreeVersion(version);
73 			drv_ = drv_create(fd);
74 			if (drv_)
75 				return 0;
76 
77 			close(fd);
78 		}
79 	}
80 
81 	return -ENODEV;
82 }
83 
is_supported(const struct cros_gralloc_buffer_descriptor * descriptor)84 bool cros_gralloc_driver::is_supported(const struct cros_gralloc_buffer_descriptor *descriptor)
85 {
86 	struct combination *combo;
87 	uint32_t resolved_format;
88 	resolved_format = drv_resolve_format(drv_, descriptor->drm_format, descriptor->use_flags);
89 	combo = drv_get_combination(drv_, resolved_format, descriptor->use_flags);
90 	return (combo != nullptr);
91 }
92 
allocate(const struct cros_gralloc_buffer_descriptor * descriptor,buffer_handle_t * out_handle)93 int32_t cros_gralloc_driver::allocate(const struct cros_gralloc_buffer_descriptor *descriptor,
94 				      buffer_handle_t *out_handle)
95 {
96 	uint32_t id;
97 	uint64_t mod;
98 	size_t num_planes;
99 	uint32_t resolved_format;
100 	uint32_t bytes_per_pixel;
101 	uint64_t use_flags;
102 
103 	struct bo *bo;
104 	struct cros_gralloc_handle *hnd;
105 
106 	resolved_format = drv_resolve_format(drv_, descriptor->drm_format, descriptor->use_flags);
107 	use_flags = descriptor->use_flags;
108 	/*
109 	 * TODO(b/79682290): ARC++ assumes NV12 is always linear and doesn't
110 	 * send modifiers across Wayland protocol, so we or in the
111 	 * BO_USE_LINEAR flag here. We need to fix ARC++ to allocate and work
112 	 * with tiled buffers.
113 	 */
114 	if (resolved_format == DRM_FORMAT_NV12)
115 		use_flags |= BO_USE_LINEAR;
116 
117 	/*
118 	 * This unmask is a backup in the case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED is resolved
119 	 * to non-YUV formats.
120 	 */
121 	if (descriptor->drm_format == DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED &&
122 	    (resolved_format == DRM_FORMAT_XBGR8888 || resolved_format == DRM_FORMAT_ABGR8888)) {
123 		use_flags &= ~BO_USE_HW_VIDEO_ENCODER;
124 	}
125 
126 	bo = drv_bo_create(drv_, descriptor->width, descriptor->height, resolved_format, use_flags);
127 	if (!bo) {
128 		drv_log("Failed to create bo.\n");
129 		return -ENOMEM;
130 	}
131 
132 	/*
133 	 * If there is a desire for more than one kernel buffer, this can be
134 	 * removed once the ArcCodec and Wayland service have the ability to
135 	 * send more than one fd. GL/Vulkan drivers may also have to modified.
136 	 */
137 	if (drv_num_buffers_per_bo(bo) != 1) {
138 		drv_bo_destroy(bo);
139 		drv_log("Can only support one buffer per bo.\n");
140 		return -EINVAL;
141 	}
142 
143 	hnd = new cros_gralloc_handle();
144 	num_planes = drv_bo_get_num_planes(bo);
145 
146 	hnd->base.version = sizeof(hnd->base);
147 	hnd->base.numFds = num_planes;
148 	hnd->base.numInts = handle_data_size - num_planes;
149 
150 	for (size_t plane = 0; plane < num_planes; plane++) {
151 		hnd->fds[plane] = drv_bo_get_plane_fd(bo, plane);
152 		hnd->strides[plane] = drv_bo_get_plane_stride(bo, plane);
153 		hnd->offsets[plane] = drv_bo_get_plane_offset(bo, plane);
154 
155 		mod = drv_bo_get_plane_format_modifier(bo, plane);
156 		hnd->format_modifiers[2 * plane] = static_cast<uint32_t>(mod >> 32);
157 		hnd->format_modifiers[2 * plane + 1] = static_cast<uint32_t>(mod);
158 	}
159 
160 	hnd->width = drv_bo_get_width(bo);
161 	hnd->height = drv_bo_get_height(bo);
162 	hnd->format = drv_bo_get_format(bo);
163 	hnd->use_flags[0] = static_cast<uint32_t>(descriptor->use_flags >> 32);
164 	hnd->use_flags[1] = static_cast<uint32_t>(descriptor->use_flags);
165 	bytes_per_pixel = drv_bytes_per_pixel_from_format(hnd->format, 0);
166 	hnd->pixel_stride = DIV_ROUND_UP(hnd->strides[0], bytes_per_pixel);
167 	hnd->magic = cros_gralloc_magic;
168 	hnd->droid_format = descriptor->droid_format;
169 	hnd->usage = descriptor->producer_usage;
170 
171 	id = drv_bo_get_plane_handle(bo, 0).u32;
172 	auto buffer = new cros_gralloc_buffer(id, bo, hnd);
173 
174 	std::lock_guard<std::mutex> lock(mutex_);
175 	buffers_.emplace(id, buffer);
176 	handles_.emplace(hnd, std::make_pair(buffer, 1));
177 	*out_handle = &hnd->base;
178 	return 0;
179 }
180 
retain(buffer_handle_t handle)181 int32_t cros_gralloc_driver::retain(buffer_handle_t handle)
182 {
183 	uint32_t id;
184 	std::lock_guard<std::mutex> lock(mutex_);
185 
186 	auto hnd = cros_gralloc_convert_handle(handle);
187 	if (!hnd) {
188 		drv_log("Invalid handle.\n");
189 		return -EINVAL;
190 	}
191 
192 	auto buffer = get_buffer(hnd);
193 	if (buffer) {
194 		handles_[hnd].second++;
195 		buffer->increase_refcount();
196 		return 0;
197 	}
198 
199 	if (drmPrimeFDToHandle(drv_get_fd(drv_), hnd->fds[0], &id)) {
200 		drv_log("drmPrimeFDToHandle failed.\n");
201 		return -errno;
202 	}
203 
204 	if (buffers_.count(id)) {
205 		buffer = buffers_[id];
206 		buffer->increase_refcount();
207 	} else {
208 		struct bo *bo;
209 		struct drv_import_fd_data data;
210 		data.format = hnd->format;
211 		data.width = hnd->width;
212 		data.height = hnd->height;
213 		data.use_flags = static_cast<uint64_t>(hnd->use_flags[0]) << 32;
214 		data.use_flags |= hnd->use_flags[1];
215 
216 		memcpy(data.fds, hnd->fds, sizeof(data.fds));
217 		memcpy(data.strides, hnd->strides, sizeof(data.strides));
218 		memcpy(data.offsets, hnd->offsets, sizeof(data.offsets));
219 		for (uint32_t plane = 0; plane < DRV_MAX_PLANES; plane++) {
220 			data.format_modifiers[plane] =
221 			    static_cast<uint64_t>(hnd->format_modifiers[2 * plane]) << 32;
222 			data.format_modifiers[plane] |= hnd->format_modifiers[2 * plane + 1];
223 		}
224 
225 		bo = drv_bo_import(drv_, &data);
226 		if (!bo)
227 			return -EFAULT;
228 
229 		id = drv_bo_get_plane_handle(bo, 0).u32;
230 
231 		buffer = new cros_gralloc_buffer(id, bo, nullptr);
232 		buffers_.emplace(id, buffer);
233 	}
234 
235 	handles_.emplace(hnd, std::make_pair(buffer, 1));
236 	return 0;
237 }
238 
release(buffer_handle_t handle)239 int32_t cros_gralloc_driver::release(buffer_handle_t handle)
240 {
241 	std::lock_guard<std::mutex> lock(mutex_);
242 
243 	auto hnd = cros_gralloc_convert_handle(handle);
244 	if (!hnd) {
245 		drv_log("Invalid handle.\n");
246 		return -EINVAL;
247 	}
248 
249 	auto buffer = get_buffer(hnd);
250 	if (!buffer) {
251 		drv_log("Invalid Reference.\n");
252 		return -EINVAL;
253 	}
254 
255 	if (!--handles_[hnd].second)
256 		handles_.erase(hnd);
257 
258 	if (buffer->decrease_refcount() == 0) {
259 		buffers_.erase(buffer->get_id());
260 		delete buffer;
261 	}
262 
263 	return 0;
264 }
265 
lock(buffer_handle_t handle,int32_t acquire_fence,const struct rectangle * rect,uint32_t map_flags,uint8_t * addr[DRV_MAX_PLANES])266 int32_t cros_gralloc_driver::lock(buffer_handle_t handle, int32_t acquire_fence,
267 				  const struct rectangle *rect, uint32_t map_flags,
268 				  uint8_t *addr[DRV_MAX_PLANES])
269 {
270 	int32_t ret = cros_gralloc_sync_wait(acquire_fence);
271 	if (ret)
272 		return ret;
273 
274 	std::lock_guard<std::mutex> lock(mutex_);
275 	auto hnd = cros_gralloc_convert_handle(handle);
276 	if (!hnd) {
277 		drv_log("Invalid handle.\n");
278 		return -EINVAL;
279 	}
280 
281 	auto buffer = get_buffer(hnd);
282 	if (!buffer) {
283 		drv_log("Invalid Reference.\n");
284 		return -EINVAL;
285 	}
286 
287 	return buffer->lock(rect, map_flags, addr);
288 }
289 
unlock(buffer_handle_t handle,int32_t * release_fence)290 int32_t cros_gralloc_driver::unlock(buffer_handle_t handle, int32_t *release_fence)
291 {
292 	std::lock_guard<std::mutex> lock(mutex_);
293 
294 	auto hnd = cros_gralloc_convert_handle(handle);
295 	if (!hnd) {
296 		drv_log("Invalid handle.\n");
297 		return -EINVAL;
298 	}
299 
300 	auto buffer = get_buffer(hnd);
301 	if (!buffer) {
302 		drv_log("Invalid Reference.\n");
303 		return -EINVAL;
304 	}
305 
306 	/*
307 	 * From the ANativeWindow::dequeueBuffer documentation:
308 	 *
309 	 * "A value of -1 indicates that the caller may access the buffer immediately without
310 	 * waiting on a fence."
311 	 */
312 	*release_fence = -1;
313 	return buffer->unlock();
314 }
315 
get_backing_store(buffer_handle_t handle,uint64_t * out_store)316 int32_t cros_gralloc_driver::get_backing_store(buffer_handle_t handle, uint64_t *out_store)
317 {
318 	std::lock_guard<std::mutex> lock(mutex_);
319 
320 	auto hnd = cros_gralloc_convert_handle(handle);
321 	if (!hnd) {
322 		drv_log("Invalid handle.\n");
323 		return -EINVAL;
324 	}
325 
326 	auto buffer = get_buffer(hnd);
327 	if (!buffer) {
328 		drv_log("Invalid Reference.\n");
329 		return -EINVAL;
330 	}
331 
332 	*out_store = static_cast<uint64_t>(buffer->get_id());
333 	return 0;
334 }
335 
resource_info(buffer_handle_t handle,uint32_t strides[DRV_MAX_PLANES],uint32_t offsets[DRV_MAX_PLANES])336 int32_t cros_gralloc_driver::resource_info(buffer_handle_t handle, uint32_t strides[DRV_MAX_PLANES],
337 					   uint32_t offsets[DRV_MAX_PLANES])
338 {
339 	std::lock_guard<std::mutex> lock(mutex_);
340 
341 	auto hnd = cros_gralloc_convert_handle(handle);
342 	if (!hnd) {
343 		drv_log("Invalid handle.\n");
344 		return -EINVAL;
345 	}
346 
347 	auto buffer = get_buffer(hnd);
348 	if (!buffer) {
349 		drv_log("Invalid Reference.\n");
350 		return -EINVAL;
351 	}
352 
353 	return buffer->resource_info(strides, offsets);
354 }
355 
get_buffer(cros_gralloc_handle_t hnd)356 cros_gralloc_buffer *cros_gralloc_driver::get_buffer(cros_gralloc_handle_t hnd)
357 {
358 	/* Assumes driver mutex is held. */
359 	if (handles_.count(hnd))
360 		return handles_[hnd].first;
361 
362 	return nullptr;
363 }
364