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 "vkms_formats.h" 11 12 /** 13 * packed_pixels_offset() - Get the offset of the block containing the pixel at coordinates x/y 14 * 15 * @frame_info: Buffer metadata 16 * @x: The x coordinate of the wanted pixel in the buffer 17 * @y: The y coordinate of the wanted pixel in the buffer 18 * @plane_index: The index of the plane to use 19 * @offset: The returned offset inside the buffer of the block 20 * @rem_x: The returned X coordinate of the requested pixel in the block 21 * @rem_y: The returned Y coordinate of the requested pixel in the block 22 * 23 * As some pixel formats store multiple pixels in a block (DRM_FORMAT_R* for example), some 24 * pixels are not individually addressable. This function return 3 values: the offset of the 25 * whole block, and the coordinate of the requested pixel inside this block. 26 * For example, if the format is DRM_FORMAT_R1 and the requested coordinate is 13,5, the offset 27 * will point to the byte 5*pitches + 13/8 (second byte of the 5th line), and the rem_x/rem_y 28 * coordinates will be (13 % 8, 5 % 1) = (5, 0) 29 * 30 * With this function, the caller just have to extract the correct pixel from the block. 31 */ 32 static void packed_pixels_offset(const struct vkms_frame_info *frame_info, int x, int y, 33 int plane_index, int *offset, int *rem_x, int *rem_y) 34 { 35 struct drm_framebuffer *fb = frame_info->fb; 36 const struct drm_format_info *format = frame_info->fb->format; 37 /* Directly using x and y to multiply pitches and format->ccp is not sufficient because 38 * in some formats a block can represent multiple pixels. 39 * 40 * Dividing x and y by the block size allows to extract the correct offset of the block 41 * containing the pixel. 42 */ 43 44 int block_x = x / drm_format_info_block_width(format, plane_index); 45 int block_y = y / drm_format_info_block_height(format, plane_index); 46 int block_pitch = fb->pitches[plane_index] * drm_format_info_block_height(format, 47 plane_index); 48 *rem_x = x % drm_format_info_block_width(format, plane_index); 49 *rem_y = y % drm_format_info_block_height(format, plane_index); 50 *offset = fb->offsets[plane_index] + 51 block_y * block_pitch + 52 block_x * format->char_per_block[plane_index]; 53 } 54 55 /** 56 * packed_pixels_addr() - Get the pointer to the block containing the pixel at the given 57 * coordinates 58 * 59 * @frame_info: Buffer metadata 60 * @x: The x (width) coordinate inside the plane 61 * @y: The y (height) coordinate inside the plane 62 * @plane_index: The index of the plane 63 * @addr: The returned pointer 64 * @rem_x: The returned X coordinate of the requested pixel in the block 65 * @rem_y: The returned Y coordinate of the requested pixel in the block 66 * 67 * Takes the information stored in the frame_info, a pair of coordinates, and returns the address 68 * of the block containing this pixel and the pixel position inside this block. 69 * 70 * See @packed_pixels_offset for details about rem_x/rem_y behavior. 71 */ 72 static void packed_pixels_addr(const struct vkms_frame_info *frame_info, 73 int x, int y, int plane_index, u8 **addr, int *rem_x, 74 int *rem_y) 75 { 76 int offset; 77 78 packed_pixels_offset(frame_info, x, y, plane_index, &offset, rem_x, rem_y); 79 *addr = (u8 *)frame_info->map[0].vaddr + offset; 80 } 81 82 /** 83 * get_block_step_bytes() - Common helper to compute the correct step value between each pixel block 84 * to read in a certain direction. 85 * 86 * @fb: Framebuffer to iter on 87 * @direction: Direction of the reading 88 * @plane_index: Plane to get the step from 89 * 90 * As the returned count is the number of bytes between two consecutive blocks in a direction, 91 * the caller may have to read multiple pixels before using the next one (for example, to read from 92 * left to right in a DRM_FORMAT_R1 plane, each block contains 8 pixels, so the step must be used 93 * only every 8 pixels). 94 */ 95 static int get_block_step_bytes(struct drm_framebuffer *fb, enum pixel_read_direction direction, 96 int plane_index) 97 { 98 switch (direction) { 99 case READ_LEFT_TO_RIGHT: 100 return fb->format->char_per_block[plane_index]; 101 case READ_RIGHT_TO_LEFT: 102 return -fb->format->char_per_block[plane_index]; 103 case READ_TOP_TO_BOTTOM: 104 return (int)fb->pitches[plane_index] * drm_format_info_block_width(fb->format, 105 plane_index); 106 case READ_BOTTOM_TO_TOP: 107 return -(int)fb->pitches[plane_index] * drm_format_info_block_width(fb->format, 108 plane_index); 109 } 110 111 return 0; 112 } 113 114 /** 115 * packed_pixels_addr_1x1() - Get the pointer to the block containing the pixel at the given 116 * coordinates 117 * 118 * @frame_info: Buffer metadata 119 * @x: The x (width) coordinate inside the plane 120 * @y: The y (height) coordinate inside the plane 121 * @plane_index: The index of the plane 122 * @addr: The returned pointer 123 * 124 * This function can only be used with format where block_h == block_w == 1. 125 */ 126 static void packed_pixels_addr_1x1(const struct vkms_frame_info *frame_info, 127 int x, int y, int plane_index, u8 **addr) 128 { 129 int offset, rem_x, rem_y; 130 131 WARN_ONCE(drm_format_info_block_width(frame_info->fb->format, 132 plane_index) != 1, 133 "%s() only support formats with block_w == 1", __func__); 134 WARN_ONCE(drm_format_info_block_height(frame_info->fb->format, 135 plane_index) != 1, 136 "%s() only support formats with block_h == 1", __func__); 137 138 packed_pixels_offset(frame_info, x, y, plane_index, &offset, &rem_x, 139 &rem_y); 140 *addr = (u8 *)frame_info->map[0].vaddr + offset; 141 } 142 143 /* 144 * The following functions take pixel data (a, r, g, b, pixel, ...) and convert them to 145 * &struct pixel_argb_u16 146 * 147 * They are used in the `read_line`s functions to avoid duplicate work for some pixel formats. 148 */ 149 150 static struct pixel_argb_u16 argb_u16_from_u8888(u8 a, u8 r, u8 g, u8 b) 151 { 152 struct pixel_argb_u16 out_pixel; 153 /* 154 * The 257 is the "conversion ratio". This number is obtained by the 155 * (2^16 - 1) / (2^8 - 1) division. Which, in this case, tries to get 156 * the best color value in a pixel format with more possibilities. 157 * A similar idea applies to others RGB color conversions. 158 */ 159 out_pixel.a = (u16)a * 257; 160 out_pixel.r = (u16)r * 257; 161 out_pixel.g = (u16)g * 257; 162 out_pixel.b = (u16)b * 257; 163 164 return out_pixel; 165 } 166 167 static struct pixel_argb_u16 argb_u16_from_u16161616(u16 a, u16 r, u16 g, u16 b) 168 { 169 struct pixel_argb_u16 out_pixel; 170 171 out_pixel.a = a; 172 out_pixel.r = r; 173 out_pixel.g = g; 174 out_pixel.b = b; 175 176 return out_pixel; 177 } 178 179 static struct pixel_argb_u16 argb_u16_from_le16161616(__le16 a, __le16 r, __le16 g, __le16 b) 180 { 181 return argb_u16_from_u16161616(le16_to_cpu(a), le16_to_cpu(r), le16_to_cpu(g), 182 le16_to_cpu(b)); 183 } 184 185 static struct pixel_argb_u16 argb_u16_from_RGB565(const __le16 *pixel) 186 { 187 struct pixel_argb_u16 out_pixel; 188 189 s64 fp_rb_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(31)); 190 s64 fp_g_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(63)); 191 192 u16 rgb_565 = le16_to_cpu(*pixel); 193 s64 fp_r = drm_int2fixp((rgb_565 >> 11) & 0x1f); 194 s64 fp_g = drm_int2fixp((rgb_565 >> 5) & 0x3f); 195 s64 fp_b = drm_int2fixp(rgb_565 & 0x1f); 196 197 out_pixel.a = (u16)0xffff; 198 out_pixel.r = drm_fixp2int_round(drm_fixp_mul(fp_r, fp_rb_ratio)); 199 out_pixel.g = drm_fixp2int_round(drm_fixp_mul(fp_g, fp_g_ratio)); 200 out_pixel.b = drm_fixp2int_round(drm_fixp_mul(fp_b, fp_rb_ratio)); 201 202 return out_pixel; 203 } 204 205 /* 206 * The following functions are read_line function for each pixel format supported by VKMS. 207 * 208 * They read a line starting at the point @x_start,@y_start following the @direction. The result 209 * is stored in @out_pixel and in the format ARGB16161616. 210 * 211 * These functions are very repetitive, but the innermost pixel loops must be kept inside these 212 * functions for performance reasons. Some benchmarking was done in [1] where having the innermost 213 * loop factored out of these functions showed a slowdown by a factor of three. 214 * 215 * [1]: https://lore.kernel.org/dri-devel/d258c8dc-78e9-4509-9037-a98f7f33b3a3@riseup.net/ 216 */ 217 218 static void ARGB8888_read_line(const struct vkms_plane_state *plane, int x_start, int y_start, 219 enum pixel_read_direction direction, int count, 220 struct pixel_argb_u16 out_pixel[]) 221 { 222 struct pixel_argb_u16 *end = out_pixel + count; 223 u8 *src_pixels; 224 225 packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels); 226 227 int step = get_block_step_bytes(plane->frame_info->fb, direction, 0); 228 229 while (out_pixel < end) { 230 u8 *px = (u8 *)src_pixels; 231 *out_pixel = argb_u16_from_u8888(px[3], px[2], px[1], px[0]); 232 out_pixel += 1; 233 src_pixels += step; 234 } 235 } 236 237 static void XRGB8888_read_line(const struct vkms_plane_state *plane, int x_start, int y_start, 238 enum pixel_read_direction direction, int count, 239 struct pixel_argb_u16 out_pixel[]) 240 { 241 struct pixel_argb_u16 *end = out_pixel + count; 242 u8 *src_pixels; 243 244 packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels); 245 246 int step = get_block_step_bytes(plane->frame_info->fb, direction, 0); 247 248 while (out_pixel < end) { 249 u8 *px = (u8 *)src_pixels; 250 *out_pixel = argb_u16_from_u8888(255, px[2], px[1], px[0]); 251 out_pixel += 1; 252 src_pixels += step; 253 } 254 } 255 256 static void ARGB16161616_read_line(const struct vkms_plane_state *plane, int x_start, 257 int y_start, enum pixel_read_direction direction, int count, 258 struct pixel_argb_u16 out_pixel[]) 259 { 260 struct pixel_argb_u16 *end = out_pixel + count; 261 u8 *src_pixels; 262 263 packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels); 264 265 int step = get_block_step_bytes(plane->frame_info->fb, direction, 0); 266 267 while (out_pixel < end) { 268 u16 *px = (u16 *)src_pixels; 269 *out_pixel = argb_u16_from_u16161616(px[3], px[2], px[1], px[0]); 270 out_pixel += 1; 271 src_pixels += step; 272 } 273 } 274 275 static void XRGB16161616_read_line(const struct vkms_plane_state *plane, int x_start, 276 int y_start, enum pixel_read_direction direction, int count, 277 struct pixel_argb_u16 out_pixel[]) 278 { 279 struct pixel_argb_u16 *end = out_pixel + count; 280 u8 *src_pixels; 281 282 packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels); 283 284 int step = get_block_step_bytes(plane->frame_info->fb, direction, 0); 285 286 while (out_pixel < end) { 287 __le16 *px = (__le16 *)src_pixels; 288 *out_pixel = argb_u16_from_le16161616(cpu_to_le16(0xFFFF), px[2], px[1], px[0]); 289 out_pixel += 1; 290 src_pixels += step; 291 } 292 } 293 294 static void RGB565_read_line(const struct vkms_plane_state *plane, int x_start, 295 int y_start, enum pixel_read_direction direction, int count, 296 struct pixel_argb_u16 out_pixel[]) 297 { 298 struct pixel_argb_u16 *end = out_pixel + count; 299 u8 *src_pixels; 300 301 packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels); 302 303 int step = get_block_step_bytes(plane->frame_info->fb, direction, 0); 304 305 while (out_pixel < end) { 306 __le16 *px = (__le16 *)src_pixels; 307 308 *out_pixel = argb_u16_from_RGB565(px); 309 out_pixel += 1; 310 src_pixels += step; 311 } 312 } 313 314 /* 315 * The following functions take one &struct pixel_argb_u16 and convert it to a specific format. 316 * The result is stored in @out_pixel. 317 * 318 * They are used in vkms_writeback_row() to convert and store a pixel from the src_buffer to 319 * the writeback buffer. 320 */ 321 static void argb_u16_to_ARGB8888(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel) 322 { 323 /* 324 * This sequence below is important because the format's byte order is 325 * in little-endian. In the case of the ARGB8888 the memory is 326 * organized this way: 327 * 328 * | Addr | = blue channel 329 * | Addr + 1 | = green channel 330 * | Addr + 2 | = Red channel 331 * | Addr + 3 | = Alpha channel 332 */ 333 out_pixel[3] = DIV_ROUND_CLOSEST(in_pixel->a, 257); 334 out_pixel[2] = DIV_ROUND_CLOSEST(in_pixel->r, 257); 335 out_pixel[1] = DIV_ROUND_CLOSEST(in_pixel->g, 257); 336 out_pixel[0] = DIV_ROUND_CLOSEST(in_pixel->b, 257); 337 } 338 339 static void argb_u16_to_XRGB8888(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel) 340 { 341 out_pixel[3] = 0xff; 342 out_pixel[2] = DIV_ROUND_CLOSEST(in_pixel->r, 257); 343 out_pixel[1] = DIV_ROUND_CLOSEST(in_pixel->g, 257); 344 out_pixel[0] = DIV_ROUND_CLOSEST(in_pixel->b, 257); 345 } 346 347 static void argb_u16_to_ARGB16161616(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel) 348 { 349 __le16 *pixel = (__le16 *)out_pixel; 350 351 pixel[3] = cpu_to_le16(in_pixel->a); 352 pixel[2] = cpu_to_le16(in_pixel->r); 353 pixel[1] = cpu_to_le16(in_pixel->g); 354 pixel[0] = cpu_to_le16(in_pixel->b); 355 } 356 357 static void argb_u16_to_XRGB16161616(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel) 358 { 359 __le16 *pixel = (__le16 *)out_pixel; 360 361 pixel[3] = cpu_to_le16(0xffff); 362 pixel[2] = cpu_to_le16(in_pixel->r); 363 pixel[1] = cpu_to_le16(in_pixel->g); 364 pixel[0] = cpu_to_le16(in_pixel->b); 365 } 366 367 static void argb_u16_to_RGB565(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel) 368 { 369 __le16 *pixel = (__le16 *)out_pixel; 370 371 s64 fp_rb_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(31)); 372 s64 fp_g_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(63)); 373 374 s64 fp_r = drm_int2fixp(in_pixel->r); 375 s64 fp_g = drm_int2fixp(in_pixel->g); 376 s64 fp_b = drm_int2fixp(in_pixel->b); 377 378 u16 r = drm_fixp2int(drm_fixp_div(fp_r, fp_rb_ratio)); 379 u16 g = drm_fixp2int(drm_fixp_div(fp_g, fp_g_ratio)); 380 u16 b = drm_fixp2int(drm_fixp_div(fp_b, fp_rb_ratio)); 381 382 *pixel = cpu_to_le16(r << 11 | g << 5 | b); 383 } 384 385 /** 386 * vkms_writeback_row() - Generic loop for all supported writeback format. It is executed just 387 * after the blending to write a line in the writeback buffer. 388 * 389 * @wb: Job where to insert the final image 390 * @src_buffer: Line to write 391 * @y: Row to write in the writeback buffer 392 */ 393 void vkms_writeback_row(struct vkms_writeback_job *wb, 394 const struct line_buffer *src_buffer, int y) 395 { 396 struct vkms_frame_info *frame_info = &wb->wb_frame_info; 397 int x_dst = frame_info->dst.x1; 398 u8 *dst_pixels; 399 int rem_x, rem_y; 400 401 packed_pixels_addr(frame_info, x_dst, y, 0, &dst_pixels, &rem_x, &rem_y); 402 struct pixel_argb_u16 *in_pixels = src_buffer->pixels; 403 int x_limit = min_t(size_t, drm_rect_width(&frame_info->dst), src_buffer->n_pixels); 404 405 for (size_t x = 0; x < x_limit; x++, dst_pixels += frame_info->fb->format->cpp[0]) 406 wb->pixel_write(dst_pixels, &in_pixels[x]); 407 } 408 409 /** 410 * get_pixel_read_line_function() - Retrieve the correct read_line function for a specific 411 * format. The returned pointer is NULL for unsupported pixel formats. The caller must ensure that 412 * the pointer is valid before using it in a vkms_plane_state. 413 * 414 * @format: DRM_FORMAT_* value for which to obtain a conversion function (see [drm_fourcc.h]) 415 */ 416 pixel_read_line_t get_pixel_read_line_function(u32 format) 417 { 418 switch (format) { 419 case DRM_FORMAT_ARGB8888: 420 return &ARGB8888_read_line; 421 case DRM_FORMAT_XRGB8888: 422 return &XRGB8888_read_line; 423 case DRM_FORMAT_ARGB16161616: 424 return &ARGB16161616_read_line; 425 case DRM_FORMAT_XRGB16161616: 426 return &XRGB16161616_read_line; 427 case DRM_FORMAT_RGB565: 428 return &RGB565_read_line; 429 default: 430 /* 431 * This is a bug in vkms_plane_atomic_check(). All the supported 432 * format must: 433 * - Be listed in vkms_formats in vkms_plane.c 434 * - Have a pixel_read callback defined here 435 */ 436 pr_err("Pixel format %p4cc is not supported by VKMS planes. This is a kernel bug, atomic check must forbid this configuration.\n", 437 &format); 438 BUG(); 439 } 440 } 441 442 /** 443 * get_pixel_write_function() - Retrieve the correct write_pixel function for a specific format. 444 * The returned pointer is NULL for unsupported pixel formats. The caller must ensure that the 445 * pointer is valid before using it in a vkms_writeback_job. 446 * 447 * @format: DRM_FORMAT_* value for which to obtain a conversion function (see [drm_fourcc.h]) 448 */ 449 pixel_write_t get_pixel_write_function(u32 format) 450 { 451 switch (format) { 452 case DRM_FORMAT_ARGB8888: 453 return &argb_u16_to_ARGB8888; 454 case DRM_FORMAT_XRGB8888: 455 return &argb_u16_to_XRGB8888; 456 case DRM_FORMAT_ARGB16161616: 457 return &argb_u16_to_ARGB16161616; 458 case DRM_FORMAT_XRGB16161616: 459 return &argb_u16_to_XRGB16161616; 460 case DRM_FORMAT_RGB565: 461 return &argb_u16_to_RGB565; 462 default: 463 /* 464 * This is a bug in vkms_writeback_atomic_check. All the supported 465 * format must: 466 * - Be listed in vkms_wb_formats in vkms_writeback.c 467 * - Have a pixel_write callback defined here 468 */ 469 pr_err("Pixel format %p4cc is not supported by VKMS writeback. This is a kernel bug, atomic check must forbid this configuration.\n", 470 &format); 471 BUG(); 472 } 473 } 474