File Index
Files and directories
Sign in
FILE

vkms_formats.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/vkms/vkms_formats.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2
  3#include <linux/kernel.h>
  4#include <linux/minmax.h>
  5
  6#include <drm/drm_blend.h>
  7#include <drm/drm_rect.h>
  8#include <drm/drm_fixed.h>
  9
 10#include <kunit/visibility.h>
 11
 12#include "vkms_formats.h"
 13
 14/**
 15 * packed_pixels_offset() - Get the offset of the block containing the pixel at coordinates x/y
 16 *
 17 * @frame_info: Buffer metadata
 18 * @x: The x coordinate of the wanted pixel in the buffer
 19 * @y: The y coordinate of the wanted pixel in the buffer
 20 * @plane_index: The index of the plane to use
 21 * @offset: The returned offset inside the buffer of the block
 22 * @rem_x: The returned X coordinate of the requested pixel in the block
 23 * @rem_y: The returned Y coordinate of the requested pixel in the block
 24 *
 25 * As some pixel formats store multiple pixels in a block (DRM_FORMAT_R* for example), some
 26 * pixels are not individually addressable. This function return 3 values: the offset of the
 27 * whole block, and the coordinate of the requested pixel inside this block.
 28 * For example, if the format is DRM_FORMAT_R1 and the requested coordinate is 13,5, the offset
 29 * will point to the byte 5*pitches + 13/8 (second byte of the 5th line), and the rem_x/rem_y
 30 * coordinates will be (13 % 8, 5 % 1) = (5, 0)
 31 *
 32 * With this function, the caller just have to extract the correct pixel from the block.
 33 */
 34static void packed_pixels_offset(const struct vkms_frame_info *frame_info, int x, int y,
 35				 int plane_index, int *offset, int *rem_x, int *rem_y)
 36{
 37	struct drm_framebuffer *fb = frame_info->fb;
 38	const struct drm_format_info *format = frame_info->fb->format;
 39	/* Directly using x and y to multiply pitches and format->ccp is not sufficient because
 40	 * in some formats a block can represent multiple pixels.
 41	 *
 42	 * Dividing x and y by the block size allows to extract the correct offset of the block
 43	 * containing the pixel.
 44	 */
 45
 46	int block_x = x / drm_format_info_block_width(format, plane_index);
 47	int block_y = y / drm_format_info_block_height(format, plane_index);
 48	int block_pitch = fb->pitches[plane_index] * drm_format_info_block_height(format,
 49										  plane_index);
 50	*rem_x = x % drm_format_info_block_width(format, plane_index);
 51	*rem_y = y % drm_format_info_block_height(format, plane_index);
 52	*offset = fb->offsets[plane_index] +
 53		  block_y * block_pitch +
 54		  block_x * format->char_per_block[plane_index];
 55}
 56
 57/**
 58 * packed_pixels_addr() - Get the pointer to the block containing the pixel at the given
 59 * coordinates
 60 *
 61 * @frame_info: Buffer metadata
 62 * @x: The x (width) coordinate inside the plane
 63 * @y: The y (height) coordinate inside the plane
 64 * @plane_index: The index of the plane
 65 * @addr: The returned pointer
 66 * @rem_x: The returned X coordinate of the requested pixel in the block
 67 * @rem_y: The returned Y coordinate of the requested pixel in the block
 68 *
 69 * Takes the information stored in the frame_info, a pair of coordinates, and returns the address
 70 * of the block containing this pixel and the pixel position inside this block.
 71 *
 72 * See @packed_pixels_offset for details about rem_x/rem_y behavior.
 73 */
 74static void packed_pixels_addr(const struct vkms_frame_info *frame_info,
 75			       int x, int y, int plane_index, u8 **addr, int *rem_x,
 76			       int *rem_y)
 77{
 78	int offset;
 79
 80	packed_pixels_offset(frame_info, x, y, plane_index, &offset, rem_x, rem_y);
 81	*addr = (u8 *)frame_info->map[0].vaddr + offset;
 82}
 83
 84/**
 85 * get_block_step_bytes() - Common helper to compute the correct step value between each pixel block
 86 * to read in a certain direction.
 87 *
 88 * @fb: Framebuffer to iter on
 89 * @direction: Direction of the reading
 90 * @plane_index: Plane to get the step from
 91 *
 92 * As the returned count is the number of bytes between two consecutive blocks in a direction,
 93 * the caller may have to read multiple pixels before using the next one (for example, to read from
 94 * left to right in a DRM_FORMAT_R1 plane, each block contains 8 pixels, so the step must be used
 95 * only every 8 pixels).
 96 */
 97static int get_block_step_bytes(struct drm_framebuffer *fb, enum pixel_read_direction direction,
 98				int plane_index)
 99{
100	switch (direction) {
101	case READ_LEFT_TO_RIGHT:
102		return fb->format->char_per_block[plane_index];
103	case READ_RIGHT_TO_LEFT:
104		return -fb->format->char_per_block[plane_index];
105	case READ_TOP_TO_BOTTOM:
106		return (int)fb->pitches[plane_index] * drm_format_info_block_width(fb->format,
107										   plane_index);
108	case READ_BOTTOM_TO_TOP:
109		return -(int)fb->pitches[plane_index] * drm_format_info_block_width(fb->format,
110										    plane_index);
111	}
112
113	return 0;
114}
115
116/**
117 * packed_pixels_addr_1x1() - Get the pointer to the block containing the pixel at the given
118 * coordinates
119 *
120 * @frame_info: Buffer metadata
121 * @x: The x (width) coordinate inside the plane
122 * @y: The y (height) coordinate inside the plane
123 * @plane_index: The index of the plane
124 * @addr: The returned pointer
125 *
126 * This function can only be used with format where block_h == block_w == 1.
127 */
128static void packed_pixels_addr_1x1(const struct vkms_frame_info *frame_info,
129				   int x, int y, int plane_index, u8 **addr)
130{
131	int offset, rem_x, rem_y;
132
133	WARN_ONCE(drm_format_info_block_width(frame_info->fb->format,
134					      plane_index) != 1,
135		"%s() only support formats with block_w == 1", __func__);
136	WARN_ONCE(drm_format_info_block_height(frame_info->fb->format,
137					       plane_index) != 1,
138		"%s() only support formats with block_h == 1", __func__);
139
140	packed_pixels_offset(frame_info, x, y, plane_index, &offset, &rem_x,
141			     &rem_y);
142	*addr = (u8 *)frame_info->map[0].vaddr + offset;
143}
144
145/**
146 * get_subsampling() - Get the subsampling divisor value on a specific direction
147 *
148 * @format: format to extarct the subsampling from
149 * @direction: direction of the subsampling requested
150 */
151static int get_subsampling(const struct drm_format_info *format,
152			   enum pixel_read_direction direction)
153{
154	switch (direction) {
155	case READ_BOTTOM_TO_TOP:
156	case READ_TOP_TO_BOTTOM:
157		return format->vsub;
158	case READ_RIGHT_TO_LEFT:
159	case READ_LEFT_TO_RIGHT:
160		return format->hsub;
161	}
162	WARN_ONCE(true, "Invalid direction for pixel reading: %d\n", direction);
163	return 1;
164}
165
166/**
167 * get_subsampling_offset() - An offset for keeping the chroma siting consistent regardless of
168 * x_start and y_start values
169 *
170 * @direction: direction of the reading to properly compute this offset
171 * @x_start: x coordinate of the starting point of the readed line
172 * @y_start: y coordinate of the starting point of the readed line
173 */
174static int get_subsampling_offset(enum pixel_read_direction direction, int x_start, int y_start)
175{
176	switch (direction) {
177	case READ_BOTTOM_TO_TOP:
178		return -y_start - 1;
179	case READ_TOP_TO_BOTTOM:
180		return y_start;
181	case READ_RIGHT_TO_LEFT:
182		return -x_start - 1;
183	case READ_LEFT_TO_RIGHT:
184		return x_start;
185	}
186	WARN_ONCE(true, "Invalid direction for pixel reading: %d\n", direction);
187	return 0;
188}
189
190/*
191 * The following functions take pixel data (a, r, g, b, pixel, ...) and convert them to
192 * &struct pixel_argb_u16
193 *
194 * They are used in the `read_line`s functions to avoid duplicate work for some pixel formats.
195 */
196
197static struct pixel_argb_u16 argb_u16_from_u8888(u8 a, u8 r, u8 g, u8 b)
198{
199	struct pixel_argb_u16 out_pixel;
200	/*
201	 * The 257 is the "conversion ratio". This number is obtained by the
202	 * (2^16 - 1) / (2^8 - 1) division. Which, in this case, tries to get
203	 * the best color value in a pixel format with more possibilities.
204	 * A similar idea applies to others RGB color conversions.
205	 */
206	out_pixel.a = (u16)a * 257;
207	out_pixel.r = (u16)r * 257;
208	out_pixel.g = (u16)g * 257;
209	out_pixel.b = (u16)b * 257;
210
211	return out_pixel;
212}
213
214static struct pixel_argb_u16 argb_u16_from_u16161616(u16 a, u16 r, u16 g, u16 b)
215{
216	struct pixel_argb_u16 out_pixel;
217
218	out_pixel.a = a;
219	out_pixel.r = r;
220	out_pixel.g = g;
221	out_pixel.b = b;
222
223	return out_pixel;
224}
225
226static struct pixel_argb_u16 argb_u16_from_le16161616(__le16 a, __le16 r, __le16 g, __le16 b)
227{
228	return argb_u16_from_u16161616(le16_to_cpu(a), le16_to_cpu(r), le16_to_cpu(g),
229				       le16_to_cpu(b));
230}
231
232static struct pixel_argb_u16 argb_u16_from_RGB565(const __le16 *pixel)
233{
234	struct pixel_argb_u16 out_pixel;
235
236	s64 fp_rb_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(31));
237	s64 fp_g_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(63));
238
239	u16 rgb_565 = le16_to_cpu(*pixel);
240	s64 fp_r = drm_int2fixp((rgb_565 >> 11) & 0x1f);
241	s64 fp_g = drm_int2fixp((rgb_565 >> 5) & 0x3f);
242	s64 fp_b = drm_int2fixp(rgb_565 & 0x1f);
243
244	out_pixel.a = (u16)0xffff;
245	out_pixel.r = drm_fixp2int_round(drm_fixp_mul(fp_r, fp_rb_ratio));
246	out_pixel.g = drm_fixp2int_round(drm_fixp_mul(fp_g, fp_g_ratio));
247	out_pixel.b = drm_fixp2int_round(drm_fixp_mul(fp_b, fp_rb_ratio));
248
249	return out_pixel;
250}
251
252static struct pixel_argb_u16 argb_u16_from_gray8(u8 gray)
253{
254	return argb_u16_from_u8888(255, gray, gray, gray);
255}
256
257static struct pixel_argb_u16 argb_u16_from_grayu16(u16 gray)
258{
259	return argb_u16_from_u16161616(0xFFFF, gray, gray, gray);
260}
261
262static struct pixel_argb_u16 argb_u16_from_BGR565(const __le16 *pixel)
263{
264	struct pixel_argb_u16 out_pixel;
265
266	out_pixel = argb_u16_from_RGB565(pixel);
267	swap(out_pixel.r, out_pixel.b);
268
269	return out_pixel;
270}
271
272VISIBLE_IF_KUNIT
273struct pixel_argb_u16 argb_u16_from_yuv161616(const struct conversion_matrix *matrix,
274					      u16 y, u16 channel_1, u16 channel_2)
275{
276	u16 r, g, b;
277	s64 fp_y, fp_channel_1, fp_channel_2;
278	s64 fp_r, fp_g, fp_b;
279
280	fp_y = drm_int2fixp((int)y - matrix->y_offset * 257);
281	fp_channel_1 = drm_int2fixp((int)channel_1 - 128 * 257);
282	fp_channel_2 = drm_int2fixp((int)channel_2 - 128 * 257);
283
284	fp_r = drm_fixp_mul(matrix->matrix[0][0], fp_y) +
285	       drm_fixp_mul(matrix->matrix[0][1], fp_channel_1) +
286	       drm_fixp_mul(matrix->matrix[0][2], fp_channel_2);
287	fp_g = drm_fixp_mul(matrix->matrix[1][0], fp_y) +
288	       drm_fixp_mul(matrix->matrix[1][1], fp_channel_1) +
289	       drm_fixp_mul(matrix->matrix[1][2], fp_channel_2);
290	fp_b = drm_fixp_mul(matrix->matrix[2][0], fp_y) +
291	       drm_fixp_mul(matrix->matrix[2][1], fp_channel_1) +
292	       drm_fixp_mul(matrix->matrix[2][2], fp_channel_2);
293
294	fp_r = drm_fixp2int_round(fp_r);
295	fp_g = drm_fixp2int_round(fp_g);
296	fp_b = drm_fixp2int_round(fp_b);
297
298	r = clamp(fp_r, 0, 0xffff);
299	g = clamp(fp_g, 0, 0xffff);
300	b = clamp(fp_b, 0, 0xffff);
301
302	return argb_u16_from_u16161616(0xffff, r, g, b);
303}
304EXPORT_SYMBOL_IF_KUNIT(argb_u16_from_yuv161616);
305
306/**
307 * READ_LINE() - Generic generator for a read_line function which can be used for format with one
308 * plane and a block_h == block_w == 1.
309 *
310 * @function_name: Function name to generate
311 * @pixel_name: Temporary pixel name used in the @__VA_ARGS__ parameters
312 * @pixel_type: Used to specify the type you want to cast the pixel pointer
313 * @callback: Callback to call for each pixels. This fonction should take @__VA_ARGS__ as parameter
314 *            and return a pixel_argb_u16
315 * __VA_ARGS__: Argument to pass inside the callback. You can use @pixel_name to access current
316 *  pixel.
317 */
318#define READ_LINE(function_name, pixel_name, pixel_type, callback, ...)				\
319static void function_name(const struct vkms_plane_state *plane, int x_start,			\
320			      int y_start, enum pixel_read_direction direction, int count,	\
321			      struct pixel_argb_u16 out_pixel[])				\
322{												\
323	struct pixel_argb_u16 *end = out_pixel + count;						\
324	int step = get_block_step_bytes(plane->frame_info->fb, direction, 0);			\
325	u8 *src_pixels;										\
326												\
327	packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels);		\
328												\
329	while (out_pixel < end) {								\
330		pixel_type *(pixel_name) = (pixel_type *)src_pixels;				\
331		*out_pixel = (callback)(__VA_ARGS__);						\
332		out_pixel += 1;									\
333		src_pixels += step;								\
334	}											\
335}
336
337/**
338 * READ_LINE_ARGB8888() - Generic generator for ARGB8888 formats.
339 * The pixel type used is u8, so pixel_name[0]..pixel_name[n] are the n components of the pixel.
340 *
341 * @function_name: Function name to generate
342 * @pixel_name: temporary pixel to use in @a, @r, @g and @b parameters
343 * @a: alpha value
344 * @r: red value
345 * @g: green value
346 * @b: blue value
347 */
348#define READ_LINE_ARGB8888(function_name, pixel_name, a, r, g, b) \
349	READ_LINE(function_name, pixel_name, u8, argb_u16_from_u8888, a, r, g, b)
350/**
351 * READ_LINE_le16161616() - Generic generator for ARGB16161616 formats.
352 * The pixel type used is u16, so pixel_name[0]..pixel_name[n] are the n components of the pixel.
353 *
354 * @function_name: Function name to generate
355 * @pixel_name: temporary pixel to use in @a, @r, @g and @b parameters
356 * @a: alpha value
357 * @r: red value
358 * @g: green value
359 * @b: blue value
360 */
361#define READ_LINE_le16161616(function_name, pixel_name, a, r, g, b) \
362	READ_LINE(function_name, pixel_name, __le16, argb_u16_from_le16161616, a, r, g, b)
363
364/*
365 * The following functions are read_line function for each pixel format supported by VKMS.
366 *
367 * They read a line starting at the point @x_start,@y_start following the @direction. The result
368 * is stored in @out_pixel and in a 64 bits format, see struct pixel_argb_u16.
369 *
370 * These functions are very repetitive, but the innermost pixel loops must be kept inside these
371 * functions for performance reasons. Some benchmarking was done in [1] where having the innermost
372 * loop factored out of these functions showed a slowdown by a factor of three.
373 *
374 * [1]: https://lore.kernel.org/dri-devel/d258c8dc-78e9-4509-9037-a98f7f33b3a3@riseup.net/
375 */
376
377static void Rx_read_line(const struct vkms_plane_state *plane, int x_start,
378			 int y_start, enum pixel_read_direction direction, int count,
379			 struct pixel_argb_u16 out_pixel[])
380{
381	struct pixel_argb_u16 *end = out_pixel + count;
382	int bits_per_pixel = drm_format_info_bpp(plane->frame_info->fb->format, 0);
383	u8 *src_pixels;
384	int rem_x, rem_y;
385
386	WARN_ONCE(drm_format_info_block_height(plane->frame_info->fb->format, 0) != 1,
387		  "%s() only support formats with block_h == 1", __func__);
388
389	packed_pixels_addr(plane->frame_info, x_start, y_start, 0, &src_pixels, &rem_x, &rem_y);
390	int bit_offset = (8 - bits_per_pixel) - rem_x * bits_per_pixel;
391	int step = get_block_step_bytes(plane->frame_info->fb, direction, 0);
392	int mask = (0x1 << bits_per_pixel) - 1;
393	int lum_per_level = 0xFFFF / mask;
394
395	if (direction == READ_LEFT_TO_RIGHT || direction == READ_RIGHT_TO_LEFT) {
396		int restart_bit_offset;
397		int step_bit_offset;
398
399		if (direction == READ_LEFT_TO_RIGHT) {
400			restart_bit_offset = 8 - bits_per_pixel;
401			step_bit_offset = -bits_per_pixel;
402		} else {
403			restart_bit_offset = 0;
404			step_bit_offset = bits_per_pixel;
405		}
406
407		while (out_pixel < end) {
408			u8 val = ((*src_pixels) >> bit_offset) & mask;
409
410			*out_pixel = argb_u16_from_grayu16((int)val * lum_per_level);
411
412			bit_offset += step_bit_offset;
413			if (bit_offset < 0 || 8 <= bit_offset) {
414				bit_offset = restart_bit_offset;
415				src_pixels += step;
416			}
417			out_pixel += 1;
418		}
419	} else if (direction == READ_TOP_TO_BOTTOM || direction == READ_BOTTOM_TO_TOP) {
420		while (out_pixel < end) {
421			u8 val = (*src_pixels >> bit_offset) & mask;
422			*out_pixel = argb_u16_from_grayu16((int)val * lum_per_level);
423			src_pixels += step;
424			out_pixel += 1;
425		}
426	}
427}
428
429static void R1_read_line(const struct vkms_plane_state *plane, int x_start,
430			 int y_start, enum pixel_read_direction direction, int count,
431			 struct pixel_argb_u16 out_pixel[])
432{
433	Rx_read_line(plane, x_start, y_start, direction, count, out_pixel);
434}
435
436static void R2_read_line(const struct vkms_plane_state *plane, int x_start,
437			 int y_start, enum pixel_read_direction direction, int count,
438			 struct pixel_argb_u16 out_pixel[])
439{
440	Rx_read_line(plane, x_start, y_start, direction, count, out_pixel);
441}
442
443static void R4_read_line(const struct vkms_plane_state *plane, int x_start,
444			 int y_start, enum pixel_read_direction direction, int count,
445			 struct pixel_argb_u16 out_pixel[])
446{
447	Rx_read_line(plane, x_start, y_start, direction, count, out_pixel);
448}
449
450
451READ_LINE_ARGB8888(XRGB8888_read_line, px, 0xFF, px[2], px[1], px[0])
452READ_LINE_ARGB8888(XBGR8888_read_line, px, 0xFF, px[0], px[1], px[2])
453
454READ_LINE_ARGB8888(ARGB8888_read_line, px, px[3], px[2], px[1], px[0])
455READ_LINE_ARGB8888(ABGR8888_read_line, px, px[3], px[0], px[1], px[2])
456READ_LINE_ARGB8888(RGBA8888_read_line, px, px[0], px[3], px[2], px[1])
457READ_LINE_ARGB8888(BGRA8888_read_line, px, px[0], px[1], px[2], px[3])
458
459READ_LINE_ARGB8888(RGB888_read_line, px, 0xFF, px[2], px[1], px[0])
460READ_LINE_ARGB8888(BGR888_read_line, px, 0xFF, px[0], px[1], px[2])
461
462READ_LINE_le16161616(ARGB16161616_read_line, px, px[3], px[2], px[1], px[0])
463READ_LINE_le16161616(ABGR16161616_read_line, px, px[3], px[0], px[1], px[2])
464READ_LINE_le16161616(XRGB16161616_read_line, px, cpu_to_le16(0xFFFF), px[2], px[1], px[0])
465READ_LINE_le16161616(XBGR16161616_read_line, px, cpu_to_le16(0xFFFF), px[0], px[1], px[2])
466
467READ_LINE(RGB565_read_line, px, __le16, argb_u16_from_RGB565, px)
468READ_LINE(BGR565_read_line, px, __le16, argb_u16_from_BGR565, px)
469
470READ_LINE(R8_read_line, px, u8, argb_u16_from_gray8, *px)
471
472/*
473 * This callback can be used for YUV formats where U and V values are
474 * stored in the same plane (often called semi-planar formats). It will
475 * correctly handle subsampling as described in the drm_format_info of the plane.
476 *
477 * The conversion matrix stored in the @plane is used to:
478 * - Apply the correct color range and encoding
479 * - Convert YUV and YVU with the same function (a column swap is needed when setting up
480 * plane->conversion_matrix)
481 */
482
483/**
484 * READ_LINE_YUV_SEMIPLANAR() - Generic generator for a read_line function which can be used for yuv
485 * formats with two planes and block_w == block_h == 1.
486 *
487 * @function_name: Function name to generate
488 * @pixel_1_name: temporary pixel name for the first plane used in the @__VA_ARGS__ parameters
489 * @pixel_2_name: temporary pixel name for the second plane used in the @__VA_ARGS__ parameters
490 * @pixel_1_type: Used to specify the type you want to cast the pixel pointer on the plane 1
491 * @pixel_2_type: Used to specify the type you want to cast the pixel pointer on the plane 2
492 * @callback: Callback to call for each pixels. This function should take
493 *            (struct conversion_matrix*, @__VA_ARGS__) as parameter and return a pixel_argb_u16
494 * __VA_ARGS__: Argument to pass inside the callback. You can use @pixel_1_name and @pixel_2_name
495 *               to access current pixel values
496 */
497#define READ_LINE_YUV_SEMIPLANAR(function_name, pixel_1_name, pixel_2_name, pixel_1_type,	\
498				 pixel_2_type, callback, ...)					\
499static void function_name(const struct vkms_plane_state *plane, int x_start,			\
500		 int y_start, enum pixel_read_direction direction, int count,			\
501		 struct pixel_argb_u16 out_pixel[])						\
502{												\
503	u8 *plane_1;										\
504	u8 *plane_2;										\
505												\
506	packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0,				\
507			       &plane_1);							\
508	packed_pixels_addr_1x1(plane->frame_info,						\
509			       x_start / plane->frame_info->fb->format->hsub,			\
510			       y_start / plane->frame_info->fb->format->vsub, 1,		\
511			       &plane_2);							\
512	int step_1 = get_block_step_bytes(plane->frame_info->fb, direction, 0);			\
513	int step_2 = get_block_step_bytes(plane->frame_info->fb, direction, 1);			\
514	int subsampling = get_subsampling(plane->frame_info->fb->format, direction);		\
515	int subsampling_offset = get_subsampling_offset(direction, x_start, y_start);		\
516	const struct conversion_matrix *conversion_matrix = &plane->conversion_matrix;		\
517												\
518	for (int i = 0; i < count; i++) {							\
519		pixel_1_type *(pixel_1_name) = (pixel_1_type *)plane_1;				\
520		pixel_2_type *(pixel_2_name) = (pixel_2_type *)plane_2;				\
521		*out_pixel = (callback)(conversion_matrix, __VA_ARGS__);			\
522		out_pixel += 1;									\
523		plane_1 += step_1;								\
524		if ((i + subsampling_offset + 1) % subsampling == 0)				\
525			plane_2 += step_2;							\
526	}											\
527}
528
529READ_LINE_YUV_SEMIPLANAR(YUV888_semiplanar_read_line, y, uv, u8, u8, argb_u16_from_yuv161616,
530			 y[0] * 257, uv[0] * 257, uv[1] * 257)
531READ_LINE_YUV_SEMIPLANAR(YUV161616_semiplanar_read_line, y, uv, u16, u16, argb_u16_from_yuv161616,
532			 y[0], uv[0], uv[1])
533/*
534 * This callback can be used for YUV format where each color component is
535 * stored in a different plane (often called planar formats). It will
536 * correctly handle subsampling as described in the drm_format_info of the plane.
537 *
538 * The conversion matrix stored in the @plane is used to:
539 * - Apply the correct color range and encoding
540 * - Convert YUV and YVU with the same function (a column swap is needed when setting up
541 * plane->conversion_matrix)
542 */
543static void planar_yuv_read_line(const struct vkms_plane_state *plane, int x_start,
544				 int y_start, enum pixel_read_direction direction, int count,
545				 struct pixel_argb_u16 out_pixel[])
546{
547	u8 *y_plane;
548	u8 *channel_1_plane;
549	u8 *channel_2_plane;
550
551	packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0,
552			       &y_plane);
553	packed_pixels_addr_1x1(plane->frame_info,
554			       x_start / plane->frame_info->fb->format->hsub,
555			       y_start / plane->frame_info->fb->format->vsub, 1,
556			       &channel_1_plane);
557	packed_pixels_addr_1x1(plane->frame_info,
558			       x_start / plane->frame_info->fb->format->hsub,
559			       y_start / plane->frame_info->fb->format->vsub, 2,
560			       &channel_2_plane);
561	int step_y = get_block_step_bytes(plane->frame_info->fb, direction, 0);
562	int step_channel_1 = get_block_step_bytes(plane->frame_info->fb, direction, 1);
563	int step_channel_2 = get_block_step_bytes(plane->frame_info->fb, direction, 2);
564	int subsampling = get_subsampling(plane->frame_info->fb->format, direction);
565	int subsampling_offset = get_subsampling_offset(direction, x_start, y_start);
566	const struct conversion_matrix *conversion_matrix = &plane->conversion_matrix;
567
568	for (int i = 0; i < count; i++) {
569		*out_pixel = argb_u16_from_yuv161616(conversion_matrix,
570						     *y_plane * 257, *channel_1_plane * 257,
571						     *channel_2_plane * 257);
572		out_pixel += 1;
573		y_plane += step_y;
574		if ((i + subsampling_offset + 1) % subsampling == 0) {
575			channel_1_plane += step_channel_1;
576			channel_2_plane += step_channel_2;
577		}
578	}
579}
580
581/*
582 * The following functions take one &struct pixel_argb_u16 and convert it to a specific format.
583 * The result is stored in @out_pixel.
584 *
585 * They are used in vkms_writeback_row() to convert and store a pixel from the src_buffer to
586 * the writeback buffer.
587 */
588static void argb_u16_to_ARGB8888(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel)
589{
590	/*
591	 * This sequence below is important because the format's byte order is
592	 * in little-endian. In the case of the ARGB8888 the memory is
593	 * organized this way:
594	 *
595	 * | Addr     | = blue channel
596	 * | Addr + 1 | = green channel
597	 * | Addr + 2 | = Red channel
598	 * | Addr + 3 | = Alpha channel
599	 */
600	out_pixel[3] = DIV_ROUND_CLOSEST(in_pixel->a, 257);
601	out_pixel[2] = DIV_ROUND_CLOSEST(in_pixel->r, 257);
602	out_pixel[1] = DIV_ROUND_CLOSEST(in_pixel->g, 257);
603	out_pixel[0] = DIV_ROUND_CLOSEST(in_pixel->b, 257);
604}
605
606static void argb_u16_to_XRGB8888(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel)
607{
608	out_pixel[3] = 0xff;
609	out_pixel[2] = DIV_ROUND_CLOSEST(in_pixel->r, 257);
610	out_pixel[1] = DIV_ROUND_CLOSEST(in_pixel->g, 257);
611	out_pixel[0] = DIV_ROUND_CLOSEST(in_pixel->b, 257);
612}
613
614static void argb_u16_to_ABGR8888(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel)
615{
616	out_pixel[3] = DIV_ROUND_CLOSEST(in_pixel->a, 257);
617	out_pixel[2] = DIV_ROUND_CLOSEST(in_pixel->b, 257);
618	out_pixel[1] = DIV_ROUND_CLOSEST(in_pixel->g, 257);
619	out_pixel[0] = DIV_ROUND_CLOSEST(in_pixel->r, 257);
620}
621
622static void argb_u16_to_ARGB16161616(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel)
623{
624	__le16 *pixel = (__le16 *)out_pixel;
625
626	pixel[3] = cpu_to_le16(in_pixel->a);
627	pixel[2] = cpu_to_le16(in_pixel->r);
628	pixel[1] = cpu_to_le16(in_pixel->g);
629	pixel[0] = cpu_to_le16(in_pixel->b);
630}
631
632static void argb_u16_to_XRGB16161616(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel)
633{
634	__le16 *pixel = (__le16 *)out_pixel;
635
636	pixel[3] = cpu_to_le16(0xffff);
637	pixel[2] = cpu_to_le16(in_pixel->r);
638	pixel[1] = cpu_to_le16(in_pixel->g);
639	pixel[0] = cpu_to_le16(in_pixel->b);
640}
641
642static void argb_u16_to_RGB565(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel)
643{
644	__le16 *pixel = (__le16 *)out_pixel;
645
646	s64 fp_rb_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(31));
647	s64 fp_g_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(63));
648
649	s64 fp_r = drm_int2fixp(in_pixel->r);
650	s64 fp_g = drm_int2fixp(in_pixel->g);
651	s64 fp_b = drm_int2fixp(in_pixel->b);
652
653	u16 r = drm_fixp2int(drm_fixp_div(fp_r, fp_rb_ratio));
654	u16 g = drm_fixp2int(drm_fixp_div(fp_g, fp_g_ratio));
655	u16 b = drm_fixp2int(drm_fixp_div(fp_b, fp_rb_ratio));
656
657	*pixel = cpu_to_le16(r << 11 | g << 5 | b);
658}
659
660/**
661 * vkms_writeback_row() - Generic loop for all supported writeback format. It is executed just
662 * after the blending to write a line in the writeback buffer.
663 *
664 * @wb: Job where to insert the final image
665 * @src_buffer: Line to write
666 * @y: Row to write in the writeback buffer
667 */
668void vkms_writeback_row(struct vkms_writeback_job *wb,
669			const struct line_buffer *src_buffer, int y)
670{
671	struct vkms_frame_info *frame_info = &wb->wb_frame_info;
672	int x_dst = frame_info->dst.x1;
673	u8 *dst_pixels;
674	int rem_x, rem_y;
675
676	packed_pixels_addr(frame_info, x_dst, y, 0, &dst_pixels, &rem_x, &rem_y);
677	struct pixel_argb_u16 *in_pixels = src_buffer->pixels;
678	int x_limit = min_t(size_t, drm_rect_width(&frame_info->dst), src_buffer->n_pixels);
679
680	for (size_t x = 0; x < x_limit; x++, dst_pixels += frame_info->fb->format->cpp[0])
681		wb->pixel_write(dst_pixels, &in_pixels[x]);
682}
683
684/**
685 * get_pixel_read_line_function() - Retrieve the correct read_line function for a specific
686 * format. The returned pointer is NULL for unsupported pixel formats. The caller must ensure that
687 * the pointer is valid before using it in a vkms_plane_state.
688 *
689 * @format: DRM_FORMAT_* value for which to obtain a conversion function (see [drm_fourcc.h])
690 */
691pixel_read_line_t get_pixel_read_line_function(u32 format)
692{
693	switch (format) {
694	case DRM_FORMAT_ARGB8888:
695		return &ARGB8888_read_line;
696	case DRM_FORMAT_ABGR8888:
697		return &ABGR8888_read_line;
698	case DRM_FORMAT_BGRA8888:
699		return &BGRA8888_read_line;
700	case DRM_FORMAT_RGBA8888:
701		return &RGBA8888_read_line;
702	case DRM_FORMAT_XRGB8888:
703		return &XRGB8888_read_line;
704	case DRM_FORMAT_XBGR8888:
705		return &XBGR8888_read_line;
706	case DRM_FORMAT_RGB888:
707		return &RGB888_read_line;
708	case DRM_FORMAT_BGR888:
709		return &BGR888_read_line;
710	case DRM_FORMAT_ARGB16161616:
711		return &ARGB16161616_read_line;
712	case DRM_FORMAT_ABGR16161616:
713		return &ABGR16161616_read_line;
714	case DRM_FORMAT_XRGB16161616:
715		return &XRGB16161616_read_line;
716	case DRM_FORMAT_XBGR16161616:
717		return &XBGR16161616_read_line;
718	case DRM_FORMAT_RGB565:
719		return &RGB565_read_line;
720	case DRM_FORMAT_BGR565:
721		return &BGR565_read_line;
722	case DRM_FORMAT_NV12:
723	case DRM_FORMAT_NV16:
724	case DRM_FORMAT_NV24:
725	case DRM_FORMAT_NV21:
726	case DRM_FORMAT_NV61:
727	case DRM_FORMAT_NV42:
728		return &YUV888_semiplanar_read_line;
729	case DRM_FORMAT_P010:
730	case DRM_FORMAT_P012:
731	case DRM_FORMAT_P016:
732		return &YUV161616_semiplanar_read_line;
733	case DRM_FORMAT_YUV420:
734	case DRM_FORMAT_YUV422:
735	case DRM_FORMAT_YUV444:
736	case DRM_FORMAT_YVU420:
737	case DRM_FORMAT_YVU422:
738	case DRM_FORMAT_YVU444:
739		return &planar_yuv_read_line;
740	case DRM_FORMAT_R1:
741		return &R1_read_line;
742	case DRM_FORMAT_R2:
743		return &R2_read_line;
744	case DRM_FORMAT_R4:
745		return &R4_read_line;
746	case DRM_FORMAT_R8:
747		return &R8_read_line;
748	default:
749		/*
750		 * This is a bug in vkms_plane_atomic_check(). All the supported
751		 * format must:
752		 * - Be listed in vkms_formats in vkms_plane.c
753		 * - Have a pixel_read callback defined here
754		 */
755		pr_err("Pixel format %p4cc is not supported by VKMS planes. This is a kernel bug, atomic check must forbid this configuration.\n",
756		       &format);
757		BUG();
758	}
759}
760
761/*
762 * Those matrices were generated using the colour python framework
763 *
764 * Below are the function calls used to generate each matrix, go to
765 * https://colour.readthedocs.io/en/develop/generated/colour.matrix_YCbCr.html
766 * for more info:
767 *
768 * numpy.around(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.601"],
769 *                                  is_legal = False,
770 *                                  bits = 8) * 2**32).astype(int)
771 */
772static const struct conversion_matrix no_operation = {
773	.matrix = {
774		{ 4294967296, 0,          0, },
775		{ 0,          4294967296, 0, },
776		{ 0,          0,          4294967296, },
777	},
778	.y_offset = 0,
779};
780
781static const struct conversion_matrix yuv_bt601_full = {
782	.matrix = {
783		{ 4294967296, 0,           6021544149 },
784		{ 4294967296, -1478054095, -3067191994 },
785		{ 4294967296, 7610682049,  0 },
786	},
787	.y_offset = 0,
788};
789
790/*
791 * numpy.around(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.601"],
792 *                                  is_legal = True,
793 *                                  bits = 8) * 2**32).astype(int)
794 */
795static const struct conversion_matrix yuv_bt601_limited = {
796	.matrix = {
797		{ 5020601039, 0,           6881764740 },
798		{ 5020601039, -1689204679, -3505362278 },
799		{ 5020601039, 8697922339,  0 },
800	},
801	.y_offset = 16,
802};
803
804/*
805 * numpy.around(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.709"],
806 *                                  is_legal = False,
807 *                                  bits = 8) * 2**32).astype(int)
808 */
809static const struct conversion_matrix yuv_bt709_full = {
810	.matrix = {
811		{ 4294967296, 0,          6763714498 },
812		{ 4294967296, -804551626, -2010578443 },
813		{ 4294967296, 7969741314, 0 },
814	},
815	.y_offset = 0,
816};
817
818/*
819 * numpy.around(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.709"],
820 *                                  is_legal = True,
821 *                                  bits = 8) * 2**32).astype(int)
822 */
823static const struct conversion_matrix yuv_bt709_limited = {
824	.matrix = {
825		{ 5020601039, 0,          7729959424 },
826		{ 5020601039, -919487572, -2297803934 },
827		{ 5020601039, 9108275786, 0 },
828	},
829	.y_offset = 16,
830};
831
832/*
833 * numpy.around(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.2020"],
834 *                                  is_legal = False,
835 *                                  bits = 8) * 2**32).astype(int)
836 */
837static const struct conversion_matrix yuv_bt2020_full = {
838	.matrix = {
839		{ 4294967296, 0,          6333358775 },
840		{ 4294967296, -706750298, -2453942994 },
841		{ 4294967296, 8080551471, 0 },
842	},
843	.y_offset = 0,
844};
845
846/*
847 * numpy.around(colour.matrix_YCbCr(K=colour.WEIGHTS_YCBCR["ITU-R BT.2020"],
848 *                                  is_legal = True,
849 *                                  bits = 8) * 2**32).astype(int)
850 */
851static const struct conversion_matrix yuv_bt2020_limited = {
852	.matrix = {
853		{ 5020601039, 0,          7238124312 },
854		{ 5020601039, -807714626, -2804506279 },
855		{ 5020601039, 9234915964, 0 },
856	},
857	.y_offset = 16,
858};
859
860/**
861 * swap_uv_columns() - Swap u and v column of a given matrix
862 *
863 * @matrix: Matrix in which column are swapped
864 */
865static void swap_uv_columns(struct conversion_matrix *matrix)
866{
867	swap(matrix->matrix[0][2], matrix->matrix[0][1]);
868	swap(matrix->matrix[1][2], matrix->matrix[1][1]);
869	swap(matrix->matrix[2][2], matrix->matrix[2][1]);
870}
871
872/**
873 * get_conversion_matrix_to_argb_u16() - Retrieve the correct yuv to rgb conversion matrix for a
874 * given encoding and range.
875 *
876 * @format: DRM_FORMAT_* value for which to obtain a conversion function (see [drm_fourcc.h])
877 * @encoding: DRM_COLOR_* value for which to obtain a conversion matrix
878 * @range: DRM_COLOR_*_RANGE value for which to obtain a conversion matrix
879 * @matrix: Pointer to store the value into
880 */
881void get_conversion_matrix_to_argb_u16(u32 format,
882				       enum drm_color_encoding encoding,
883				       enum drm_color_range range,
884				       struct conversion_matrix *matrix)
885{
886	const struct conversion_matrix *matrix_to_copy;
887	bool limited_range;
888
889	switch (range) {
890	case DRM_COLOR_YCBCR_LIMITED_RANGE:
891		limited_range = true;
892		break;
893	case DRM_COLOR_YCBCR_FULL_RANGE:
894		limited_range = false;
895		break;
896	case DRM_COLOR_RANGE_MAX:
897		limited_range = false;
898		WARN_ONCE(true, "The requested range is not supported.");
899		break;
900	}
901
902	switch (encoding) {
903	case DRM_COLOR_YCBCR_BT601:
904		matrix_to_copy = limited_range ? &yuv_bt601_limited :
905						 &yuv_bt601_full;
906		break;
907	case DRM_COLOR_YCBCR_BT709:
908		matrix_to_copy = limited_range ? &yuv_bt709_limited :
909						 &yuv_bt709_full;
910		break;
911	case DRM_COLOR_YCBCR_BT2020:
912		matrix_to_copy = limited_range ? &yuv_bt2020_limited :
913						 &yuv_bt2020_full;
914		break;
915	case DRM_COLOR_ENCODING_MAX:
916		matrix_to_copy = &no_operation;
917		WARN_ONCE(true, "The requested encoding is not supported.");
918		break;
919	}
920
921	memcpy(matrix, matrix_to_copy, sizeof(*matrix_to_copy));
922
923	switch (format) {
924	case DRM_FORMAT_YVU420:
925	case DRM_FORMAT_YVU422:
926	case DRM_FORMAT_YVU444:
927	case DRM_FORMAT_NV21:
928	case DRM_FORMAT_NV61:
929	case DRM_FORMAT_NV42:
930		swap_uv_columns(matrix);
931		break;
932	default:
933		break;
934	}
935}
936EXPORT_SYMBOL(get_conversion_matrix_to_argb_u16);
937
938/**
939 * get_pixel_write_function() - Retrieve the correct write_pixel function for a specific format.
940 * The returned pointer is NULL for unsupported pixel formats. The caller must ensure that the
941 * pointer is valid before using it in a vkms_writeback_job.
942 *
943 * @format: DRM_FORMAT_* value for which to obtain a conversion function (see [drm_fourcc.h])
944 */
945pixel_write_t get_pixel_write_function(u32 format)
946{
947	switch (format) {
948	case DRM_FORMAT_ARGB8888:
949		return &argb_u16_to_ARGB8888;
950	case DRM_FORMAT_XRGB8888:
951		return &argb_u16_to_XRGB8888;
952	case DRM_FORMAT_ABGR8888:
953		return &argb_u16_to_ABGR8888;
954	case DRM_FORMAT_ARGB16161616:
955		return &argb_u16_to_ARGB16161616;
956	case DRM_FORMAT_XRGB16161616:
957		return &argb_u16_to_XRGB16161616;
958	case DRM_FORMAT_RGB565:
959		return &argb_u16_to_RGB565;
960	default:
961		/*
962		 * This is a bug in vkms_writeback_atomic_check. All the supported
963		 * format must:
964		 * - Be listed in vkms_wb_formats in vkms_writeback.c
965		 * - Have a pixel_write callback defined here
966		 */
967		pr_err("Pixel format %p4cc is not supported by VKMS writeback. This is a kernel bug, atomic check must forbid this configuration.\n",
968		       &format);
969		BUG();
970	}
971}
~/ Read-only file preview.