Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/format-helper: Share implementation among conversion helpers

Provide format-independent conversion helpers for system and I/O
memory. Implement most existing helpers on top of it. The source and
destination formats of each conversion is handled by a per-line
helper that is given to the generic implementation.

v2:
* remove a blank line

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220427141409.22842-5-tzimmermann@suse.de

+123 -246
+123 -246
drivers/gpu/drm/drm_format_helper.c
··· 40 40 } 41 41 EXPORT_SYMBOL(drm_fb_clip_offset); 42 42 43 + /* TODO: Make this functon work with multi-plane formats. */ 44 + static int drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize, 45 + const void *vaddr, const struct drm_framebuffer *fb, 46 + const struct drm_rect *clip, bool vaddr_cached_hint, 47 + void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) 48 + { 49 + unsigned long linepixels = drm_rect_width(clip); 50 + unsigned long lines = drm_rect_height(clip); 51 + size_t sbuf_len = linepixels * fb->format->cpp[0]; 52 + void *stmp = NULL; 53 + unsigned long i; 54 + const void *sbuf; 55 + 56 + /* 57 + * Some source buffers, such as CMA memory, use write-combine 58 + * caching, so reads are uncached. Speed up access by fetching 59 + * one line at a time. 60 + */ 61 + if (!vaddr_cached_hint) { 62 + stmp = kmalloc(sbuf_len, GFP_KERNEL); 63 + if (!stmp) 64 + return -ENOMEM; 65 + } 66 + 67 + if (!dst_pitch) 68 + dst_pitch = drm_rect_width(clip) * dst_pixsize; 69 + vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]); 70 + 71 + for (i = 0; i < lines; ++i) { 72 + if (stmp) 73 + sbuf = memcpy(stmp, vaddr, sbuf_len); 74 + else 75 + sbuf = vaddr; 76 + xfrm_line(dst, sbuf, linepixels); 77 + vaddr += fb->pitches[0]; 78 + dst += dst_pitch; 79 + } 80 + 81 + kfree(stmp); 82 + 83 + return 0; 84 + } 85 + 86 + /* TODO: Make this functon work with multi-plane formats. */ 87 + static int drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize, 88 + const void *vaddr, const struct drm_framebuffer *fb, 89 + const struct drm_rect *clip, bool vaddr_cached_hint, 90 + void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) 91 + { 92 + unsigned long linepixels = drm_rect_width(clip); 93 + unsigned long lines = drm_rect_height(clip); 94 + size_t dbuf_len = linepixels * dst_pixsize; 95 + size_t stmp_off = round_up(dbuf_len, ARCH_KMALLOC_MINALIGN); /* for sbuf alignment */ 96 + size_t sbuf_len = linepixels * fb->format->cpp[0]; 97 + void *stmp = NULL; 98 + unsigned long i; 99 + const void *sbuf; 100 + void *dbuf; 101 + 102 + if (vaddr_cached_hint) { 103 + dbuf = kmalloc(dbuf_len, GFP_KERNEL); 104 + } else { 105 + dbuf = kmalloc(stmp_off + sbuf_len, GFP_KERNEL); 106 + stmp = dbuf + stmp_off; 107 + } 108 + if (!dbuf) 109 + return -ENOMEM; 110 + 111 + if (!dst_pitch) 112 + dst_pitch = linepixels * dst_pixsize; 113 + vaddr += clip_offset(clip, fb->pitches[0], fb->format->cpp[0]); 114 + 115 + for (i = 0; i < lines; ++i) { 116 + if (stmp) 117 + sbuf = memcpy(stmp, vaddr, sbuf_len); 118 + else 119 + sbuf = vaddr; 120 + xfrm_line(dbuf, sbuf, linepixels); 121 + memcpy_toio(dst, dbuf, dbuf_len); 122 + vaddr += fb->pitches[0]; 123 + dst += dst_pitch; 124 + } 125 + 126 + kfree(dbuf); 127 + 128 + return 0; 129 + } 130 + 43 131 /** 44 132 * drm_fb_memcpy - Copy clip buffer 45 133 * @dst: Destination buffer ··· 228 140 bool cached) 229 141 { 230 142 u8 cpp = fb->format->cpp[0]; 231 - unsigned long linepixels = drm_rect_width(clip); 232 - size_t len = linepixels * cpp; 233 - const void *sbuf; 234 - void *dbuf; 235 - unsigned int y; 236 - void *buf = NULL; 237 143 238 - if (WARN_ON_ONCE(cpp != 2 && cpp != 4)) 239 - return; 240 - 241 - if (!dst_pitch) 242 - dst_pitch = len; 243 - src += clip_offset(clip, fb->pitches[0], cpp); 244 - 245 - if (!cached) 246 - buf = kmalloc(len, GFP_KERNEL); 247 - 248 - for (y = clip->y1; y < clip->y2; y++) { 249 - if (buf) 250 - sbuf = memcpy(buf, src, len); 251 - else 252 - sbuf = src; 253 - dbuf = dst + clip->x1 * cpp; 254 - 255 - if (cpp == 4) 256 - drm_fb_swab32_line(dbuf, sbuf, linepixels); 257 - else 258 - drm_fb_swab16_line(dbuf, sbuf, linepixels); 259 - 260 - src += fb->pitches[0]; 261 - dst += dst_pitch; 144 + switch (cpp) { 145 + case 4: 146 + drm_fb_xfrm(dst, dst_pitch, cpp, src, fb, clip, cached, drm_fb_swab32_line); 147 + break; 148 + case 2: 149 + drm_fb_xfrm(dst, dst_pitch, cpp, src, fb, clip, cached, drm_fb_swab16_line); 150 + break; 151 + default: 152 + drm_warn_once(fb->dev, "Format %p4cc has unsupported pixel size.\n", 153 + &fb->format->format); 154 + break; 262 155 } 263 - 264 - kfree(buf); 265 156 } 266 157 EXPORT_SYMBOL(drm_fb_swab); 267 158 268 - static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels, 269 - bool swab) 159 + static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels) 270 160 { 271 161 u8 *dbuf8 = dbuf; 272 162 const __le32 *sbuf32 = sbuf; ··· 272 206 void drm_fb_xrgb8888_to_rgb332(void *dst, unsigned int dst_pitch, const void *src, 273 207 const struct drm_framebuffer *fb, const struct drm_rect *clip) 274 208 { 275 - size_t width = drm_rect_width(clip); 276 - size_t src_len = width * sizeof(u32); 277 - unsigned int y; 278 - void *sbuf; 279 - 280 - if (!dst_pitch) 281 - dst_pitch = width; 282 - 283 - /* Use a buffer to speed up access on buffers with uncached read mapping (i.e. WC) */ 284 - sbuf = kmalloc(src_len, GFP_KERNEL); 285 - if (!sbuf) 286 - return; 287 - 288 - src += clip_offset(clip, fb->pitches[0], sizeof(u32)); 289 - for (y = 0; y < drm_rect_height(clip); y++) { 290 - memcpy(sbuf, src, src_len); 291 - drm_fb_xrgb8888_to_rgb332_line(dst, sbuf, width, false); 292 - src += fb->pitches[0]; 293 - dst += dst_pitch; 294 - } 295 - 296 - kfree(sbuf); 209 + drm_fb_xfrm(dst, dst_pitch, 1, src, fb, clip, false, drm_fb_xrgb8888_to_rgb332_line); 297 210 } 298 211 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332); 299 212 ··· 323 278 const struct drm_framebuffer *fb, const struct drm_rect *clip, 324 279 bool swab) 325 280 { 326 - size_t linepixels = clip->x2 - clip->x1; 327 - size_t src_len = linepixels * sizeof(u32); 328 - size_t dst_len = linepixels * sizeof(u16); 329 - unsigned y, lines = clip->y2 - clip->y1; 330 - void *sbuf; 331 - 332 - if (!dst_pitch) 333 - dst_pitch = dst_len; 334 - 335 - /* 336 - * The cma memory is write-combined so reads are uncached. 337 - * Speed up by fetching one line at a time. 338 - */ 339 - sbuf = kmalloc(src_len, GFP_KERNEL); 340 - if (!sbuf) 341 - return; 342 - 343 - vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32)); 344 - for (y = 0; y < lines; y++) { 345 - memcpy(sbuf, vaddr, src_len); 346 - if (swab) 347 - drm_fb_xrgb8888_to_rgb565_swab_line(dst, sbuf, linepixels); 348 - else 349 - drm_fb_xrgb8888_to_rgb565_line(dst, sbuf, linepixels); 350 - vaddr += fb->pitches[0]; 351 - dst += dst_pitch; 352 - } 353 - 354 - kfree(sbuf); 281 + if (swab) 282 + drm_fb_xfrm(dst, dst_pitch, 2, vaddr, fb, clip, false, 283 + drm_fb_xrgb8888_to_rgb565_swab_line); 284 + else 285 + drm_fb_xfrm(dst, dst_pitch, 2, vaddr, fb, clip, false, 286 + drm_fb_xrgb8888_to_rgb565_line); 355 287 } 356 288 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565); 357 289 ··· 348 326 const void *vaddr, const struct drm_framebuffer *fb, 349 327 const struct drm_rect *clip, bool swab) 350 328 { 351 - size_t linepixels = clip->x2 - clip->x1; 352 - size_t dst_len = linepixels * sizeof(u16); 353 - unsigned y, lines = clip->y2 - clip->y1; 354 - void *dbuf; 355 - 356 - if (!dst_pitch) 357 - dst_pitch = dst_len; 358 - 359 - dbuf = kmalloc(dst_len, GFP_KERNEL); 360 - if (!dbuf) 361 - return; 362 - 363 - vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32)); 364 - for (y = 0; y < lines; y++) { 365 - if (swab) 366 - drm_fb_xrgb8888_to_rgb565_swab_line(dbuf, vaddr, linepixels); 367 - else 368 - drm_fb_xrgb8888_to_rgb565_line(dbuf, vaddr, linepixels); 369 - memcpy_toio(dst, dbuf, dst_len); 370 - vaddr += fb->pitches[0]; 371 - dst += dst_pitch; 372 - } 373 - 374 - kfree(dbuf); 329 + if (swab) 330 + drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false, 331 + drm_fb_xrgb8888_to_rgb565_swab_line); 332 + else 333 + drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false, 334 + drm_fb_xrgb8888_to_rgb565_line); 375 335 } 376 336 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_toio); 377 337 ··· 384 380 void drm_fb_xrgb8888_to_rgb888(void *dst, unsigned int dst_pitch, const void *src, 385 381 const struct drm_framebuffer *fb, const struct drm_rect *clip) 386 382 { 387 - size_t width = drm_rect_width(clip); 388 - size_t src_len = width * sizeof(u32); 389 - unsigned int y; 390 - void *sbuf; 391 - 392 - if (!dst_pitch) 393 - dst_pitch = width * 3; 394 - 395 - /* Use a buffer to speed up access on buffers with uncached read mapping (i.e. WC) */ 396 - sbuf = kmalloc(src_len, GFP_KERNEL); 397 - if (!sbuf) 398 - return; 399 - 400 - src += clip_offset(clip, fb->pitches[0], sizeof(u32)); 401 - for (y = 0; y < drm_rect_height(clip); y++) { 402 - memcpy(sbuf, src, src_len); 403 - drm_fb_xrgb8888_to_rgb888_line(dst, sbuf, width); 404 - src += fb->pitches[0]; 405 - dst += dst_pitch; 406 - } 407 - 408 - kfree(sbuf); 383 + drm_fb_xfrm(dst, dst_pitch, 3, src, fb, clip, false, drm_fb_xrgb8888_to_rgb888_line); 409 384 } 410 385 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888); 411 386 ··· 403 420 const void *vaddr, const struct drm_framebuffer *fb, 404 421 const struct drm_rect *clip) 405 422 { 406 - size_t linepixels = clip->x2 - clip->x1; 407 - size_t dst_len = linepixels * 3; 408 - unsigned y, lines = clip->y2 - clip->y1; 409 - void *dbuf; 410 - 411 - if (!dst_pitch) 412 - dst_pitch = dst_len; 413 - 414 - dbuf = kmalloc(dst_len, GFP_KERNEL); 415 - if (!dbuf) 416 - return; 417 - 418 - vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32)); 419 - for (y = 0; y < lines; y++) { 420 - drm_fb_xrgb8888_to_rgb888_line(dbuf, vaddr, linepixels); 421 - memcpy_toio(dst, dbuf, dst_len); 422 - vaddr += fb->pitches[0]; 423 - dst += dst_pitch; 424 - } 425 - 426 - kfree(dbuf); 423 + drm_fb_xfrm_toio(dst, dst_pitch, 3, vaddr, fb, clip, false, 424 + drm_fb_xrgb8888_to_rgb888_line); 427 425 } 428 426 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_toio); 429 427 ··· 428 464 const void *vaddr, const struct drm_framebuffer *fb, 429 465 const struct drm_rect *clip) 430 466 { 431 - size_t linepixels = drm_rect_width(clip); 432 - size_t dst_len = linepixels * 4; 433 - unsigned int y, lines = drm_rect_height(clip); 434 - void *dbuf; 435 - 436 - if (!dst_pitch) 437 - dst_pitch = dst_len; 438 - 439 - dbuf = kmalloc(dst_len, GFP_KERNEL); 440 - if (!dbuf) 441 - return; 442 - 443 - vaddr += clip_offset(clip, fb->pitches[0], 2); 444 - for (y = 0; y < lines; y++) { 445 - drm_fb_rgb565_to_xrgb8888_line(dbuf, vaddr, linepixels); 446 - memcpy_toio(dst, dbuf, dst_len); 447 - vaddr += fb->pitches[0]; 448 - dst += dst_pitch; 449 - } 450 - 451 - kfree(dbuf); 467 + drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false, 468 + drm_fb_rgb565_to_xrgb8888_line); 452 469 } 453 470 454 471 static void drm_fb_rgb888_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels) ··· 450 505 const void *vaddr, const struct drm_framebuffer *fb, 451 506 const struct drm_rect *clip) 452 507 { 453 - size_t linepixels = drm_rect_width(clip); 454 - size_t dst_len = linepixels * 4; 455 - unsigned int y, lines = drm_rect_height(clip); 456 - void *dbuf; 457 - 458 - if (!dst_pitch) 459 - dst_pitch = dst_len; 460 - 461 - dbuf = kmalloc(dst_len, GFP_KERNEL); 462 - if (!dbuf) 463 - return; 464 - 465 - vaddr += clip_offset(clip, fb->pitches[0], 3); 466 - for (y = 0; y < lines; y++) { 467 - drm_fb_rgb888_to_xrgb8888_line(dbuf, vaddr, linepixels); 468 - memcpy_toio(dst, dbuf, dst_len); 469 - vaddr += fb->pitches[0]; 470 - dst += dst_pitch; 471 - } 472 - 473 - kfree(dbuf); 508 + drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false, 509 + drm_fb_rgb888_to_xrgb8888_line); 474 510 } 475 511 476 512 static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels) ··· 486 560 const struct drm_framebuffer *fb, 487 561 const struct drm_rect *clip) 488 562 { 489 - size_t linepixels = clip->x2 - clip->x1; 490 - size_t dst_len = linepixels * sizeof(u32); 491 - unsigned int y, lines = clip->y2 - clip->y1; 492 - void *dbuf; 493 - 494 - if (!dst_pitch) 495 - dst_pitch = dst_len; 496 - 497 - dbuf = kmalloc(dst_len, GFP_KERNEL); 498 - if (!dbuf) 499 - return; 500 - 501 - vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32)); 502 - for (y = 0; y < lines; y++) { 503 - drm_fb_xrgb8888_to_xrgb2101010_line(dbuf, vaddr, linepixels); 504 - memcpy_toio(dst, dbuf, dst_len); 505 - vaddr += fb->pitches[0]; 506 - dst += dst_pitch; 507 - } 508 - 509 - kfree(dbuf); 563 + drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false, 564 + drm_fb_xrgb8888_to_xrgb2101010_line); 510 565 } 511 566 EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010_toio); 512 567 ··· 528 621 void drm_fb_xrgb8888_to_gray8(void *dst, unsigned int dst_pitch, const void *vaddr, 529 622 const struct drm_framebuffer *fb, const struct drm_rect *clip) 530 623 { 531 - unsigned int linepixels = clip->x2 - clip->x1; 532 - unsigned int len = linepixels * sizeof(u32); 533 - unsigned int y; 534 - void *buf; 535 - u8 *dst8; 536 - u32 *src32; 537 - 538 - if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888)) 539 - return; 540 - 541 - if (!dst_pitch) 542 - dst_pitch = drm_rect_width(clip); 543 - 544 - /* 545 - * The cma memory is write-combined so reads are uncached. 546 - * Speed up by fetching one line at a time. 547 - */ 548 - buf = kmalloc(len, GFP_KERNEL); 549 - if (!buf) 550 - return; 551 - 552 - vaddr += clip_offset(clip, fb->pitches[0], sizeof(u32)); 553 - for (y = clip->y1; y < clip->y2; y++) { 554 - dst8 = dst; 555 - src32 = memcpy(buf, vaddr, len); 556 - drm_fb_xrgb8888_to_gray8_line(dst8, src32, linepixels); 557 - vaddr += fb->pitches[0]; 558 - dst += dst_pitch; 559 - } 560 - 561 - kfree(buf); 624 + drm_fb_xfrm(dst, dst_pitch, 1, vaddr, fb, clip, false, drm_fb_xrgb8888_to_gray8_line); 562 625 } 563 626 EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); 564 627