blob: aa555c8757d44f0ccc6136e4977a4255a19d03d0 [file] [log] [blame]
Stéphane Marchesin25a26062014-09-12 16:18:59 -07001/*
2 * Copyright (c) 2014 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
Yuly Novikov96c7a3b2015-12-08 22:48:29 -05007#include <assert.h>
8#include <stdbool.h>
Stéphane Marchesin25a26062014-09-12 16:18:59 -07009#include <stdio.h>
Yuly Novikov96c7a3b2015-12-08 22:48:29 -050010#include <stdlib.h>
Stéphane Marchesin25a26062014-09-12 16:18:59 -070011#include <string.h>
Gurchetan Singhef920532016-08-12 16:38:25 -070012#include <sys/mman.h>
Stéphane Marchesin25a26062014-09-12 16:18:59 -070013#include <xf86drm.h>
14
Gurchetan Singh46faf6b2016-08-05 14:40:07 -070015#include "drv_priv.h"
Lauri Peltonen904a8792015-01-17 13:57:51 +020016#include "helpers.h"
Yuly Novikov96c7a3b2015-12-08 22:48:29 -050017#include "util.h"
18
Gurchetan Singh83dc4fb2016-07-19 15:52:33 -070019int drv_bpp_from_format(uint32_t format, size_t plane)
Stéphane Marchesin25a26062014-09-12 16:18:59 -070020{
Gurchetan Singh83dc4fb2016-07-19 15:52:33 -070021 assert(plane < drv_num_planes_from_format(format));
22
Gurchetan Singhd6fb5772016-08-29 19:13:51 -070023 switch (format) {
24 case DRV_FORMAT_C8:
25 case DRV_FORMAT_R8:
26 case DRV_FORMAT_RGB332:
27 case DRV_FORMAT_BGR233:
Gurchetan Singh2a119342016-11-02 10:40:51 -070028 case DRV_FORMAT_YVU420:
Gurchetan Singhd6fb5772016-08-29 19:13:51 -070029 return 8;
Stéphane Marchesin25a26062014-09-12 16:18:59 -070030
Gurchetan Singh2a119342016-11-02 10:40:51 -070031 /*
32 * NV12 is laid out as follows. Each letter represents a byte.
33 * Y plane:
34 * Y0_0, Y0_1, Y0_2, Y0_3, ..., Y0_N
35 * Y1_0, Y1_1, Y1_2, Y1_3, ..., Y1_N
36 * ...
37 * YM_0, YM_1, YM_2, YM_3, ..., YM_N
38 * CbCr plane:
39 * Cb01_01, Cr01_01, Cb01_23, Cr01_23, ..., Cb01_(N-1)N, Cr01_(N-1)N
40 * Cb23_01, Cr23_01, Cb23_23, Cr23_23, ..., Cb23_(N-1)N, Cr23_(N-1)N
41 * ...
42 * Cb(M-1)M_01, Cr(M-1)M_01, ..., Cb(M-1)M_(N-1)N, Cr(M-1)M_(N-1)N
43 *
44 * Pixel (0, 0) requires Y0_0, Cb01_01 and Cr01_01. Pixel (0, 1) requires
45 * Y0_1, Cb01_01 and Cr01_01. So for a single pixel, 2 bytes of luma data
46 * are required.
47 */
Gurchetan Singhd6fb5772016-08-29 19:13:51 -070048 case DRV_FORMAT_NV12:
Gurchetan Singh2a119342016-11-02 10:40:51 -070049 return (plane == 0) ? 8 : 16;
Yuly Novikov96c7a3b2015-12-08 22:48:29 -050050
Gurchetan Singhd6fb5772016-08-29 19:13:51 -070051 case DRV_FORMAT_RG88:
52 case DRV_FORMAT_GR88:
53 case DRV_FORMAT_XRGB4444:
54 case DRV_FORMAT_XBGR4444:
55 case DRV_FORMAT_RGBX4444:
56 case DRV_FORMAT_BGRX4444:
57 case DRV_FORMAT_ARGB4444:
58 case DRV_FORMAT_ABGR4444:
59 case DRV_FORMAT_RGBA4444:
60 case DRV_FORMAT_BGRA4444:
61 case DRV_FORMAT_XRGB1555:
62 case DRV_FORMAT_XBGR1555:
63 case DRV_FORMAT_RGBX5551:
64 case DRV_FORMAT_BGRX5551:
65 case DRV_FORMAT_ARGB1555:
66 case DRV_FORMAT_ABGR1555:
67 case DRV_FORMAT_RGBA5551:
68 case DRV_FORMAT_BGRA5551:
69 case DRV_FORMAT_RGB565:
70 case DRV_FORMAT_BGR565:
71 case DRV_FORMAT_YUYV:
72 case DRV_FORMAT_YVYU:
73 case DRV_FORMAT_UYVY:
74 case DRV_FORMAT_VYUY:
75 return 16;
Stéphane Marchesin25a26062014-09-12 16:18:59 -070076
Gurchetan Singhd6fb5772016-08-29 19:13:51 -070077 case DRV_FORMAT_RGB888:
78 case DRV_FORMAT_BGR888:
79 return 24;
Stéphane Marchesin25a26062014-09-12 16:18:59 -070080
Gurchetan Singhd6fb5772016-08-29 19:13:51 -070081 case DRV_FORMAT_XRGB8888:
82 case DRV_FORMAT_XBGR8888:
83 case DRV_FORMAT_RGBX8888:
84 case DRV_FORMAT_BGRX8888:
85 case DRV_FORMAT_ARGB8888:
86 case DRV_FORMAT_ABGR8888:
87 case DRV_FORMAT_RGBA8888:
88 case DRV_FORMAT_BGRA8888:
89 case DRV_FORMAT_XRGB2101010:
90 case DRV_FORMAT_XBGR2101010:
91 case DRV_FORMAT_RGBX1010102:
92 case DRV_FORMAT_BGRX1010102:
93 case DRV_FORMAT_ARGB2101010:
94 case DRV_FORMAT_ABGR2101010:
95 case DRV_FORMAT_RGBA1010102:
96 case DRV_FORMAT_BGRA1010102:
97 case DRV_FORMAT_AYUV:
98 return 32;
Stéphane Marchesin25a26062014-09-12 16:18:59 -070099 }
100
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700101 fprintf(stderr, "drv: UNKNOWN FORMAT %d\n", format);
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700102 return 0;
103}
104
Gurchetan Singh83dc4fb2016-07-19 15:52:33 -0700105/*
Gurchetan Singh42cc6d62016-08-29 18:19:19 -0700106 * This function fills in the buffer object given driver aligned dimensions
107 * and a format. This function assumes there is just one kernel buffer per
108 * buffer object.
109 */
110int drv_bo_from_format(struct bo *bo, uint32_t width, uint32_t height,
111 drv_format_t format)
112{
113
Gurchetan Singh2a119342016-11-02 10:40:51 -0700114 size_t p, num_planes;
115 uint32_t offset = 0;
116
117 num_planes = drv_num_planes_from_format(format);
118 assert(num_planes);
119
120 for (p = 0; p < num_planes; p++) {
121 bo->strides[p] = drv_stride_from_format(format, width, p);
122 bo->sizes[p] = drv_size_from_format(format, bo->strides[p],
123 height, p);
124 bo->offsets[p] = offset;
125 offset += bo->sizes[p];
Gurchetan Singh42cc6d62016-08-29 18:19:19 -0700126 }
127
Gurchetan Singha40ca9e2016-08-29 19:51:45 -0700128 bo->total_size = bo->offsets[bo->num_planes - 1] +
129 bo->sizes[bo->num_planes - 1];
130
Gurchetan Singh42cc6d62016-08-29 18:19:19 -0700131 return 0;
132}
133
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700134int drv_dumb_bo_create(struct bo *bo, uint32_t width, uint32_t height,
Stéphane Marchesinec88e892015-11-03 16:14:59 -0800135 uint32_t format, uint32_t flags)
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700136{
137 struct drm_mode_create_dumb create_dumb;
138 int ret;
139
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500140 /* Only single-plane formats are supported */
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700141 assert(drv_num_planes_from_format(format) == 1);
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500142
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700143 memset(&create_dumb, 0, sizeof(create_dumb));
144 create_dumb.height = height;
145 create_dumb.width = width;
Gurchetan Singh83dc4fb2016-07-19 15:52:33 -0700146 create_dumb.bpp = drv_bpp_from_format(format, 0);
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700147 create_dumb.flags = 0;
148
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700149 ret = drmIoctl(bo->drv->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
Ilja H. Friedelf9d2ab72015-04-09 14:08:36 -0700150 if (ret) {
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700151 fprintf(stderr, "drv: DRM_IOCTL_MODE_CREATE_DUMB failed\n");
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700152 return ret;
Ilja H. Friedelf9d2ab72015-04-09 14:08:36 -0700153 }
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700154
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500155 bo->handles[0].u32 = create_dumb.handle;
156 bo->offsets[0] = 0;
Gurchetan Singha40ca9e2016-08-29 19:51:45 -0700157 bo->total_size = bo->sizes[0] = create_dumb.size;
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500158 bo->strides[0] = create_dumb.pitch;
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700159
160 return 0;
161}
162
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700163int drv_dumb_bo_destroy(struct bo *bo)
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700164{
165 struct drm_mode_destroy_dumb destroy_dumb;
166 int ret;
167
168 memset(&destroy_dumb, 0, sizeof(destroy_dumb));
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500169 destroy_dumb.handle = bo->handles[0].u32;
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700170
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700171 ret = drmIoctl(bo->drv->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
Ilja H. Friedelf9d2ab72015-04-09 14:08:36 -0700172 if (ret) {
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700173 fprintf(stderr, "drv: DRM_IOCTL_MODE_DESTROY_DUMB failed "
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500174 "(handle=%x)\n", bo->handles[0].u32);
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700175 return ret;
Ilja H. Friedelf9d2ab72015-04-09 14:08:36 -0700176 }
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700177
178 return 0;
179}
180
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700181int drv_gem_bo_destroy(struct bo *bo)
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700182{
183 struct drm_gem_close gem_close;
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500184 int ret, error = 0;
185 size_t plane, i;
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700186
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500187 for (plane = 0; plane < bo->num_planes; plane++) {
Gurchetan Singhf64487b2016-07-14 19:54:44 -0700188 for (i = 0; i < plane; i++)
189 if (bo->handles[i].u32 == bo->handles[plane].u32)
190 break;
191 /* Make sure close hasn't already been called on this handle */
192 if (i != plane)
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500193 continue;
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700194
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500195 memset(&gem_close, 0, sizeof(gem_close));
196 gem_close.handle = bo->handles[plane].u32;
197
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700198 ret = drmIoctl(bo->drv->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500199 if (ret) {
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700200 fprintf(stderr, "drv: DRM_IOCTL_GEM_CLOSE failed "
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500201 "(handle=%x) error %d\n",
202 bo->handles[plane].u32, ret);
203 error = ret;
204 }
Ilja H. Friedelf9d2ab72015-04-09 14:08:36 -0700205 }
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700206
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500207 return error;
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700208}
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700209
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700210void *drv_dumb_bo_map(struct bo *bo, struct map_info *data, size_t plane)
Gurchetan Singhef920532016-08-12 16:38:25 -0700211{
212 int ret;
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700213 size_t i;
Gurchetan Singhef920532016-08-12 16:38:25 -0700214 struct drm_mode_map_dumb map_dumb;
215
216 memset(&map_dumb, 0, sizeof(map_dumb));
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700217 map_dumb.handle = bo->handles[plane].u32;
Gurchetan Singhef920532016-08-12 16:38:25 -0700218
219 ret = drmIoctl(bo->drv->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb);
220 if (ret) {
221 fprintf(stderr, "drv: DRM_IOCTL_MODE_MAP_DUMB failed \n");
222 return MAP_FAILED;
223 }
224
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700225 for (i = 0; i < bo->num_planes; i++)
226 if (bo->handles[i].u32 == bo->handles[plane].u32)
227 data->length += bo->sizes[i];
228
229 return mmap(0, data->length, PROT_READ | PROT_WRITE, MAP_SHARED,
Gurchetan Singhef920532016-08-12 16:38:25 -0700230 bo->drv->fd, map_dumb.offset);
231}
232
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700233uintptr_t drv_get_reference_count(struct driver *drv, struct bo *bo,
234 size_t plane)
235{
236 void *count;
237 uintptr_t num = 0;
238
239 if (!drmHashLookup(drv->buffer_table, bo->handles[plane].u32, &count))
240 num = (uintptr_t) (count);
241
242 return num;
243}
244
245void drv_increment_reference_count(struct driver *drv, struct bo *bo,
246 size_t plane)
247{
248 uintptr_t num = drv_get_reference_count(drv, bo, plane);
249
250 /* If a value isn't in the table, drmHashDelete is a no-op */
251 drmHashDelete(drv->buffer_table, bo->handles[plane].u32);
252 drmHashInsert(drv->buffer_table, bo->handles[plane].u32,
253 (void *) (num + 1));
254}
255
256void drv_decrement_reference_count(struct driver *drv, struct bo *bo,
257 size_t plane)
258{
259 uintptr_t num = drv_get_reference_count(drv, bo, plane);
260
261 drmHashDelete(drv->buffer_table, bo->handles[plane].u32);
262
263 if (num > 0)
264 drmHashInsert(drv->buffer_table, bo->handles[plane].u32,
265 (void *) (num - 1));
266}
Gurchetan Singhef920532016-08-12 16:38:25 -0700267
Akshu Agrawal0337d9b2016-07-28 15:35:45 +0530268uint32_t drv_log_base2(uint32_t value)
269{
270 int ret = 0;
271
272 while (value >>= 1)
273 ++ret;
274
275 return ret;
276}