OSDN Git Service

Add support to query tiling mode.
[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 "i915_private_android.h"
11
12 #include <cstdlib>
13 #include <fcntl.h>
14 #include <xf86drm.h>
15
16 cros_gralloc_driver::cros_gralloc_driver() : drv_(nullptr)
17 {
18 }
19
20 cros_gralloc_driver::~cros_gralloc_driver()
21 {
22         buffers_.clear();
23         handles_.clear();
24
25         if (drv_) {
26                 drv_destroy(drv_);
27                 drv_ = nullptr;
28         }
29 }
30
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                                 continue;
63
64                         if (undesired[i] && !strcmp(version->name, undesired[i])) {
65                                 drmFreeVersion(version);
66                                 continue;
67                         }
68
69                         drmFreeVersion(version);
70                         drv_ = drv_create(fd);
71                         if (drv_)
72                                 return 0;
73                 }
74         }
75
76         return -ENODEV;
77 }
78
79 bool cros_gralloc_driver::is_supported(const struct cros_gralloc_buffer_descriptor *descriptor)
80 {
81         struct combination *combo;
82         uint32_t resolved_format;
83         resolved_format = drv_resolve_format(drv_, descriptor->drm_format, descriptor->use_flags);
84         combo = drv_get_combination(drv_, resolved_format, descriptor->use_flags);
85         return (combo != nullptr);
86 }
87
88 int32_t cros_gralloc_driver::allocate(const struct cros_gralloc_buffer_descriptor *descriptor,
89                                       buffer_handle_t *out_handle)
90 {
91         uint32_t id;
92         uint64_t mod;
93         size_t num_planes;
94         uint32_t resolved_format;
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         if (descriptor->modifier == 0) {
101                 bo = drv_bo_create(drv_, descriptor->width, descriptor->height, resolved_format,
102                                    descriptor->use_flags);
103         } else {
104                 bo = drv_bo_create_with_modifiers(drv_, descriptor->width, descriptor->height,
105                                                   resolved_format, &descriptor->modifier, 1);
106         }
107         if (!bo) {
108                 cros_gralloc_error("Failed to create bo.");
109                 return -ENOMEM;
110         }
111
112         /*
113          * If there is a desire for more than one kernel buffer, this can be
114          * removed once the ArcCodec and Wayland service have the ability to
115          * send more than one fd. GL/Vulkan drivers may also have to modified.
116          */
117         if (drv_num_buffers_per_bo(bo) != 1) {
118                 drv_bo_destroy(bo);
119                 cros_gralloc_error("Can only support one buffer per bo.");
120                 return -EINVAL;
121         }
122
123         hnd = new cros_gralloc_handle();
124         num_planes = drv_bo_get_num_planes(bo);
125
126         hnd->base.version = sizeof(hnd->base);
127         hnd->base.numFds = num_planes;
128         hnd->base.numInts = handle_data_size - num_planes;
129
130         for (size_t plane = 0; plane < num_planes; plane++) {
131                 hnd->fds[plane] = drv_bo_get_plane_fd(bo, plane);
132                 hnd->strides[plane] = drv_bo_get_plane_stride(bo, plane);
133                 hnd->offsets[plane] = drv_bo_get_plane_offset(bo, plane);
134                 hnd->sizes[plane] = drv_bo_get_plane_size(bo, plane);
135
136                 mod = drv_bo_get_plane_format_modifier(bo, plane);
137                 hnd->format_modifiers[2 * plane] = static_cast<uint32_t>(mod >> 32);
138                 hnd->format_modifiers[2 * plane + 1] = static_cast<uint32_t>(mod);
139         }
140
141         hnd->width = drv_bo_get_width(bo);
142         hnd->height = drv_bo_get_height(bo);
143         hnd->format = drv_bo_get_format(bo);
144         hnd->tiling_mode = drv_bo_get_stride_or_tiling(bo);
145         hnd->use_flags[0] = static_cast<uint32_t>(descriptor->use_flags >> 32);
146         hnd->use_flags[1] = static_cast<uint32_t>(descriptor->use_flags);
147         hnd->pixel_stride = drv_bo_get_stride_in_pixels(bo);
148         hnd->magic = cros_gralloc_magic;
149         int32_t format = i915_private_invert_format(hnd->format);
150         if (format == 0) {
151                 format =  descriptor->droid_format;
152         }
153         hnd->droid_format = format;
154         hnd->usage = descriptor->producer_usage;
155         hnd->producer_usage = descriptor->producer_usage;
156         hnd->consumer_usage = descriptor->consumer_usage;
157
158         id = drv_bo_get_plane_handle(bo, 0).u32;
159         auto buffer = new cros_gralloc_buffer(id, bo, hnd);
160
161         SCOPED_SPIN_LOCK(mutex_);
162         buffers_.emplace(id, buffer);
163         handles_.emplace(hnd, std::make_pair(buffer, 1));
164         *out_handle = &hnd->base;
165         return 0;
166 }
167
168 int32_t cros_gralloc_driver::retain(buffer_handle_t handle)
169 {
170         uint32_t id;
171         SCOPED_SPIN_LOCK(mutex_);
172
173         auto hnd = cros_gralloc_convert_handle(handle);
174         if (!hnd) {
175                 cros_gralloc_error("Invalid handle.");
176                 return -EINVAL;
177         }
178
179         auto buffer = get_buffer(hnd);
180         if (buffer) {
181                 handles_[hnd].second++;
182                 buffer->increase_refcount();
183                 return 0;
184         }
185
186         if (drmPrimeFDToHandle(drv_get_fd(drv_), hnd->fds[0], &id)) {
187                 cros_gralloc_error("drmPrimeFDToHandle failed.");
188                 return -errno;
189         }
190
191         if (buffers_.count(id)) {
192                 buffer = buffers_[id];
193                 buffer->increase_refcount();
194         } else {
195                 struct bo *bo;
196                 struct drv_import_fd_data data;
197                 data.format = hnd->format;
198                 data.width = hnd->width;
199                 data.height = hnd->height;
200                 data.use_flags = static_cast<uint64_t>(hnd->use_flags[0]) << 32;
201                 data.use_flags |= hnd->use_flags[1];
202
203                 memcpy(data.fds, hnd->fds, sizeof(data.fds));
204                 memcpy(data.strides, hnd->strides, sizeof(data.strides));
205                 memcpy(data.offsets, hnd->offsets, sizeof(data.offsets));
206                 for (uint32_t plane = 0; plane < DRV_MAX_PLANES; plane++) {
207                         data.format_modifiers[plane] =
208                             static_cast<uint64_t>(hnd->format_modifiers[2 * plane]) << 32;
209                         data.format_modifiers[plane] |= hnd->format_modifiers[2 * plane + 1];
210                 }
211
212                 bo = drv_bo_import(drv_, &data);
213                 if (!bo)
214                         return -EFAULT;
215
216                 id = drv_bo_get_plane_handle(bo, 0).u32;
217
218                 buffer = new cros_gralloc_buffer(id, bo, nullptr);
219                 buffers_.emplace(id, buffer);
220         }
221
222         handles_.emplace(hnd, std::make_pair(buffer, 1));
223         return 0;
224 }
225
226 int32_t cros_gralloc_driver::release(buffer_handle_t handle)
227 {
228         SCOPED_SPIN_LOCK(mutex_);
229
230         auto hnd = cros_gralloc_convert_handle(handle);
231         if (!hnd) {
232                 cros_gralloc_error("Invalid handle.");
233                 return -EINVAL;
234         }
235
236         auto buffer = get_buffer(hnd);
237         if (!buffer) {
238                 cros_gralloc_error("Invalid Reference.");
239                 return -EINVAL;
240         }
241
242         if (!--handles_[hnd].second)
243                 handles_.erase(hnd);
244
245         if (buffer->decrease_refcount() == 0) {
246                 buffers_.erase(buffer->get_id());
247                 delete buffer;
248         }
249
250         return 0;
251 }
252
253 int32_t cros_gralloc_driver::lock(buffer_handle_t handle, int32_t acquire_fence, uint32_t map_flags,
254                                   uint8_t *addr[DRV_MAX_PLANES])
255 {
256         int32_t ret = cros_gralloc_sync_wait(acquire_fence);
257         if (ret)
258                 return ret;
259
260         SCOPED_SPIN_LOCK(mutex_);
261         auto hnd = cros_gralloc_convert_handle(handle);
262         if (!hnd) {
263                 cros_gralloc_error("Invalid handle.");
264                 return -EINVAL;
265         }
266
267         auto buffer = get_buffer(hnd);
268         if (!buffer) {
269                 cros_gralloc_error("Invalid Reference.");
270                 return -EINVAL;
271         }
272
273         return buffer->lock(map_flags, addr);
274 }
275
276 int32_t cros_gralloc_driver::unlock(buffer_handle_t handle, int32_t *release_fence)
277 {
278         SCOPED_SPIN_LOCK(mutex_);;
279
280         auto hnd = cros_gralloc_convert_handle(handle);
281         if (!hnd) {
282                 cros_gralloc_error("Invalid handle.");
283                 return -EINVAL;
284         }
285
286         auto buffer = get_buffer(hnd);
287         if (!buffer) {
288                 cros_gralloc_error("Invalid Reference.");
289                 return -EINVAL;
290         }
291
292         /*
293          * From the ANativeWindow::dequeueBuffer documentation:
294          *
295          * "A value of -1 indicates that the caller may access the buffer immediately without
296          * waiting on a fence."
297          */
298         *release_fence = -1;
299         return buffer->unlock();
300 }
301
302 int32_t cros_gralloc_driver::get_backing_store(buffer_handle_t handle, uint64_t *out_store)
303 {
304         SCOPED_SPIN_LOCK(mutex_);
305
306         auto hnd = cros_gralloc_convert_handle(handle);
307         if (!hnd) {
308                 cros_gralloc_error("Invalid handle.");
309                 return -EINVAL;
310         }
311
312         auto buffer = get_buffer(hnd);
313         if (!buffer) {
314                 cros_gralloc_error("Invalid Reference.");
315                 return -EINVAL;
316         }
317
318         *out_store = static_cast<uint64_t>(buffer->get_id());
319         return 0;
320 }
321
322 cros_gralloc_buffer *cros_gralloc_driver::get_buffer(cros_gralloc_handle_t hnd)
323 {
324         /* Assumes driver mutex is held. */
325         if (handles_.count(hnd))
326                 return handles_[hnd].first;
327
328         return nullptr;
329 }