diff options
Diffstat (limited to 'drivers/gpu/drm/drm_format_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_format_helper.c | 112 |
1 files changed, 57 insertions, 55 deletions
diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index d631627e6c39..0523f81e2445 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -1070,6 +1070,39 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc } EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono); +static uint32_t drm_fb_nonalpha_fourcc(uint32_t fourcc) +{ + /* only handle formats with depth != 0 and alpha channel */ + switch (fourcc) { + case DRM_FORMAT_ARGB1555: + return DRM_FORMAT_XRGB1555; + case DRM_FORMAT_ABGR1555: + return DRM_FORMAT_XBGR1555; + case DRM_FORMAT_RGBA5551: + return DRM_FORMAT_RGBX5551; + case DRM_FORMAT_BGRA5551: + return DRM_FORMAT_BGRX5551; + case DRM_FORMAT_ARGB8888: + return DRM_FORMAT_XRGB8888; + case DRM_FORMAT_ABGR8888: + return DRM_FORMAT_XBGR8888; + case DRM_FORMAT_RGBA8888: + return DRM_FORMAT_RGBX8888; + case DRM_FORMAT_BGRA8888: + return DRM_FORMAT_BGRX8888; + case DRM_FORMAT_ARGB2101010: + return DRM_FORMAT_XRGB2101010; + case DRM_FORMAT_ABGR2101010: + return DRM_FORMAT_XBGR2101010; + case DRM_FORMAT_RGBA1010102: + return DRM_FORMAT_RGBX1010102; + case DRM_FORMAT_BGRA1010102: + return DRM_FORMAT_BGRX1010102; + } + + return fourcc; +} + static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t fourcc) { const uint32_t *fourccs_end = fourccs + nfourccs; @@ -1082,73 +1115,48 @@ static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t return false; } -static const uint32_t conv_from_xrgb8888[] = { - DRM_FORMAT_XRGB8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_ARGB2101010, - DRM_FORMAT_RGB565, - DRM_FORMAT_RGB888, -}; - -static const uint32_t conv_from_rgb565_888[] = { - DRM_FORMAT_XRGB8888, - DRM_FORMAT_ARGB8888, -}; - -static bool is_conversion_supported(uint32_t from, uint32_t to) -{ - switch (from) { - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_ARGB8888: - return is_listed_fourcc(conv_from_xrgb8888, ARRAY_SIZE(conv_from_xrgb8888), to); - case DRM_FORMAT_RGB565: - case DRM_FORMAT_RGB888: - return is_listed_fourcc(conv_from_rgb565_888, ARRAY_SIZE(conv_from_rgb565_888), to); - case DRM_FORMAT_XRGB2101010: - return to == DRM_FORMAT_ARGB2101010; - case DRM_FORMAT_ARGB2101010: - return to == DRM_FORMAT_XRGB2101010; - default: - 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. + * supported formats and additional 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 + * will go before emulated formats. Native formats with alpha channel + * will be replaced by such without, as primary planes usually don't + * support alpha. 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. Formats - * without conversion helpers will be skipped. New drivers should only - * pass in XRGB8888 and avoid exposing additional emulated formats. + * 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) { + /* + * XRGB8888 is the default fallback format for most of userspace + * and it's currently the only format that should be emulated for + * the primary plane. Only if there's ever another default fallback, + * it should be added here. + */ + static const uint32_t extra_fourccs[] = { + DRM_FORMAT_XRGB8888, + }; + static const size_t extra_nfourccs = ARRAY_SIZE(extra_fourccs); + u32 *fourccs = fourccs_out; const u32 *fourccs_end = fourccs_out + nfourccs_out; - uint32_t native_format = 0; size_t i; /* @@ -1156,7 +1164,12 @@ size_t drm_fb_build_fourcc_list(struct drm_device *dev, */ for (i = 0; i < native_nfourccs; ++i) { - u32 fourcc = native_fourccs[i]; + /* + * Several DTs, boot loaders and firmware report native + * alpha formats that are non-alpha formats instead. So + * replace alpha formats by non-alpha formats. + */ + u32 fourcc = drm_fb_nonalpha_fourcc(native_fourccs[i]); if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) { continue; /* skip duplicate entries */ @@ -1167,14 +1180,6 @@ size_t drm_fb_build_fourcc_list(struct drm_device *dev, drm_dbg_kms(dev, "adding native format %p4cc\n", &fourcc); - /* - * There should only be one native format with the current API. - * This API needs to be refactored to correctly support arbitrary - * sets of native formats, since it needs to report which native - * format to use for each emulated format. - */ - if (!native_format) - native_format = fourcc; *fourccs = fourcc; ++fourccs; } @@ -1183,17 +1188,14 @@ size_t drm_fb_build_fourcc_list(struct drm_device *dev, * The extra formats, emulated by the driver, go second. */ - for (i = 0; (i < driver_nfourccs) && (fourccs < fourccs_end); ++i) { - u32 fourcc = driver_fourccs[i]; + for (i = 0; (i < extra_nfourccs) && (fourccs < fourccs_end); ++i) { + u32 fourcc = extra_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 */ - } else if (!is_conversion_supported(fourcc, native_format)) { - drm_dbg_kms(dev, "Unsupported emulated format %p4cc\n", &fourcc); - continue; /* format is not supported for conversion */ } drm_dbg_kms(dev, "adding emulated format %p4cc\n", &fourcc); |