OSDN Git Service

Add framebuffer HAL implementation based on drm_framebuffer (v3)
[android-x86/external-minigbm.git] / cros_gralloc / cros_gralloc_driver.cc
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 int cros_gralloc_driver::get_fd() const {
30         return drv_get_fd(drv_);
31 }
32
33 int32_t cros_gralloc_driver::init()
34 {
35         /*
36          * Create a driver from rendernode while filtering out
37          * the specified undesired driver.
38          *
39          * TODO(gsingh): Enable render nodes on udl/evdi.
40          */
41
42         int fd;
43         drmVersionPtr version;
44         char const *str = "%s/renderD%d";
45         const char *undesired[2] = { "vgem", nullptr };
46         uint32_t num_nodes = 63;
47         uint32_t min_node = 128;
48         uint32_t max_node = (min_node + num_nodes);
49
50         for (uint32_t i = 0; i < ARRAY_SIZE(undesired); i++) {
51                 for (uint32_t j = min_node; j < max_node; j++) {
52                         char *node;
53                         if (asprintf(&node, str, DRM_DIR_NAME, j) < 0)
54                                 continue;
55
56                         fd = open(node, O_RDWR, 0);
57                         free(node);
58
59                         if (fd < 0)
60                                 continue;
61
62                         version = drmGetVersion(fd);
63                         if (!version)
64                                 continue;
65
66                         if (undesired[i] && !strcmp(version->name, undesired[i])) {
67                                 drmFreeVersion(version);
68                                 continue;
69                         }
70
71                         drmFreeVersion(version);
72                         drv_ = drv_create(fd);
73                         if (drv_)
74                                 return 0;
75                 }
76         }
77
78         return -ENODEV;
79 }
80
81 int cros_gralloc_driver::init_master()
82 {
83         int fd = open(DRM_DIR_NAME "/card0", O_RDWR, 0);
84         if (fd >= 0) {
85                 drv_ = drv_create(fd);
86                 if (drv_)
87                         return 0;
88         }
89
90         return -ENODEV;
91 }
92
93 bool cros_gralloc_driver::is_supported(const struct cros_gralloc_buffer_descriptor *descriptor)
94 {
95         struct combination *combo;
96         uint32_t resolved_format;
97         resolved_format = drv_resolve_format(drv_, descriptor->drm_format, descriptor->use_flags);
98         combo = drv_get_combination(drv_, resolved_format, descriptor->use_flags);
99         return (combo != nullptr);
100 }
101
102 int32_t cros_gralloc_driver::allocate(const struct cros_gralloc_buffer_descriptor *descriptor,
103                                       buffer_handle_t *out_handle)
104 {
105         uint32_t id;
106         uint64_t mod;
107         size_t num_planes;
108         uint32_t resolved_format;
109         uint32_t bytes_per_pixel;
110         uint64_t use_flags;
111
112         struct bo *bo;
113         struct cros_gralloc_handle *hnd;
114
115         resolved_format = drv_resolve_format(drv_, descriptor->drm_format, descriptor->use_flags);
116         use_flags = descriptor->use_flags;
117         /*
118          * TODO(b/79682290): ARC++ assumes NV12 is always linear and doesn't
119          * send modifiers across Wayland protocol, so we or in the
120          * BO_USE_LINEAR flag here. We need to fix ARC++ to allocate and work
121          * with tiled buffers.
122          */
123         if (resolved_format == DRM_FORMAT_NV12)
124                 use_flags |= BO_USE_LINEAR;
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
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
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
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
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
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
336 cros_gralloc_buffer *cros_gralloc_driver::get_buffer(cros_gralloc_handle_t hnd)
337 {
338         /* Assumes driver mutex is held. */
339         if (handles_.count(hnd))
340                 return handles_[hnd].first;
341
342         return nullptr;
343 }