xref: /linux/drivers/gpu/drm/drm_fourcc.c (revision 071bf69a0220253a44acb8b2a27f7a262b9a46bf)
1 /*
2  * Copyright (c) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
3  *
4  * DRM core format related functions
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that copyright
9  * notice and this permission notice appear in supporting documentation, and
10  * that the name of the copyright holders not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  The copyright holders make no representations
13  * about the suitability of this software for any purpose.  It is provided "as
14  * is" without express or implied warranty.
15  *
16  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22  * OF THIS SOFTWARE.
23  */
24 
25 #include <linux/bug.h>
26 #include <linux/ctype.h>
27 #include <linux/export.h>
28 #include <linux/kernel.h>
29 
30 #include <drm/drmP.h>
31 #include <drm/drm_fourcc.h>
32 
33 static char printable_char(int c)
34 {
35 	return isascii(c) && isprint(c) ? c : '?';
36 }
37 
38 /**
39  * drm_get_format_name - return a string for drm fourcc format
40  * @format: format to compute name of
41  *
42  * Note that the buffer used by this function is globally shared and owned by
43  * the function itself.
44  *
45  * FIXME: This isn't really multithreading safe.
46  */
47 const char *drm_get_format_name(uint32_t format)
48 {
49 	static char buf[32];
50 
51 	snprintf(buf, sizeof(buf),
52 		 "%c%c%c%c %s-endian (0x%08x)",
53 		 printable_char(format & 0xff),
54 		 printable_char((format >> 8) & 0xff),
55 		 printable_char((format >> 16) & 0xff),
56 		 printable_char((format >> 24) & 0x7f),
57 		 format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little",
58 		 format);
59 
60 	return buf;
61 }
62 EXPORT_SYMBOL(drm_get_format_name);
63 
64 /**
65  * drm_fb_get_bpp_depth - get the bpp/depth values for format
66  * @format: pixel format (DRM_FORMAT_*)
67  * @depth: storage for the depth value
68  * @bpp: storage for the bpp value
69  *
70  * This only supports RGB formats here for compat with code that doesn't use
71  * pixel formats directly yet.
72  */
73 void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
74 			  int *bpp)
75 {
76 	switch (format) {
77 	case DRM_FORMAT_C8:
78 	case DRM_FORMAT_RGB332:
79 	case DRM_FORMAT_BGR233:
80 		*depth = 8;
81 		*bpp = 8;
82 		break;
83 	case DRM_FORMAT_XRGB1555:
84 	case DRM_FORMAT_XBGR1555:
85 	case DRM_FORMAT_RGBX5551:
86 	case DRM_FORMAT_BGRX5551:
87 	case DRM_FORMAT_ARGB1555:
88 	case DRM_FORMAT_ABGR1555:
89 	case DRM_FORMAT_RGBA5551:
90 	case DRM_FORMAT_BGRA5551:
91 		*depth = 15;
92 		*bpp = 16;
93 		break;
94 	case DRM_FORMAT_RGB565:
95 	case DRM_FORMAT_BGR565:
96 		*depth = 16;
97 		*bpp = 16;
98 		break;
99 	case DRM_FORMAT_RGB888:
100 	case DRM_FORMAT_BGR888:
101 		*depth = 24;
102 		*bpp = 24;
103 		break;
104 	case DRM_FORMAT_XRGB8888:
105 	case DRM_FORMAT_XBGR8888:
106 	case DRM_FORMAT_RGBX8888:
107 	case DRM_FORMAT_BGRX8888:
108 		*depth = 24;
109 		*bpp = 32;
110 		break;
111 	case DRM_FORMAT_XRGB2101010:
112 	case DRM_FORMAT_XBGR2101010:
113 	case DRM_FORMAT_RGBX1010102:
114 	case DRM_FORMAT_BGRX1010102:
115 	case DRM_FORMAT_ARGB2101010:
116 	case DRM_FORMAT_ABGR2101010:
117 	case DRM_FORMAT_RGBA1010102:
118 	case DRM_FORMAT_BGRA1010102:
119 		*depth = 30;
120 		*bpp = 32;
121 		break;
122 	case DRM_FORMAT_ARGB8888:
123 	case DRM_FORMAT_ABGR8888:
124 	case DRM_FORMAT_RGBA8888:
125 	case DRM_FORMAT_BGRA8888:
126 		*depth = 32;
127 		*bpp = 32;
128 		break;
129 	default:
130 		DRM_DEBUG_KMS("unsupported pixel format %s\n",
131 			      drm_get_format_name(format));
132 		*depth = 0;
133 		*bpp = 0;
134 		break;
135 	}
136 }
137 EXPORT_SYMBOL(drm_fb_get_bpp_depth);
138 
139 /**
140  * drm_format_num_planes - get the number of planes for format
141  * @format: pixel format (DRM_FORMAT_*)
142  *
143  * Returns:
144  * The number of planes used by the specified pixel format.
145  */
146 int drm_format_num_planes(uint32_t format)
147 {
148 	switch (format) {
149 	case DRM_FORMAT_YUV410:
150 	case DRM_FORMAT_YVU410:
151 	case DRM_FORMAT_YUV411:
152 	case DRM_FORMAT_YVU411:
153 	case DRM_FORMAT_YUV420:
154 	case DRM_FORMAT_YVU420:
155 	case DRM_FORMAT_YUV422:
156 	case DRM_FORMAT_YVU422:
157 	case DRM_FORMAT_YUV444:
158 	case DRM_FORMAT_YVU444:
159 		return 3;
160 	case DRM_FORMAT_NV12:
161 	case DRM_FORMAT_NV21:
162 	case DRM_FORMAT_NV16:
163 	case DRM_FORMAT_NV61:
164 	case DRM_FORMAT_NV24:
165 	case DRM_FORMAT_NV42:
166 		return 2;
167 	default:
168 		return 1;
169 	}
170 }
171 EXPORT_SYMBOL(drm_format_num_planes);
172 
173 /**
174  * drm_format_plane_cpp - determine the bytes per pixel value
175  * @format: pixel format (DRM_FORMAT_*)
176  * @plane: plane index
177  *
178  * Returns:
179  * The bytes per pixel value for the specified plane.
180  */
181 int drm_format_plane_cpp(uint32_t format, int plane)
182 {
183 	unsigned int depth;
184 	int bpp;
185 
186 	if (plane >= drm_format_num_planes(format))
187 		return 0;
188 
189 	switch (format) {
190 	case DRM_FORMAT_YUYV:
191 	case DRM_FORMAT_YVYU:
192 	case DRM_FORMAT_UYVY:
193 	case DRM_FORMAT_VYUY:
194 		return 2;
195 	case DRM_FORMAT_NV12:
196 	case DRM_FORMAT_NV21:
197 	case DRM_FORMAT_NV16:
198 	case DRM_FORMAT_NV61:
199 	case DRM_FORMAT_NV24:
200 	case DRM_FORMAT_NV42:
201 		return plane ? 2 : 1;
202 	case DRM_FORMAT_YUV410:
203 	case DRM_FORMAT_YVU410:
204 	case DRM_FORMAT_YUV411:
205 	case DRM_FORMAT_YVU411:
206 	case DRM_FORMAT_YUV420:
207 	case DRM_FORMAT_YVU420:
208 	case DRM_FORMAT_YUV422:
209 	case DRM_FORMAT_YVU422:
210 	case DRM_FORMAT_YUV444:
211 	case DRM_FORMAT_YVU444:
212 		return 1;
213 	default:
214 		drm_fb_get_bpp_depth(format, &depth, &bpp);
215 		return bpp >> 3;
216 	}
217 }
218 EXPORT_SYMBOL(drm_format_plane_cpp);
219 
220 /**
221  * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor
222  * @format: pixel format (DRM_FORMAT_*)
223  *
224  * Returns:
225  * The horizontal chroma subsampling factor for the
226  * specified pixel format.
227  */
228 int drm_format_horz_chroma_subsampling(uint32_t format)
229 {
230 	switch (format) {
231 	case DRM_FORMAT_YUV411:
232 	case DRM_FORMAT_YVU411:
233 	case DRM_FORMAT_YUV410:
234 	case DRM_FORMAT_YVU410:
235 		return 4;
236 	case DRM_FORMAT_YUYV:
237 	case DRM_FORMAT_YVYU:
238 	case DRM_FORMAT_UYVY:
239 	case DRM_FORMAT_VYUY:
240 	case DRM_FORMAT_NV12:
241 	case DRM_FORMAT_NV21:
242 	case DRM_FORMAT_NV16:
243 	case DRM_FORMAT_NV61:
244 	case DRM_FORMAT_YUV422:
245 	case DRM_FORMAT_YVU422:
246 	case DRM_FORMAT_YUV420:
247 	case DRM_FORMAT_YVU420:
248 		return 2;
249 	default:
250 		return 1;
251 	}
252 }
253 EXPORT_SYMBOL(drm_format_horz_chroma_subsampling);
254 
255 /**
256  * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor
257  * @format: pixel format (DRM_FORMAT_*)
258  *
259  * Returns:
260  * The vertical chroma subsampling factor for the
261  * specified pixel format.
262  */
263 int drm_format_vert_chroma_subsampling(uint32_t format)
264 {
265 	switch (format) {
266 	case DRM_FORMAT_YUV410:
267 	case DRM_FORMAT_YVU410:
268 		return 4;
269 	case DRM_FORMAT_YUV420:
270 	case DRM_FORMAT_YVU420:
271 	case DRM_FORMAT_NV12:
272 	case DRM_FORMAT_NV21:
273 		return 2;
274 	default:
275 		return 1;
276 	}
277 }
278 EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
279 
280 /**
281  * drm_format_plane_width - width of the plane given the first plane
282  * @width: width of the first plane
283  * @format: pixel format
284  * @plane: plane index
285  *
286  * Returns:
287  * The width of @plane, given that the width of the first plane is @width.
288  */
289 int drm_format_plane_width(int width, uint32_t format, int plane)
290 {
291 	if (plane >= drm_format_num_planes(format))
292 		return 0;
293 
294 	if (plane == 0)
295 		return width;
296 
297 	return width / drm_format_horz_chroma_subsampling(format);
298 }
299 EXPORT_SYMBOL(drm_format_plane_width);
300 
301 /**
302  * drm_format_plane_height - height of the plane given the first plane
303  * @height: height of the first plane
304  * @format: pixel format
305  * @plane: plane index
306  *
307  * Returns:
308  * The height of @plane, given that the height of the first plane is @height.
309  */
310 int drm_format_plane_height(int height, uint32_t format, int plane)
311 {
312 	if (plane >= drm_format_num_planes(format))
313 		return 0;
314 
315 	if (plane == 0)
316 		return height;
317 
318 	return height / drm_format_vert_chroma_subsampling(format);
319 }
320 EXPORT_SYMBOL(drm_format_plane_height);
321