• 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 #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 		drv_destroy(drv_);
25 		drv_ = nullptr;
26 	}
27 }
28 
init()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 
is_supported(const struct cros_gralloc_buffer_descriptor * descriptor)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 
allocate(const struct cros_gralloc_buffer_descriptor * descriptor,buffer_handle_t * out_handle)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 
retain(buffer_handle_t handle)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 
release(buffer_handle_t handle)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 
lock(buffer_handle_t handle,int32_t acquire_fence,const struct rectangle * rect,uint32_t map_flags,uint8_t * addr[DRV_MAX_PLANES])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 
unlock(buffer_handle_t handle,int32_t * release_fence)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 
get_backing_store(buffer_handle_t handle,uint64_t * out_store)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 
get_buffer(cros_gralloc_handle_t hnd)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