Message ID | 20220209090314.2511959-3-javierm@redhat.com |
---|---|
State | New |
Headers | show |
Series | None | expand |
Hi Am 09.02.22 um 14:26 schrieb Javier Martinez Canillas: > Hello Thomas, > > Thanks a lot for your feedback. > > On 2/9/22 13:51, Thomas Zimmermann wrote: >> Hi >> > > [snip] > >>> + >>> + if (xb == pixels - 1 && end_offset) >>> + end = end_offset; >> >> end_offset should be called end_len, because it is the number of bits in >> the final byte; but not the offset of the final bit. >> > > Indeed. > > [snip] > >>> +void drm_fb_gray8_to_mono_reversed(void *dst, unsigned int dst_pitch, const void *vaddr, >>> + const struct drm_framebuffer *fb, >>> + const struct drm_rect *clip) > > [snip] > >> >> Do you really need that function. It's not exported and if it's not >> otherwise used, I'd just remove it. We don't keep unused interfaces around. >> > > At the end after your suggestion of doing line-per-line conversions it is not > needed, but since I already typed it and we were talking about adding other > formats besides the fake XRGB8888 as an optimization (R8 for grayscale and > Dx or something like that for reversed mono), I thought that would be useful > to have it as a helper. > > Also other drivers that want to advertise a R8 format could just use it and > not having to add their own helper. But I'm happy to drop it in v4 if you > think that's better to not have unused helpers. > > It could be taken from this patch-set anyways if someone wants to wire the > needed support for R8. I think, policy is to not keep unused code around. > > [snip] > >>> + >>> + /* >>> + * The reversed mono destination buffer contains 1 bit per pixel >>> + * and destination scanlines have to be in multiple of 8 pixels. >>> + */ >>> + if (!dst_pitch) >>> + dst_pitch = DIV_ROUND_UP(linepixels, 8); >> >> I'd do a warn_once if (dst_pitch % 8 != 0). >> > > Agreed. I'll add a warning an mention that will be rounded up. > >> >>> + >>> + /* >>> + * The cma memory is write-combined so reads are uncached. >>> + * Speed up by fetching one line at a time. >> >> I once had a patchset that adds caching information to struct >> dma_buf_map (soon to be named struct iosys_map). Blitting helpers would >> be able to enable/disable this optimization as needed. >> >> However, your driver doesn't use CMA. It's backed by SHMEM. Do you >> really want to keep that code in? >> > > It doesn't but the repaper does. And since the plan was to make that driver > to use the helper instead of having their own, I wanted to also make sure > that would work well with CMA. That makes sense then. > >> >>> + */ >>> + src32 = kmalloc(len_src32, GFP_KERNEL); >>> + if (!src32) >>> + return; >>> + >>> + /* >>> + * Copies are done line-by-line, allocate an intermediate >>> + * buffer to copy the gray8 lines and then convert to mono. >>> + */ >>> + gray8 = kmalloc(linepixels, GFP_KERNEL); >>> + if (!gray8) >>> + goto free_src32; >> >> If might be faster to allocate both buffers in one step and set the >> pointers into the allocated buffer. >> > > Not sure I got this. Do you mean to have a single buffer with length > linepixels + len_src32 and point src32 and gray8 to the same buffer ? That's the idea. I don't know the exact overhead for kalloc(), but at least the in userspace, malloc() in hot code paths is not a good idea. There's usually some searching for free space involved. In the long term, we could add a field in struct drm_framebuffer to keep such buffers around for reuse. > >>> + >>> + /* >>> + * For damage handling, it is possible that only parts of the source >>> + * buffer is copied and this could lead to start and end pixels that >>> + * are not aligned to multiple of 8. >>> + * >>> + * Calculate if the start and end pixels are not aligned and set the >>> + * offsets for the reversed mono line conversion function to adjust. >>> + */ >>> + start_offset = clip->x1 % 8; >>> + end_offset = clip->x2 % 8; >> >> end_len, again. If you have 1 single bit set in the final byte, the >> offset is 0, but the length is 1. >> > > Agreed, will change it too. Feel free to add my Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de> to the next version. Best regards Thomas > > Best regards,
On 2/9/22 16:21, Thomas Zimmermann wrote: [snip] >> >> It could be taken from this patch-set anyways if someone wants to wire the >> needed support for R8. > > I think, policy is to not keep unused code around. > Ok, I'll drop it then. We can include it again when adding R8 formats. [snip] >>> If might be faster to allocate both buffers in one step and set the >>> pointers into the allocated buffer. >>> >> >> Not sure I got this. Do you mean to have a single buffer with length >> linepixels + len_src32 and point src32 and gray8 to the same buffer ? > > That's the idea. I don't know the exact overhead for kalloc(), but at > least the in userspace, malloc() in hot code paths is not a good idea. > There's usually some searching for free space involved. > Sure, let's do it in one allocation then and I'll add some comments to make easier for people to follow the code. > In the long term, we could add a field in struct drm_framebuffer to keep > such buffers around for reuse. > >> >>>> + >>>> + /* >>>> + * For damage handling, it is possible that only parts of the source >>>> + * buffer is copied and this could lead to start and end pixels that >>>> + * are not aligned to multiple of 8. >>>> + * >>>> + * Calculate if the start and end pixels are not aligned and set the >>>> + * offsets for the reversed mono line conversion function to adjust. >>>> + */ >>>> + start_offset = clip->x1 % 8; >>>> + end_offset = clip->x2 % 8; >>> >>> end_len, again. If you have 1 single bit set in the final byte, the >>> offset is 0, but the length is 1. >>> >> >> Agreed, will change it too. > > Feel free to add my > > Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de> > Thanks! Best regards, -- Javier Martinez Canillas Linux Engineering Red Hat
diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index b981712623d3..19710342c0de 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -591,3 +591,160 @@ int drm_fb_blit_toio(void __iomem *dst, unsigned int dst_pitch, uint32_t dst_for return -EINVAL; } EXPORT_SYMBOL(drm_fb_blit_toio); + +static void drm_fb_gray8_to_mono_reversed_line(u8 *dst, const u8 *src, unsigned int pixels, + unsigned int start_offset, unsigned int end_offset) +{ + unsigned int xb, i; + + for (xb = 0; xb < pixels; xb++) { + unsigned int start = 0, end = 8; + u8 byte = 0x00; + + if (xb == 0 && start_offset) + start = start_offset; + + if (xb == pixels - 1 && end_offset) + end = end_offset; + + for (i = start; i < end; i++) { + unsigned int x = xb * 8 + i; + + byte >>= 1; + if (src[x] >> 7) + byte |= BIT(7); + } + *dst++ = byte; + } +} + +/** + * drm_fb_gray8_to_mono_reversed - Convert grayscale to reversed monochrome + * @dst: reversed monochrome destination buffer + * @dst_pitch: Number of bytes between two consecutive scanlines within dst + * @src: 8-bit grayscale source buffer + * @fb: DRM framebuffer + * @clip: Clip rectangle area to copy + * + * DRM doesn't have native monochrome or grayscale support. + * Such drivers can announce the commonly supported XR24 format to userspace + * and use drm_fb_xrgb8888_to_gray8() to convert to grayscale and then this + * helper function to convert to the native format. + */ +void drm_fb_gray8_to_mono_reversed(void *dst, unsigned int dst_pitch, const void *vaddr, + const struct drm_framebuffer *fb, + const struct drm_rect *clip) +{ + + unsigned int linepixels = drm_rect_width(clip); + unsigned int lines = drm_rect_height(clip); + unsigned int start_offset, end_offset; + unsigned int y; + const u8 *gray8 = vaddr; + u8 *mono = dst; + + /* + * The reversed mono destination buffer contains 1 bit per pixel + * and destination scanlines have to be in multiple of 8 pixels. + */ + if (!dst_pitch) + dst_pitch = DIV_ROUND_UP(linepixels, 8); + + /* + * For damage handling, it is possible that only parts of the source + * buffer is copied and this could lead to start and end pixels that + * are not aligned to multiple of 8. + * + * Calculate if the start and end pixels are not aligned and set the + * offsets for the reversed mono line conversion function to adjust. + */ + start_offset = clip->x1 % 8; + end_offset = clip->x2 % 8; + + for (y = 0; y < lines; y++) { + drm_fb_gray8_to_mono_reversed_line(mono, gray8, dst_pitch, + start_offset, end_offset); + gray8 += fb->pitches[0]; + mono += dst_pitch; + } +} + +/** + * drm_fb_xrgb8888_to_mono_reversed - Convert XRGB8888 to reversed monochrome + * @dst: reversed monochrome destination buffer + * @dst_pitch: Number of bytes between two consecutive scanlines within dst + * @src: XRGB8888 source buffer + * @fb: DRM framebuffer + * @clip: Clip rectangle area to copy + * + * DRM doesn't have native monochrome support. + * Such drivers can announce the commonly supported XR24 format to userspace + * and use this function to convert to the native format. + * + * This function uses drm_fb_xrgb8888_to_gray8() to convert to grayscale and + * then the result is converted from grayscale to reversed monohrome. + */ +void drm_fb_xrgb8888_to_mono_reversed(void *dst, unsigned int dst_pitch, const void *vaddr, + const struct drm_framebuffer *fb, const struct drm_rect *clip) +{ + unsigned int linepixels = drm_rect_width(clip); + unsigned int lines = clip->y2 - clip->y1; + unsigned int cpp = fb->format->cpp[0]; + unsigned int len_src32 = linepixels * cpp; + unsigned int start_offset, end_offset; + unsigned int y; + u8 *mono = dst, *gray8; + u32 *src32; + + if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888)) + return; + + /* + * The reversed mono destination buffer contains 1 bit per pixel + * and destination scanlines have to be in multiple of 8 pixels. + */ + if (!dst_pitch) + dst_pitch = DIV_ROUND_UP(linepixels, 8); + + /* + * The cma memory is write-combined so reads are uncached. + * Speed up by fetching one line at a time. + */ + src32 = kmalloc(len_src32, GFP_KERNEL); + if (!src32) + return; + + /* + * Copies are done line-by-line, allocate an intermediate + * buffer to copy the gray8 lines and then convert to mono. + */ + gray8 = kmalloc(linepixels, GFP_KERNEL); + if (!gray8) + goto free_src32; + + /* + * For damage handling, it is possible that only parts of the source + * buffer is copied and this could lead to start and end pixels that + * are not aligned to multiple of 8. + * + * Calculate if the start and end pixels are not aligned and set the + * offsets for the reversed mono line conversion function to adjust. + */ + start_offset = clip->x1 % 8; + end_offset = clip->x2 % 8; + + vaddr += clip_offset(clip, fb->pitches[0], cpp); + for (y = 0; y < lines; y++) { + src32 = memcpy(src32, vaddr, len_src32); + drm_fb_xrgb8888_to_gray8_line(gray8, src32, linepixels); + drm_fb_gray8_to_mono_reversed_line(mono, gray8, dst_pitch, + start_offset, end_offset); + vaddr += fb->pitches[0]; + mono += dst_pitch; + } + + kfree(gray8); +free_src32: + kfree(src32); +} +EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono_reversed); diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h index b30ed5de0a33..6638da9e9774 100644 --- a/include/drm/drm_format_helper.h +++ b/include/drm/drm_format_helper.h @@ -43,4 +43,12 @@ int drm_fb_blit_toio(void __iomem *dst, unsigned int dst_pitch, uint32_t dst_for const void *vmap, const struct drm_framebuffer *fb, const struct drm_rect *rect); +void drm_fb_gray8_to_mono_reversed(void *dst, unsigned int dst_pitch, const void *src, + const struct drm_framebuffer *fb, + const struct drm_rect *clip); + +void drm_fb_xrgb8888_to_mono_reversed(void *dst, unsigned int dst_pitch, const void *src, + const struct drm_framebuffer *fb, + const struct drm_rect *clip); + #endif /* __LINUX_DRM_FORMAT_HELPER_H */
Add support to convert XR24 and 8-bit grayscale to reversed monochrome for drivers that control monochromatic panels, that only have 1 bit per pixel. The drm_fb_gray8_to_mono_reversed() helper was based on the function that does the same in the drivers/gpu/drm/tiny/repaper.c driver. Signed-off-by: Javier Martinez Canillas <javierm@redhat.com> --- Changes in v3: - Also add a drm_fb_xrgb8888_to_mono_reversed() helper (Thomas Zimmermann) - Split lines copy to drm_fb_gray8_to_mono_reversed_line() (Thomas Zimmermann) - Handle case where the source buffer is not aligned to 8 (Thomas Zimmermann) drivers/gpu/drm/drm_format_helper.c | 157 ++++++++++++++++++++++++++++ include/drm/drm_format_helper.h | 8 ++ 2 files changed, 165 insertions(+)