• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
9 #include <cstdlib>
10 #include <fcntl.h>
11 #include <sys/mman.h>
12 #include <syscall.h>
13 #include <xf86drm.h>
14 
15 #include "../drv_priv.h"
16 #include "../helpers.h"
17 #include "../util.h"
18 
19 // Constants taken from pipe_loader_drm.c in Mesa
20 
21 #define DRM_NUM_NODES 63
22 
23 // DRM Render nodes start at 128
24 #define DRM_RENDER_NODE_START 128
25 
26 // DRM Card nodes start at 0
27 #define DRM_CARD_NODE_START 0
28 
memfd_create_wrapper(const char * name,unsigned int flags)29 int memfd_create_wrapper(const char *name, unsigned int flags)
30 {
31 	int fd;
32 
33 #if defined(HAVE_MEMFD_CREATE)
34 	fd = memfd_create(name, flags);
35 #elif defined(__NR_memfd_create)
36 	fd = syscall(__NR_memfd_create, name, flags);
37 #else
38 	drv_log("Failed to create memfd '%s': memfd_create not available.", name);
39 	return -1;
40 #endif
41 
42 	if (fd == -1)
43 		drv_log("Failed to create memfd '%s': %s.\n", name, strerror(errno));
44 
45 	return fd;
46 }
47 
cros_gralloc_driver()48 cros_gralloc_driver::cros_gralloc_driver() : drv_(nullptr)
49 {
50 }
51 
~cros_gralloc_driver()52 cros_gralloc_driver::~cros_gralloc_driver()
53 {
54 	buffers_.clear();
55 	handles_.clear();
56 
57 	if (drv_) {
58 		int fd = drv_get_fd(drv_);
59 		drv_destroy(drv_);
60 		drv_ = nullptr;
61 		close(fd);
62 	}
63 }
64 
init_try_node(int idx,char const * str)65 static struct driver *init_try_node(int idx, char const *str)
66 {
67 	int fd;
68 	char *node;
69 	struct driver *drv;
70 
71 	if (asprintf(&node, str, DRM_DIR_NAME, idx) < 0)
72 		return NULL;
73 
74 	fd = open(node, O_RDWR, 0);
75 	free(node);
76 
77 	if (fd < 0)
78 		return NULL;
79 
80 	drv = drv_create(fd);
81 	if (!drv)
82 		close(fd);
83 
84 	return drv;
85 }
86 
init()87 int32_t cros_gralloc_driver::init()
88 {
89 	/*
90 	 * Create a driver from render nodes first, then try card
91 	 * nodes.
92 	 *
93 	 * TODO(gsingh): Enable render nodes on udl/evdi.
94 	 */
95 
96 	char const *render_nodes_fmt = "%s/renderD%d";
97 	char const *card_nodes_fmt = "%s/card%d";
98 	uint32_t num_nodes = DRM_NUM_NODES;
99 	uint32_t min_render_node = DRM_RENDER_NODE_START;
100 	uint32_t max_render_node = (min_render_node + num_nodes);
101 	uint32_t min_card_node = DRM_CARD_NODE_START;
102 	uint32_t max_card_node = (min_card_node + num_nodes);
103 
104 	// Try render nodes...
105 	for (uint32_t i = min_render_node; i < max_render_node; i++) {
106 		drv_ = init_try_node(i, render_nodes_fmt);
107 		if (drv_)
108 			return 0;
109 	}
110 
111 	// Try card nodes... for vkms mostly.
112 	for (uint32_t i = min_card_node; i < max_card_node; i++) {
113 		drv_ = init_try_node(i, card_nodes_fmt);
114 		if (drv_)
115 			return 0;
116 	}
117 
118 	return -ENODEV;
119 }
120 
is_supported(const struct cros_gralloc_buffer_descriptor * descriptor)121 bool cros_gralloc_driver::is_supported(const struct cros_gralloc_buffer_descriptor *descriptor)
122 {
123 	struct combination *combo;
124 	uint32_t resolved_format;
125 	resolved_format = drv_resolve_format(drv_, descriptor->drm_format, descriptor->use_flags);
126 	combo = drv_get_combination(drv_, resolved_format, descriptor->use_flags);
127 	return (combo != nullptr);
128 }
129 
create_reserved_region(const std::string & buffer_name,uint64_t reserved_region_size)130 int32_t create_reserved_region(const std::string &buffer_name, uint64_t reserved_region_size)
131 {
132 	std::string reserved_region_name = buffer_name + " reserved region";
133 
134 	int32_t reserved_region_fd = memfd_create_wrapper(reserved_region_name.c_str(), FD_CLOEXEC);
135 	if (reserved_region_fd == -1)
136 		return -errno;
137 
138 	if (ftruncate(reserved_region_fd, reserved_region_size)) {
139 		drv_log("Failed to set reserved region size: %s.\n", strerror(errno));
140 		return -errno;
141 	}
142 
143 	return reserved_region_fd;
144 }
145 
emplace_buffer(struct bo * bo,struct cros_gralloc_handle * hnd)146 void cros_gralloc_driver::emplace_buffer(struct bo *bo, struct cros_gralloc_handle *hnd)
147 {
148 	auto buffer = new cros_gralloc_buffer(hnd->id, bo, hnd, hnd->fds[hnd->num_planes],
149 					      hnd->reserved_region_size);
150 
151 	std::lock_guard<std::mutex> lock(mutex_);
152 	buffers_.emplace(hnd->id, buffer);
153 	handles_.emplace(hnd, std::make_pair(buffer, 1));
154 }
155 
allocate(const struct cros_gralloc_buffer_descriptor * descriptor,buffer_handle_t * out_handle)156 int32_t cros_gralloc_driver::allocate(const struct cros_gralloc_buffer_descriptor *descriptor,
157 				      buffer_handle_t *out_handle)
158 {
159 	int ret = 0;
160 	size_t num_planes;
161 	size_t num_fds;
162 	size_t num_ints;
163 	size_t num_bytes;
164 	uint32_t resolved_format;
165 	uint32_t bytes_per_pixel;
166 	uint64_t use_flags;
167 	char *name;
168 	struct bo *bo;
169 	struct cros_gralloc_handle *hnd;
170 
171 	resolved_format = drv_resolve_format(drv_, descriptor->drm_format, descriptor->use_flags);
172 	use_flags = descriptor->use_flags;
173 
174 	/*
175 	 * This unmask is a backup in the case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED is resolved
176 	 * to non-YUV formats.
177 	 */
178 	if (descriptor->drm_format == DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED &&
179 	    (resolved_format == DRM_FORMAT_XBGR8888 || resolved_format == DRM_FORMAT_ABGR8888)) {
180 		use_flags &= ~BO_USE_HW_VIDEO_ENCODER;
181 	}
182 
183 	bo = drv_bo_create(drv_, descriptor->width, descriptor->height, resolved_format, use_flags);
184 	if (!bo) {
185 		drv_log("Failed to create bo.\n");
186 		return -errno;
187 	}
188 
189 	/*
190 	 * If there is a desire for more than one kernel buffer, this can be
191 	 * removed once the ArcCodec and Wayland service have the ability to
192 	 * send more than one fd. GL/Vulkan drivers may also have to modified.
193 	 */
194 	if (drv_num_buffers_per_bo(bo) != 1) {
195 		drv_log("Can only support one buffer per bo.\n");
196 		goto destroy_bo;
197 	}
198 
199 	num_planes = drv_bo_get_num_planes(bo);
200 	num_fds = num_planes;
201 
202 	if (descriptor->reserved_region_size > 0)
203 		num_fds += 1;
204 
205 	num_bytes = sizeof(struct cros_gralloc_handle);
206 	num_bytes += (descriptor->name.size() + 1);
207 	/*
208 	 * Ensure that the total number of bytes is a multiple of sizeof(int) as
209 	 * native_handle_clone() copies data based on hnd->base.numInts.
210 	 */
211 	num_bytes = ALIGN(num_bytes, sizeof(int));
212 	num_ints = ((num_bytes - sizeof(native_handle_t)) / sizeof(int)) - num_fds;
213 
214 	hnd =
215 	    reinterpret_cast<struct cros_gralloc_handle *>(native_handle_create(num_fds, num_ints));
216 
217 	for (size_t i = 0; i < DRV_MAX_FDS; i++)
218 		hnd->fds[i] = -1;
219 
220 	hnd->num_planes = num_planes;
221 	for (size_t plane = 0; plane < num_planes; plane++) {
222 		ret = drv_bo_get_plane_fd(bo, plane);
223 		if (ret < 0)
224 			goto destroy_hnd;
225 
226 		hnd->fds[plane] = ret;
227 		hnd->strides[plane] = drv_bo_get_plane_stride(bo, plane);
228 		hnd->offsets[plane] = drv_bo_get_plane_offset(bo, plane);
229 		hnd->sizes[plane] = drv_bo_get_plane_size(bo, plane);
230 	}
231 
232 	hnd->reserved_region_size = descriptor->reserved_region_size;
233 	if (hnd->reserved_region_size > 0) {
234 		ret = create_reserved_region(descriptor->name, hnd->reserved_region_size);
235 		if (ret < 0)
236 			goto destroy_hnd;
237 
238 		hnd->fds[hnd->num_planes] = ret;
239 	}
240 
241 	static std::atomic<uint32_t> next_buffer_id{ 1 };
242 	hnd->id = next_buffer_id++;
243 	hnd->width = drv_bo_get_width(bo);
244 	hnd->height = drv_bo_get_height(bo);
245 	hnd->format = drv_bo_get_format(bo);
246 	hnd->tiling = bo->meta.tiling;
247 	hnd->format_modifier = drv_bo_get_format_modifier(bo);
248 	hnd->use_flags = descriptor->use_flags;
249 	bytes_per_pixel = drv_bytes_per_pixel_from_format(hnd->format, 0);
250 	hnd->pixel_stride = DIV_ROUND_UP(hnd->strides[0], bytes_per_pixel);
251 	hnd->magic = cros_gralloc_magic;
252 	hnd->droid_format = descriptor->droid_format;
253 	hnd->usage = descriptor->droid_usage;
254 	hnd->total_size = descriptor->reserved_region_size + bo->meta.total_size;
255 	hnd->name_offset = handle_data_size;
256 
257 	name = (char *)(&hnd->data[hnd->name_offset]);
258 	snprintf(name, descriptor->name.size() + 1, "%s", descriptor->name.c_str());
259 
260 	emplace_buffer(bo, hnd);
261 
262 	*out_handle = reinterpret_cast<buffer_handle_t>(hnd);
263 	return 0;
264 
265 destroy_hnd:
266 	native_handle_close(hnd);
267 	native_handle_delete(hnd);
268 
269 destroy_bo:
270 	drv_bo_destroy(bo);
271 	return ret;
272 }
273 
retain(buffer_handle_t handle)274 int32_t cros_gralloc_driver::retain(buffer_handle_t handle)
275 {
276 	uint32_t id;
277 	std::lock_guard<std::mutex> lock(mutex_);
278 
279 	auto hnd = cros_gralloc_convert_handle(handle);
280 	if (!hnd) {
281 		drv_log("Invalid handle.\n");
282 		return -EINVAL;
283 	}
284 
285 	auto buffer = get_buffer(hnd);
286 	if (buffer) {
287 		handles_[hnd].second++;
288 		buffer->increase_refcount();
289 		return 0;
290 	}
291 
292 	id = hnd->id;
293 
294 	if (buffers_.count(id)) {
295 		buffer = buffers_[id];
296 		buffer->increase_refcount();
297 	} else {
298 		struct bo *bo;
299 		struct drv_import_fd_data data;
300 		data.format = hnd->format;
301 		data.tiling = hnd->tiling;
302 
303 		data.width = hnd->width;
304 		data.height = hnd->height;
305 		data.use_flags = hnd->use_flags;
306 
307 		memcpy(data.fds, hnd->fds, sizeof(data.fds));
308 		memcpy(data.strides, hnd->strides, sizeof(data.strides));
309 		memcpy(data.offsets, hnd->offsets, sizeof(data.offsets));
310 		data.format_modifier = hnd->format_modifier;
311 
312 		bo = drv_bo_import(drv_, &data);
313 		if (!bo)
314 			return -EFAULT;
315 
316 		buffer = new cros_gralloc_buffer(id, bo, nullptr, hnd->fds[hnd->num_planes],
317 						 hnd->reserved_region_size);
318 		buffers_.emplace(id, buffer);
319 	}
320 
321 	handles_.emplace(hnd, std::make_pair(buffer, 1));
322 	return 0;
323 }
324 
release(buffer_handle_t handle)325 int32_t cros_gralloc_driver::release(buffer_handle_t handle)
326 {
327 	std::lock_guard<std::mutex> lock(mutex_);
328 
329 	auto hnd = cros_gralloc_convert_handle(handle);
330 	if (!hnd) {
331 		drv_log("Invalid handle.\n");
332 		return -EINVAL;
333 	}
334 
335 	auto buffer = get_buffer(hnd);
336 	if (!buffer) {
337 		drv_log("Invalid Reference.\n");
338 		return -EINVAL;
339 	}
340 
341 	if (!--handles_[hnd].second)
342 		handles_.erase(hnd);
343 
344 	if (buffer->decrease_refcount() == 0) {
345 		buffers_.erase(buffer->get_id());
346 		delete buffer;
347 	}
348 
349 	return 0;
350 }
351 
lock(buffer_handle_t handle,int32_t acquire_fence,bool close_acquire_fence,const struct rectangle * rect,uint32_t map_flags,uint8_t * addr[DRV_MAX_PLANES])352 int32_t cros_gralloc_driver::lock(buffer_handle_t handle, int32_t acquire_fence,
353 				  bool close_acquire_fence, const struct rectangle *rect,
354 				  uint32_t map_flags, uint8_t *addr[DRV_MAX_PLANES])
355 {
356 	int32_t ret = cros_gralloc_sync_wait(acquire_fence, close_acquire_fence);
357 	if (ret)
358 		return ret;
359 
360 	std::lock_guard<std::mutex> lock(mutex_);
361 	auto hnd = cros_gralloc_convert_handle(handle);
362 	if (!hnd) {
363 		drv_log("Invalid handle.\n");
364 		return -EINVAL;
365 	}
366 
367 	auto buffer = get_buffer(hnd);
368 	if (!buffer) {
369 		drv_log("Invalid Reference.\n");
370 		return -EINVAL;
371 	}
372 
373 	return buffer->lock(rect, map_flags, addr);
374 }
375 
unlock(buffer_handle_t handle,int32_t * release_fence)376 int32_t cros_gralloc_driver::unlock(buffer_handle_t handle, int32_t *release_fence)
377 {
378 	std::lock_guard<std::mutex> lock(mutex_);
379 
380 	auto hnd = cros_gralloc_convert_handle(handle);
381 	if (!hnd) {
382 		drv_log("Invalid handle.\n");
383 		return -EINVAL;
384 	}
385 
386 	auto buffer = get_buffer(hnd);
387 	if (!buffer) {
388 		drv_log("Invalid Reference.\n");
389 		return -EINVAL;
390 	}
391 
392 	/*
393 	 * From the ANativeWindow::dequeueBuffer documentation:
394 	 *
395 	 * "A value of -1 indicates that the caller may access the buffer immediately without
396 	 * waiting on a fence."
397 	 */
398 	*release_fence = -1;
399 	return buffer->unlock();
400 }
401 
invalidate(buffer_handle_t handle)402 int32_t cros_gralloc_driver::invalidate(buffer_handle_t handle)
403 {
404 	std::lock_guard<std::mutex> lock(mutex_);
405 
406 	auto hnd = cros_gralloc_convert_handle(handle);
407 	if (!hnd) {
408 		drv_log("Invalid handle.\n");
409 		return -EINVAL;
410 	}
411 
412 	auto buffer = get_buffer(hnd);
413 	if (!buffer) {
414 		drv_log("Invalid Reference.\n");
415 		return -EINVAL;
416 	}
417 
418 	return buffer->invalidate();
419 }
420 
flush(buffer_handle_t handle,int32_t * release_fence)421 int32_t cros_gralloc_driver::flush(buffer_handle_t handle, int32_t *release_fence)
422 {
423 	std::lock_guard<std::mutex> lock(mutex_);
424 
425 	auto hnd = cros_gralloc_convert_handle(handle);
426 	if (!hnd) {
427 		drv_log("Invalid handle.\n");
428 		return -EINVAL;
429 	}
430 
431 	auto buffer = get_buffer(hnd);
432 	if (!buffer) {
433 		drv_log("Invalid Reference.\n");
434 		return -EINVAL;
435 	}
436 
437 	/*
438 	 * From the ANativeWindow::dequeueBuffer documentation:
439 	 *
440 	 * "A value of -1 indicates that the caller may access the buffer immediately without
441 	 * waiting on a fence."
442 	 */
443 	*release_fence = -1;
444 	return buffer->flush();
445 }
446 
get_backing_store(buffer_handle_t handle,uint64_t * out_store)447 int32_t cros_gralloc_driver::get_backing_store(buffer_handle_t handle, uint64_t *out_store)
448 {
449 	std::lock_guard<std::mutex> lock(mutex_);
450 
451 	auto hnd = cros_gralloc_convert_handle(handle);
452 	if (!hnd) {
453 		drv_log("Invalid handle.\n");
454 		return -EINVAL;
455 	}
456 
457 	auto buffer = get_buffer(hnd);
458 	if (!buffer) {
459 		drv_log("Invalid Reference.\n");
460 		return -EINVAL;
461 	}
462 
463 	*out_store = static_cast<uint64_t>(buffer->get_id());
464 	return 0;
465 }
466 
resource_info(buffer_handle_t handle,uint32_t strides[DRV_MAX_PLANES],uint32_t offsets[DRV_MAX_PLANES],uint64_t * format_modifier)467 int32_t cros_gralloc_driver::resource_info(buffer_handle_t handle, uint32_t strides[DRV_MAX_PLANES],
468 					   uint32_t offsets[DRV_MAX_PLANES],
469 					   uint64_t *format_modifier)
470 {
471 	std::lock_guard<std::mutex> lock(mutex_);
472 
473 	auto hnd = cros_gralloc_convert_handle(handle);
474 	if (!hnd) {
475 		drv_log("Invalid handle.\n");
476 		return -EINVAL;
477 	}
478 
479 	auto buffer = get_buffer(hnd);
480 	if (!buffer) {
481 		drv_log("Invalid Reference.\n");
482 		return -EINVAL;
483 	}
484 
485 	return buffer->resource_info(strides, offsets, format_modifier);
486 }
487 
get_reserved_region(buffer_handle_t handle,void ** reserved_region_addr,uint64_t * reserved_region_size)488 int32_t cros_gralloc_driver::get_reserved_region(buffer_handle_t handle,
489 						 void **reserved_region_addr,
490 						 uint64_t *reserved_region_size)
491 {
492 	std::lock_guard<std::mutex> lock(mutex_);
493 
494 	auto hnd = cros_gralloc_convert_handle(handle);
495 	if (!hnd) {
496 		drv_log("Invalid handle.\n");
497 		return -EINVAL;
498 	}
499 
500 	auto buffer = get_buffer(hnd);
501 	if (!buffer) {
502 		drv_log("Invalid Reference.\n");
503 		return -EINVAL;
504 	}
505 
506 	return buffer->get_reserved_region(reserved_region_addr, reserved_region_size);
507 }
508 
get_resolved_drm_format(uint32_t drm_format,uint64_t usage)509 uint32_t cros_gralloc_driver::get_resolved_drm_format(uint32_t drm_format, uint64_t usage)
510 {
511 	return drv_resolve_format(drv_, drm_format, usage);
512 }
513 
get_buffer(cros_gralloc_handle_t hnd)514 cros_gralloc_buffer *cros_gralloc_driver::get_buffer(cros_gralloc_handle_t hnd)
515 {
516 	/* Assumes driver mutex is held. */
517 	if (handles_.count(hnd))
518 		return handles_[hnd].first;
519 
520 	return nullptr;
521 }
522 
for_each_handle(const std::function<void (cros_gralloc_handle_t)> & function)523 void cros_gralloc_driver::for_each_handle(
524     const std::function<void(cros_gralloc_handle_t)> &function)
525 {
526 	std::lock_guard<std::mutex> lock(mutex_);
527 
528 	for (const auto &pair : handles_)
529 		function(pair.first);
530 }
531