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 ABGR8888_read_line(const struct vkms_plane_state *plane, int x_start, int y_start, 257 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 u8 *px = (u8 *)src_pixels; 269 /* Switch blue and red pixels. */ 270 *out_pixel = argb_u16_from_u8888(px[3], px[0], px[1], px[2]); 271 out_pixel += 1; 272 src_pixels += step; 273 } 274 } 275 276 static void ARGB16161616_read_line(const struct vkms_plane_state *plane, int x_start, 277 int y_start, enum pixel_read_direction direction, int count, 278 struct pixel_argb_u16 out_pixel[]) 279 { 280 struct pixel_argb_u16 *end = out_pixel + count; 281 u8 *src_pixels; 282 283 packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels); 284 285 int step = get_block_step_bytes(plane->frame_info->fb, direction, 0); 286 287 while (out_pixel < end) { 288 u16 *px = (u16 *)src_pixels; 289 *out_pixel = argb_u16_from_u16161616(px[3], px[2], px[1], px[0]); 290 out_pixel += 1; 291 src_pixels += step; 292 } 293 } 294 295 static void XRGB16161616_read_line(const struct vkms_plane_state *plane, int x_start, 296 int y_start, enum pixel_read_direction direction, int count, 297 struct pixel_argb_u16 out_pixel[]) 298 { 299 struct pixel_argb_u16 *end = out_pixel + count; 300 u8 *src_pixels; 301 302 packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels); 303 304 int step = get_block_step_bytes(plane->frame_info->fb, direction, 0); 305 306 while (out_pixel < end) { 307 __le16 *px = (__le16 *)src_pixels; 308 *out_pixel = argb_u16_from_le16161616(cpu_to_le16(0xFFFF), px[2], px[1], px[0]); 309 out_pixel += 1; 310 src_pixels += step; 311 } 312 } 313 314 static void RGB565_read_line(const struct vkms_plane_state *plane, int x_start, 315 int y_start, enum pixel_read_direction direction, int count, 316 struct pixel_argb_u16 out_pixel[]) 317 { 318 struct pixel_argb_u16 *end = out_pixel + count; 319 u8 *src_pixels; 320 321 packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels); 322 323 int step = get_block_step_bytes(plane->frame_info->fb, direction, 0); 324 325 while (out_pixel < end) { 326 __le16 *px = (__le16 *)src_pixels; 327 328 *out_pixel = argb_u16_from_RGB565(px); 329 out_pixel += 1; 330 src_pixels += step; 331 } 332 } 333 334 /* 335 * The following functions take one &struct pixel_argb_u16 and convert it to a specific format. 336 * The result is stored in @out_pixel. 337 * 338 * They are used in vkms_writeback_row() to convert and store a pixel from the src_buffer to 339 * the writeback buffer. 340 */ 341 static void argb_u16_to_ARGB8888(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel) 342 { 343 /* 344 * This sequence below is important because the format's byte order is 345 * in little-endian. In the case of the ARGB8888 the memory is 346 * organized this way: 347 * 348 * | Addr | = blue channel 349 * | Addr + 1 | = green channel 350 * | Addr + 2 | = Red channel 351 * | Addr + 3 | = Alpha channel 352 */ 353 out_pixel[3] = DIV_ROUND_CLOSEST(in_pixel->a, 257); 354 out_pixel[2] = DIV_ROUND_CLOSEST(in_pixel->r, 257); 355 out_pixel[1] = DIV_ROUND_CLOSEST(in_pixel->g, 257); 356 out_pixel[0] = DIV_ROUND_CLOSEST(in_pixel->b, 257); 357 } 358 359 static void argb_u16_to_XRGB8888(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel) 360 { 361 out_pixel[3] = 0xff; 362 out_pixel[2] = DIV_ROUND_CLOSEST(in_pixel->r, 257); 363 out_pixel[1] = DIV_ROUND_CLOSEST(in_pixel->g, 257); 364 out_pixel[0] = DIV_ROUND_CLOSEST(in_pixel->b, 257); 365 } 366 367 static void argb_u16_to_ABGR8888(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel) 368 { 369 out_pixel[3] = DIV_ROUND_CLOSEST(in_pixel->a, 257); 370 out_pixel[2] = DIV_ROUND_CLOSEST(in_pixel->b, 257); 371 out_pixel[1] = DIV_ROUND_CLOSEST(in_pixel->g, 257); 372 out_pixel[0] = DIV_ROUND_CLOSEST(in_pixel->r, 257); 373 } 374 375 static void argb_u16_to_ARGB16161616(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel) 376 { 377 __le16 *pixel = (__le16 *)out_pixel; 378 379 pixel[3] = cpu_to_le16(in_pixel->a); 380 pixel[2] = cpu_to_le16(in_pixel->r); 381 pixel[1] = cpu_to_le16(in_pixel->g); 382 pixel[0] = cpu_to_le16(in_pixel->b); 383 } 384 385 static void argb_u16_to_XRGB16161616(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel) 386 { 387 __le16 *pixel = (__le16 *)out_pixel; 388 389 pixel[3] = cpu_to_le16(0xffff); 390 pixel[2] = cpu_to_le16(in_pixel->r); 391 pixel[1] = cpu_to_le16(in_pixel->g); 392 pixel[0] = cpu_to_le16(in_pixel->b); 393 } 394 395 static void argb_u16_to_RGB565(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel) 396 { 397 __le16 *pixel = (__le16 *)out_pixel; 398 399 s64 fp_rb_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(31)); 400 s64 fp_g_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(63)); 401 402 s64 fp_r = drm_int2fixp(in_pixel->r); 403 s64 fp_g = drm_int2fixp(in_pixel->g); 404 s64 fp_b = drm_int2fixp(in_pixel->b); 405 406 u16 r = drm_fixp2int(drm_fixp_div(fp_r, fp_rb_ratio)); 407 u16 g = drm_fixp2int(drm_fixp_div(fp_g, fp_g_ratio)); 408 u16 b = drm_fixp2int(drm_fixp_div(fp_b, fp_rb_ratio)); 409 410 *pixel = cpu_to_le16(r << 11 | g << 5 | b); 411 } 412 413 /** 414 * vkms_writeback_row() - Generic loop for all supported writeback format. It is executed just 415 * after the blending to write a line in the writeback buffer. 416 * 417 * @wb: Job where to insert the final image 418 * @src_buffer: Line to write 419 * @y: Row to write in the writeback buffer 420 */ 421 void vkms_writeback_row(struct vkms_writeback_job *wb, 422 const struct line_buffer *src_buffer, int y) 423 { 424 struct vkms_frame_info *frame_info = &wb->wb_frame_info; 425 int x_dst = frame_info->dst.x1; 426 u8 *dst_pixels; 427 int rem_x, rem_y; 428 429 packed_pixels_addr(frame_info, x_dst, y, 0, &dst_pixels, &rem_x, &rem_y); 430 struct pixel_argb_u16 *in_pixels = src_buffer->pixels; 431 int x_limit = min_t(size_t, drm_rect_width(&frame_info->dst), src_buffer->n_pixels); 432 433 for (size_t x = 0; x < x_limit; x++, dst_pixels += frame_info->fb->format->cpp[0]) 434 wb->pixel_write(dst_pixels, &in_pixels[x]); 435 } 436 437 /** 438 * get_pixel_read_line_function() - Retrieve the correct read_line function for a specific 439 * format. The returned pointer is NULL for unsupported pixel formats. The caller must ensure that 440 * the pointer is valid before using it in a vkms_plane_state. 441 * 442 * @format: DRM_FORMAT_* value for which to obtain a conversion function (see [drm_fourcc.h]) 443 */ 444 pixel_read_line_t get_pixel_read_line_function(u32 format) 445 { 446 switch (format) { 447 case DRM_FORMAT_ARGB8888: 448 return &ARGB8888_read_line; 449 case DRM_FORMAT_XRGB8888: 450 return &XRGB8888_read_line; 451 case DRM_FORMAT_ABGR8888: 452 return &ABGR8888_read_line; 453 case DRM_FORMAT_ARGB16161616: 454 return &ARGB16161616_read_line; 455 case DRM_FORMAT_XRGB16161616: 456 return &XRGB16161616_read_line; 457 case DRM_FORMAT_RGB565: 458 return &RGB565_read_line; 459 default: 460 /* 461 * This is a bug in vkms_plane_atomic_check(). All the supported 462 * format must: 463 * - Be listed in vkms_formats in vkms_plane.c 464 * - Have a pixel_read callback defined here 465 */ 466 pr_err("Pixel format %p4cc is not supported by VKMS planes. This is a kernel bug, atomic check must forbid this configuration.\n", 467 &format); 468 BUG(); 469 } 470 } 471 472 /** 473 * get_pixel_write_function() - Retrieve the correct write_pixel function for a specific format. 474 * The returned pointer is NULL for unsupported pixel formats. The caller must ensure that the 475 * pointer is valid before using it in a vkms_writeback_job. 476 * 477 * @format: DRM_FORMAT_* value for which to obtain a conversion function (see [drm_fourcc.h]) 478 */ 479 pixel_write_t get_pixel_write_function(u32 format) 480 { 481 switch (format) { 482 case DRM_FORMAT_ARGB8888: 483 return &argb_u16_to_ARGB8888; 484 case DRM_FORMAT_XRGB8888: 485 return &argb_u16_to_XRGB8888; 486 case DRM_FORMAT_ABGR8888: 487 return &argb_u16_to_ABGR8888; 488 case DRM_FORMAT_ARGB16161616: 489 return &argb_u16_to_ARGB16161616; 490 case DRM_FORMAT_XRGB16161616: 491 return &argb_u16_to_XRGB16161616; 492 case DRM_FORMAT_RGB565: 493 return &argb_u16_to_RGB565; 494 default: 495 /* 496 * This is a bug in vkms_writeback_atomic_check. All the supported 497 * format must: 498 * - Be listed in vkms_wb_formats in vkms_writeback.c 499 * - Have a pixel_write callback defined here 500 */ 501 pr_err("Pixel format %p4cc is not supported by VKMS writeback. This is a kernel bug, atomic check must forbid this configuration.\n", 502 &format); 503 BUG(); 504 } 505 } 506