Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
scenefx/render/pixel_format.c (8.1K)
1 #include <assert.h>
2 #include <drm_fourcc.h>
3 #include <wlr/util/log.h>
4 #include "render/pixel_format.h"
5
6 static const struct wlr_pixel_format_info pixel_format_info[] = {
7 {
8 .drm_format = DRM_FORMAT_XRGB8888,
9 .bytes_per_block = 4,
10 },
11 {
12 .drm_format = DRM_FORMAT_ARGB8888,
13 .opaque_substitute = DRM_FORMAT_XRGB8888,
14 .bytes_per_block = 4,
15 },
16 {
17 .drm_format = DRM_FORMAT_XBGR8888,
18 .bytes_per_block = 4,
19 },
20 {
21 .drm_format = DRM_FORMAT_ABGR8888,
22 .opaque_substitute = DRM_FORMAT_XBGR8888,
23 .bytes_per_block = 4,
24 },
25 {
26 .drm_format = DRM_FORMAT_RGBX8888,
27 .bytes_per_block = 4,
28 },
29 {
30 .drm_format = DRM_FORMAT_RGBA8888,
31 .opaque_substitute = DRM_FORMAT_RGBX8888,
32 .bytes_per_block = 4,
33 },
34 {
35 .drm_format = DRM_FORMAT_BGRX8888,
36 .bytes_per_block = 4,
37 },
38 {
39 .drm_format = DRM_FORMAT_BGRA8888,
40 .opaque_substitute = DRM_FORMAT_BGRX8888,
41 .bytes_per_block = 4,
42 },
43 {
44 .drm_format = DRM_FORMAT_R8,
45 .bytes_per_block = 1,
46 },
47 {
48 .drm_format = DRM_FORMAT_R16F,
49 .bytes_per_block = 2,
50 },
51 {
52 .drm_format = DRM_FORMAT_R32F,
53 .bytes_per_block = 4,
54 },
55 {
56 .drm_format = DRM_FORMAT_GR88,
57 .bytes_per_block = 2,
58 },
59 {
60 .drm_format = DRM_FORMAT_GR1616F,
61 .bytes_per_block = 4,
62 },
63 {
64 .drm_format = DRM_FORMAT_GR3232F,
65 .bytes_per_block = 8,
66 },
67 {
68 .drm_format = DRM_FORMAT_RGB888,
69 .bytes_per_block = 3,
70 },
71 {
72 .drm_format = DRM_FORMAT_BGR888,
73 .bytes_per_block = 3,
74 },
75 {
76 .drm_format = DRM_FORMAT_BGR161616,
77 .bytes_per_block = 6,
78 },
79 {
80 .drm_format = DRM_FORMAT_BGR161616F,
81 .bytes_per_block = 6,
82 },
83 {
84 .drm_format = DRM_FORMAT_BGR323232F,
85 .bytes_per_block = 12,
86 },
87 {
88 .drm_format = DRM_FORMAT_RGBX4444,
89 .bytes_per_block = 2,
90 },
91 {
92 .drm_format = DRM_FORMAT_RGBA4444,
93 .opaque_substitute = DRM_FORMAT_RGBX4444,
94 .bytes_per_block = 2,
95 },
96 {
97 .drm_format = DRM_FORMAT_BGRX4444,
98 .bytes_per_block = 2,
99 },
100 {
101 .drm_format = DRM_FORMAT_BGRA4444,
102 .opaque_substitute = DRM_FORMAT_BGRX4444,
103 .bytes_per_block = 2,
104 },
105 {
106 .drm_format = DRM_FORMAT_RGBX5551,
107 .bytes_per_block = 2,
108 },
109 {
110 .drm_format = DRM_FORMAT_RGBA5551,
111 .opaque_substitute = DRM_FORMAT_RGBX5551,
112 .bytes_per_block = 2,
113 },
114 {
115 .drm_format = DRM_FORMAT_BGRX5551,
116 .bytes_per_block = 2,
117 },
118 {
119 .drm_format = DRM_FORMAT_BGRA5551,
120 .opaque_substitute = DRM_FORMAT_BGRX5551,
121 .bytes_per_block = 2,
122 },
123 {
124 .drm_format = DRM_FORMAT_XRGB1555,
125 .bytes_per_block = 2,
126 },
127 {
128 .drm_format = DRM_FORMAT_ARGB1555,
129 .opaque_substitute = DRM_FORMAT_XRGB1555,
130 .bytes_per_block = 2,
131 },
132 {
133 .drm_format = DRM_FORMAT_RGB565,
134 .bytes_per_block = 2,
135 },
136 {
137 .drm_format = DRM_FORMAT_BGR565,
138 .bytes_per_block = 2,
139 },
140 {
141 .drm_format = DRM_FORMAT_XRGB2101010,
142 .bytes_per_block = 4,
143 },
144 {
145 .drm_format = DRM_FORMAT_ARGB2101010,
146 .opaque_substitute = DRM_FORMAT_XRGB2101010,
147 .bytes_per_block = 4,
148 },
149 {
150 .drm_format = DRM_FORMAT_XBGR2101010,
151 .bytes_per_block = 4,
152 },
153 {
154 .drm_format = DRM_FORMAT_ABGR2101010,
155 .opaque_substitute = DRM_FORMAT_XBGR2101010,
156 .bytes_per_block = 4,
157 },
158 {
159 .drm_format = DRM_FORMAT_XBGR16161616F,
160 .bytes_per_block = 8,
161 },
162 {
163 .drm_format = DRM_FORMAT_ABGR16161616F,
164 .opaque_substitute = DRM_FORMAT_XBGR16161616F,
165 .bytes_per_block = 8,
166 },
167 {
168 .drm_format = DRM_FORMAT_ABGR32323232F,
169 .bytes_per_block = 16,
170 },
171 {
172 .drm_format = DRM_FORMAT_XBGR16161616,
173 .bytes_per_block = 8,
174 },
175 {
176 .drm_format = DRM_FORMAT_ABGR16161616,
177 .opaque_substitute = DRM_FORMAT_XBGR16161616,
178 .bytes_per_block = 8,
179 },
180 {
181 .drm_format = DRM_FORMAT_YVYU,
182 .bytes_per_block = 4,
183 .block_width = 2,
184 .block_height = 1,
185 },
186 {
187 .drm_format = DRM_FORMAT_VYUY,
188 .bytes_per_block = 4,
189 .block_width = 2,
190 .block_height = 1,
191 },
192 };
193
194 static const uint32_t opaque_pixel_formats[] = {
195 DRM_FORMAT_XRGB8888,
196 DRM_FORMAT_XBGR8888,
197 DRM_FORMAT_RGBX8888,
198 DRM_FORMAT_BGRX8888,
199 DRM_FORMAT_R8,
200 DRM_FORMAT_GR88,
201 DRM_FORMAT_RGB888,
202 DRM_FORMAT_BGR888,
203 DRM_FORMAT_RGBX4444,
204 DRM_FORMAT_BGRX4444,
205 DRM_FORMAT_RGBX5551,
206 DRM_FORMAT_BGRX5551,
207 DRM_FORMAT_XRGB1555,
208 DRM_FORMAT_RGB565,
209 DRM_FORMAT_BGR565,
210 DRM_FORMAT_XRGB2101010,
211 DRM_FORMAT_XBGR2101010,
212 DRM_FORMAT_XBGR16161616F,
213 DRM_FORMAT_XBGR16161616,
214 DRM_FORMAT_YVYU,
215 DRM_FORMAT_VYUY,
216 DRM_FORMAT_NV12,
217 DRM_FORMAT_P010,
218 };
219
220 static const size_t pixel_format_info_size =
221 sizeof(pixel_format_info) / sizeof(pixel_format_info[0]);
222
223 static const size_t opaque_pixel_formats_size =
224 sizeof(opaque_pixel_formats) / sizeof(opaque_pixel_formats[0]);
225
226 const struct wlr_pixel_format_info *drm_get_pixel_format_info(uint32_t fmt) {
227 for (size_t i = 0; i < pixel_format_info_size; ++i) {
228 if (pixel_format_info[i].drm_format == fmt) {
229 return &pixel_format_info[i];
230 }
231 }
232
233 return NULL;
234 }
235
236 uint32_t convert_wl_shm_format_to_drm(enum wl_shm_format fmt) {
237 switch (fmt) {
238 case WL_SHM_FORMAT_XRGB8888:
239 return DRM_FORMAT_XRGB8888;
240 case WL_SHM_FORMAT_ARGB8888:
241 return DRM_FORMAT_ARGB8888;
242 default:
243 return (uint32_t)fmt;
244 }
245 }
246
247 enum wl_shm_format convert_drm_format_to_wl_shm(uint32_t fmt) {
248 switch (fmt) {
249 case DRM_FORMAT_XRGB8888:
250 return WL_SHM_FORMAT_XRGB8888;
251 case DRM_FORMAT_ARGB8888:
252 return WL_SHM_FORMAT_ARGB8888;
253 default:
254 return (enum wl_shm_format)fmt;
255 }
256 }
257
258 uint32_t pixel_format_info_pixels_per_block(const struct wlr_pixel_format_info *info) {
259 uint32_t pixels = info->block_width * info->block_height;
260 return pixels > 0 ? pixels : 1;
261 }
262
263 static int32_t div_round_up(int32_t dividend, int32_t divisor) {
264 int32_t quotient = dividend / divisor;
265 if (dividend % divisor != 0) {
266 quotient++;
267 }
268 return quotient;
269 }
270
271 int32_t pixel_format_info_min_stride(const struct wlr_pixel_format_info *fmt, int32_t width) {
272 int32_t pixels_per_block = (int32_t)pixel_format_info_pixels_per_block(fmt);
273 int32_t bytes_per_block = (int32_t)fmt->bytes_per_block;
274 if (width > INT32_MAX / bytes_per_block) {
275 wlr_log(WLR_DEBUG, "Invalid width %d (overflow)", width);
276 return 0;
277 }
278 return div_round_up(width * bytes_per_block, pixels_per_block);
279 }
280
281 bool pixel_format_info_check_stride(const struct wlr_pixel_format_info *fmt,
282 int32_t stride, int32_t width) {
283 int32_t bytes_per_block = (int32_t)fmt->bytes_per_block;
284 if (stride % bytes_per_block != 0) {
285 wlr_log(WLR_DEBUG, "Invalid stride %d (incompatible with %d "
286 "bytes-per-block)", stride, bytes_per_block);
287 return false;
288 }
289
290 int32_t min_stride = pixel_format_info_min_stride(fmt, width);
291 if (min_stride <= 0) {
292 return false;
293 } else if (stride < min_stride) {
294 wlr_log(WLR_DEBUG, "Invalid stride %d (too small for %d "
295 "bytes-per-block and width %d)", stride, bytes_per_block, width);
296 return false;
297 }
298
299 return true;
300 }
301
302 bool pixel_format_has_alpha(uint32_t fmt) {
303 for (size_t i = 0; i < opaque_pixel_formats_size; i++) {
304 if (fmt == opaque_pixel_formats[i]) {
305 return false;
306 }
307 }
308 return true;
309 }
310
311 bool pixel_format_is_ycbcr(uint32_t format) {
312 switch (format) {
313 case DRM_FORMAT_AYUV:
314 case DRM_FORMAT_NV12:
315 case DRM_FORMAT_NV15:
316 case DRM_FORMAT_NV16:
317 case DRM_FORMAT_NV20:
318 case DRM_FORMAT_NV21:
319 case DRM_FORMAT_NV24:
320 case DRM_FORMAT_NV30:
321 case DRM_FORMAT_NV42:
322 case DRM_FORMAT_NV61:
323 case DRM_FORMAT_P010:
324 case DRM_FORMAT_P012:
325 case DRM_FORMAT_P016:
326 case DRM_FORMAT_P030:
327 case DRM_FORMAT_P210:
328 case DRM_FORMAT_Q401:
329 case DRM_FORMAT_Q410:
330 case DRM_FORMAT_S010:
331 case DRM_FORMAT_S012:
332 case DRM_FORMAT_S016:
333 case DRM_FORMAT_S210:
334 case DRM_FORMAT_S212:
335 case DRM_FORMAT_S216:
336 case DRM_FORMAT_S410:
337 case DRM_FORMAT_S412:
338 case DRM_FORMAT_S416:
339 case DRM_FORMAT_UYVY:
340 case DRM_FORMAT_VUY101010:
341 case DRM_FORMAT_VUY888:
342 case DRM_FORMAT_VYUY:
343 case DRM_FORMAT_X0L0:
344 case DRM_FORMAT_X0L2:
345 case DRM_FORMAT_XVYU12_16161616:
346 case DRM_FORMAT_XVYU16161616:
347 case DRM_FORMAT_XVYU2101010:
348 case DRM_FORMAT_XYUV8888:
349 case DRM_FORMAT_Y0L0:
350 case DRM_FORMAT_Y0L2:
351 case DRM_FORMAT_Y210:
352 case DRM_FORMAT_Y212:
353 case DRM_FORMAT_Y216:
354 case DRM_FORMAT_Y410:
355 case DRM_FORMAT_Y412:
356 case DRM_FORMAT_Y416:
357 case DRM_FORMAT_YUV410:
358 case DRM_FORMAT_YUV411:
359 case DRM_FORMAT_YUV420:
360 case DRM_FORMAT_YUV420_10BIT:
361 case DRM_FORMAT_YUV420_8BIT:
362 case DRM_FORMAT_YUV422:
363 case DRM_FORMAT_YUV444:
364 case DRM_FORMAT_YUYV:
365 case DRM_FORMAT_YVU410:
366 case DRM_FORMAT_YVU411:
367 case DRM_FORMAT_YVU420:
368 case DRM_FORMAT_YVU422:
369 case DRM_FORMAT_YVU444:
370 case DRM_FORMAT_YVYU:
371 return true;
372 }
373 return false;
374 }