mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	drm/format-helper: Add drm_fb_build_fourcc_list() helper
Add drm_fb_build_fourcc_list() function that builds a list of supported formats from native and emulated ones. Helpful for all drivers that do format conversion as part of their plane updates. Update current caller. v3: * improve warnings on ignored formats (Sam) v2: * use u32 instead of uint32_t (Sam) * print a warning if output array is too small (Sam) * comment fixes (Sam) Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> Reviewed-by: Sam Ravnborg <sam@ravnborg.org> Link: https://patchwork.freedesktop.org/patch/msgid/20220905141648.22013-5-tzimmermann@suse.de
This commit is contained in:
		
							parent
							
								
									385d1bba89
								
							
						
					
					
						commit
						4a85b0b51e
					
				
					 3 changed files with 123 additions and 43 deletions
				
			
		| 
						 | 
					@ -793,3 +793,111 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc
 | 
				
			||||||
	kfree(src32);
 | 
						kfree(src32);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono);
 | 
					EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t fourcc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const uint32_t *fourccs_end = fourccs + nfourccs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (fourccs < fourccs_end) {
 | 
				
			||||||
 | 
							if (*fourccs == fourcc)
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							++fourccs;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * drm_fb_build_fourcc_list - Filters a list of supported color formats against
 | 
				
			||||||
 | 
					 *                            the device's native formats
 | 
				
			||||||
 | 
					 * @dev: DRM device
 | 
				
			||||||
 | 
					 * @native_fourccs: 4CC codes of natively supported color formats
 | 
				
			||||||
 | 
					 * @native_nfourccs: The number of entries in @native_fourccs
 | 
				
			||||||
 | 
					 * @driver_fourccs: 4CC codes of all driver-supported color formats
 | 
				
			||||||
 | 
					 * @driver_nfourccs: The number of entries in @driver_fourccs
 | 
				
			||||||
 | 
					 * @fourccs_out: Returns 4CC codes of supported color formats
 | 
				
			||||||
 | 
					 * @nfourccs_out: The number of available entries in @fourccs_out
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function create a list of supported color format from natively
 | 
				
			||||||
 | 
					 * supported formats and the emulated formats.
 | 
				
			||||||
 | 
					 * At a minimum, most userspace programs expect at least support for
 | 
				
			||||||
 | 
					 * XRGB8888 on the primary plane. Devices that have to emulate the
 | 
				
			||||||
 | 
					 * format, and possibly others, can use drm_fb_build_fourcc_list() to
 | 
				
			||||||
 | 
					 * create a list of supported color formats. The returned list can
 | 
				
			||||||
 | 
					 * be handed over to drm_universal_plane_init() et al. Native formats
 | 
				
			||||||
 | 
					 * will go before emulated formats. Other heuristics might be applied
 | 
				
			||||||
 | 
					 * to optimize the order. Formats near the beginning of the list are
 | 
				
			||||||
 | 
					 * usually preferred over formats near the end of the list.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns:
 | 
				
			||||||
 | 
					 * The number of color-formats 4CC codes returned in @fourccs_out.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					size_t drm_fb_build_fourcc_list(struct drm_device *dev,
 | 
				
			||||||
 | 
									const u32 *native_fourccs, size_t native_nfourccs,
 | 
				
			||||||
 | 
									const u32 *driver_fourccs, size_t driver_nfourccs,
 | 
				
			||||||
 | 
									u32 *fourccs_out, size_t nfourccs_out)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 *fourccs = fourccs_out;
 | 
				
			||||||
 | 
						const u32 *fourccs_end = fourccs_out + nfourccs_out;
 | 
				
			||||||
 | 
						bool found_native = false;
 | 
				
			||||||
 | 
						size_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * The device's native formats go first.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < native_nfourccs; ++i) {
 | 
				
			||||||
 | 
							u32 fourcc = native_fourccs[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
 | 
				
			||||||
 | 
								continue; /* skip duplicate entries */
 | 
				
			||||||
 | 
							} else if (fourccs == fourccs_end) {
 | 
				
			||||||
 | 
								drm_warn(dev, "Ignoring native format %p4cc\n", &fourcc);
 | 
				
			||||||
 | 
								continue; /* end of available output buffer */
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							drm_dbg_kms(dev, "adding native format %p4cc\n", &fourcc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!found_native)
 | 
				
			||||||
 | 
								found_native = is_listed_fourcc(driver_fourccs, driver_nfourccs, fourcc);
 | 
				
			||||||
 | 
							*fourccs = fourcc;
 | 
				
			||||||
 | 
							++fourccs;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * The plane's atomic_update helper converts the framebuffer's color format
 | 
				
			||||||
 | 
						 * to a native format when copying to device memory.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * If there is not a single format supported by both, device and
 | 
				
			||||||
 | 
						 * driver, the native formats are likely not supported by the conversion
 | 
				
			||||||
 | 
						 * helpers. Therefore *only* support the native formats and add a
 | 
				
			||||||
 | 
						 * conversion helper ASAP.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (!found_native) {
 | 
				
			||||||
 | 
							drm_warn(dev, "Format conversion helpers required to add extra formats.\n");
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * The extra formats, emulated by the driver, go second.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; (i < driver_nfourccs) && (fourccs < fourccs_end); ++i) {
 | 
				
			||||||
 | 
							u32 fourcc = driver_fourccs[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
 | 
				
			||||||
 | 
								continue; /* skip duplicate and native entries */
 | 
				
			||||||
 | 
							} else if (fourccs == fourccs_end) {
 | 
				
			||||||
 | 
								drm_warn(dev, "Ignoring emulated format %p4cc\n", &fourcc);
 | 
				
			||||||
 | 
								continue; /* end of available output buffer */
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							drm_dbg_kms(dev, "adding emulated format %p4cc\n", &fourcc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							*fourccs = fourcc;
 | 
				
			||||||
 | 
							++fourccs;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						return fourccs - fourccs_out;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(drm_fb_build_fourcc_list);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -644,45 +644,6 @@ static struct drm_display_mode simpledrm_mode(unsigned int width,
 | 
				
			||||||
	return mode;
 | 
						return mode;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const uint32_t *simpledrm_device_formats(struct simpledrm_device *sdev,
 | 
					 | 
				
			||||||
						size_t *nformats_out)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct drm_device *dev = &sdev->dev;
 | 
					 | 
				
			||||||
	size_t i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (sdev->nformats)
 | 
					 | 
				
			||||||
		goto out; /* don't rebuild list on recurring calls */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* native format goes first */
 | 
					 | 
				
			||||||
	sdev->formats[0] = sdev->format->format;
 | 
					 | 
				
			||||||
	sdev->nformats = 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* default formats go second */
 | 
					 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(simpledrm_primary_plane_formats); ++i) {
 | 
					 | 
				
			||||||
		if (simpledrm_primary_plane_formats[i] == sdev->format->format)
 | 
					 | 
				
			||||||
			continue; /* native format already went first */
 | 
					 | 
				
			||||||
		sdev->formats[sdev->nformats] = simpledrm_primary_plane_formats[i];
 | 
					 | 
				
			||||||
		sdev->nformats++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * TODO: The simpledrm driver converts framebuffers to the native
 | 
					 | 
				
			||||||
	 * format when copying them to device memory. If there are more
 | 
					 | 
				
			||||||
	 * formats listed than supported by the driver, the native format
 | 
					 | 
				
			||||||
	 * is not supported by the conversion helpers. Therefore *only*
 | 
					 | 
				
			||||||
	 * support the native format and add a conversion helper ASAP.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (drm_WARN_ONCE(dev, i != sdev->nformats,
 | 
					 | 
				
			||||||
			  "format conversion helpers required for %p4cc",
 | 
					 | 
				
			||||||
			  &sdev->format->format)) {
 | 
					 | 
				
			||||||
		sdev->nformats = 1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	*nformats_out = sdev->nformats;
 | 
					 | 
				
			||||||
	return sdev->formats;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
 | 
					static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
 | 
				
			||||||
							struct platform_device *pdev)
 | 
												struct platform_device *pdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -699,7 +660,6 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
 | 
				
			||||||
	struct drm_encoder *encoder;
 | 
						struct drm_encoder *encoder;
 | 
				
			||||||
	struct drm_connector *connector;
 | 
						struct drm_connector *connector;
 | 
				
			||||||
	unsigned long max_width, max_height;
 | 
						unsigned long max_width, max_height;
 | 
				
			||||||
	const uint32_t *formats;
 | 
					 | 
				
			||||||
	size_t nformats;
 | 
						size_t nformats;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -811,11 +771,14 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Primary plane */
 | 
						/* Primary plane */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	formats = simpledrm_device_formats(sdev, &nformats);
 | 
						nformats = drm_fb_build_fourcc_list(dev, &format->format, 1,
 | 
				
			||||||
 | 
										    simpledrm_primary_plane_formats,
 | 
				
			||||||
 | 
										    ARRAY_SIZE(simpledrm_primary_plane_formats),
 | 
				
			||||||
 | 
										    sdev->formats, ARRAY_SIZE(sdev->formats));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	primary_plane = &sdev->primary_plane;
 | 
						primary_plane = &sdev->primary_plane;
 | 
				
			||||||
	ret = drm_universal_plane_init(dev, primary_plane, 0, &simpledrm_primary_plane_funcs,
 | 
						ret = drm_universal_plane_init(dev, primary_plane, 0, &simpledrm_primary_plane_funcs,
 | 
				
			||||||
				       formats, nformats,
 | 
									       sdev->formats, nformats,
 | 
				
			||||||
				       simpledrm_primary_plane_format_modifiers,
 | 
									       simpledrm_primary_plane_format_modifiers,
 | 
				
			||||||
				       DRM_PLANE_TYPE_PRIMARY, NULL);
 | 
									       DRM_PLANE_TYPE_PRIMARY, NULL);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,11 +6,15 @@
 | 
				
			||||||
#ifndef __LINUX_DRM_FORMAT_HELPER_H
 | 
					#ifndef __LINUX_DRM_FORMAT_HELPER_H
 | 
				
			||||||
#define __LINUX_DRM_FORMAT_HELPER_H
 | 
					#define __LINUX_DRM_FORMAT_HELPER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct iosys_map;
 | 
					#include <linux/types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct drm_device;
 | 
				
			||||||
struct drm_format_info;
 | 
					struct drm_format_info;
 | 
				
			||||||
struct drm_framebuffer;
 | 
					struct drm_framebuffer;
 | 
				
			||||||
struct drm_rect;
 | 
					struct drm_rect;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct iosys_map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,
 | 
					unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,
 | 
				
			||||||
				const struct drm_rect *clip);
 | 
									const struct drm_rect *clip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,4 +48,9 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc
 | 
				
			||||||
			     const struct iosys_map *src, const struct drm_framebuffer *fb,
 | 
								     const struct iosys_map *src, const struct drm_framebuffer *fb,
 | 
				
			||||||
			     const struct drm_rect *clip);
 | 
								     const struct drm_rect *clip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t drm_fb_build_fourcc_list(struct drm_device *dev,
 | 
				
			||||||
 | 
									const u32 *native_fourccs, size_t native_nfourccs,
 | 
				
			||||||
 | 
									const u32 *extra_fourccs, size_t extra_nfourccs,
 | 
				
			||||||
 | 
									u32 *fourccs_out, size_t nfourccs_out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __LINUX_DRM_FORMAT_HELPER_H */
 | 
					#endif /* __LINUX_DRM_FORMAT_HELPER_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue