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