| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef COMPONENTS_VIZ_COMMON_RESOURCES_SHARED_IMAGE_FORMAT_H_ |
| #define COMPONENTS_VIZ_COMMON_RESOURCES_SHARED_IMAGE_FORMAT_H_ |
| |
| #include <stdint.h> |
| |
| #include <compare> |
| #include <optional> |
| #include <string> |
| |
| #include "base/check.h" |
| #include "base/component_export.h" |
| #include "build/build_config.h" |
| #include "mojo/public/cpp/bindings/struct_traits.h" |
| #include "mojo/public/cpp/bindings/union_traits.h" |
| #include "services/viz/public/mojom/compositing/internal/singleplanar_format.mojom.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace viz { |
| |
| class LegacyMultiPlaneFormat; |
| class SinglePlaneFormat; |
| |
| namespace mojom { |
| class SharedImageFormatDataView; |
| class MultiplanarFormatDataView; |
| } // namespace mojom |
| |
| // This class represents the image format used by SharedImages for single plane |
| // images (eg. RGBA) or multiplanar images (eg. NV12). This format can be |
| // either SingleplanarFormat or MultiplanarFormat (PlaneConfig + Subsampling + |
| // ChannelFormat). |
| class COMPONENT_EXPORT(VIZ_SHARED_IMAGE_FORMAT) SharedImageFormat final { |
| public: |
| // Specifies how YUV (and optionally A) are divided among planes. Planes are |
| // separated by underscores in the enum value names. Within each plane the |
| // pixmap/texture channels are mapped to the YUVA channels in the order |
| // specified, e.g. for kY_UV Y is in channel 0 of plane 0, U is in channel 0 |
| // of plane 1, and V is in channel 1 of plane 1. |
| enum class PlaneConfig : uint8_t { |
| kY_U_V, // Plane 0: Y, Plane 1: U, Plane 2: V |
| kY_V_U, // Plane 0: Y, Plane 1: V, Plane 2: U |
| kY_UV, // Plane 0: Y, Plane 1: UV |
| kY_UV_A, // Plane 0: Y, Plane 1: UV, Plane 2: A |
| kY_U_V_A, // Plane 0: Y, Plane 1: U, Plane 2: V, Plane 3: A |
| }; |
| |
| // UV subsampling is also specified in the enum value names using J:a:b |
| // notation (e.g. 4:2:0 is 1/2 horizontal and 1/2 vertical resolution for U |
| // and V). If alpha is present it is not subsampled. |
| enum class Subsampling : uint8_t { |
| k420, // 1 set of UV values for each 2x2 block of Y values. |
| k422, // 1 set of UV values for each 2x1 block of Y values. |
| k444, // No subsampling. UV values for each Y. |
| }; |
| |
| // Specifies the channel format for Y plane in the YUV (and optionally A) |
| // plane config. The channel format for remaining planes are identified based |
| // on the planes in the PlaneConfig. For individual planes like Y_V_U, U and V |
| // are both 8 bit channel formats whereas for Y_UV, the UV plane contains 2 |
| // channels with each being an 8 bit channel format. |
| enum class ChannelFormat : uint8_t { |
| k8, // 8 bit unorm |
| k10, // 10 bit unorm |
| k16, // 16 bit unorm |
| k16F // 16 bit float |
| }; |
| |
| SharedImageFormat() = default; |
| static constexpr SharedImageFormat MultiPlane(PlaneConfig plane_config, |
| Subsampling subsampling, |
| ChannelFormat channel_format) { |
| return SharedImageFormat(plane_config, subsampling, channel_format); |
| } |
| |
| PlaneConfig plane_config() const { |
| DCHECK(is_multi_plane()); |
| return format_.multiplanar_format.plane_config; |
| } |
| Subsampling subsampling() const { |
| DCHECK(is_multi_plane()); |
| return format_.multiplanar_format.subsampling; |
| } |
| ChannelFormat channel_format() const { |
| DCHECK(is_multi_plane()); |
| return format_.multiplanar_format.channel_format; |
| } |
| |
| bool is_single_plane() const { |
| return plane_type_ == PlaneType::kSinglePlane; |
| } |
| bool is_multi_plane() const { return plane_type_ == PlaneType::kMultiPlane; } |
| |
| // Returns whether this format needs to be externally sampled. Note that |
| // external sampling is supported only on Ozone. |
| bool PrefersExternalSampler() const { |
| #if BUILDFLAG(IS_OZONE) |
| return is_multi_plane() |
| ? format_.multiplanar_format.prefers_external_sampler |
| : false; |
| #else |
| return false; |
| #endif |
| } |
| |
| #if BUILDFLAG(IS_OZONE) |
| // Sets this format (which must be multiplanar) as needing external sampling. |
| void SetPrefersExternalSampler() { |
| CHECK(is_multi_plane()); |
| format_.multiplanar_format.prefers_external_sampler = true; |
| } |
| #endif |
| |
| // Clears this format as needing external sampling. Note that with MappableSI, |
| // the type of underlying buffer (native or shared memory) is not known until |
| // the shared image is created. This is problematic for clients which needs to |
| // call SharedImageFormat::SetPrefersExternalSampler() before creating a |
| // shared image. In those cases clients will unconditionally call |
| // SharedImageFormat::SetPrefersExternalSampler() before creating a |
| // mappableSI. SI will internally take care of clearing it back to false by |
| // using this method in case it is determined that the it's backed by shared |
| // memory. https://issues.chromium.org/339546249. |
| void ClearPrefersExternalSampler() { |
| #if BUILDFLAG(IS_OZONE) |
| CHECK(is_multi_plane() && |
| format_.multiplanar_format.prefers_external_sampler); |
| format_.multiplanar_format.prefers_external_sampler = false; |
| #endif |
| } |
| |
| // Returns whether the resource format can be used as a software bitmap for |
| // export to the display compositor. |
| bool IsBitmapFormatSupported() const; |
| |
| // Return the number of planes associated with the format. |
| int NumberOfPlanes() const; |
| |
| // Returns true is `plane_index` is valid. |
| bool IsValidPlaneIndex(int plane_index) const; |
| |
| // Returns the size for a plane given `plane_index`. |
| gfx::Size GetPlaneSize(int plane_index, const gfx::Size& size) const; |
| |
| // Returns estimated size in bytes of an image in this format of `size` or |
| // nullopt if size in bytes overflows. Includes all planes for multiplanar |
| // formats. |
| std::optional<size_t> MaybeEstimatedSizeInBytes(const gfx::Size& size) const; |
| |
| // Returns estimated size in bytes for a plane of an image in this format of |
| // `size` or nullopt if size in bytes overflows. |
| std::optional<size_t> MaybeEstimatedPlaneSizeInBytes( |
| int plane_index, |
| const gfx::Size& size) const; |
| |
| // Returns estimated size in bytes for an image in this format of `size` or 0 |
| // if size in bytes overflows. Includes all planes for multiplanar formats. |
| size_t EstimatedSizeInBytes(const gfx::Size& size) const; |
| |
| // Returns true if the size in bytes doesn't overflow size_t. |
| bool VerifySizeInBytes(const gfx::Size& size) const; |
| |
| // Returns number of channels for a plane for multiplanar formats. |
| int NumChannelsInPlane(int plane_index) const; |
| |
| // Returns the bit depth for multiplanar format based on the channel format. |
| int MultiplanarBitDepth() const; |
| |
| // Returns a std::string for the format. |
| std::string ToString() const; |
| |
| // Returns a std::string for the format that is compatible with gtest. |
| std::string ToTestParamString() const; |
| |
| // Returns true if the format contains alpha. |
| bool HasAlpha() const; |
| |
| // Returns true if the format is ETC1 compressed. |
| bool IsCompressed() const; |
| |
| // Returns true if format is legacy multiplanar SingleplanarFormat i.e. |
| // YUV_420_BIPLANAR, YVU_420, YUVA_420_TRIPLANAR, P010. |
| bool IsLegacyMultiplanar() const; |
| |
| // NOTE: Supported only for true single-plane formats (i.e., formats for |
| // which is_single_plane() is true and IsLegacyMultiplanar() is false). |
| int BitsPerPixel() const; |
| |
| bool operator==(const SharedImageFormat& o) const; |
| std::weak_ordering operator<=>(const SharedImageFormat& o) const; |
| |
| private: |
| enum class PlaneType : uint8_t { |
| kUnknown, |
| kSinglePlane, |
| kMultiPlane, |
| }; |
| |
| union SharedImageFormatUnion { |
| // A struct for multiplanar format that is defined by the PlaneConfig, |
| // Subsampling and ChannelFormat it holds. |
| struct MultiplanarFormat { |
| PlaneConfig plane_config; |
| Subsampling subsampling; |
| ChannelFormat channel_format; |
| #if BUILDFLAG(IS_OZONE) |
| // NOTE: This field is intentionally not used as part of defining equality |
| // between two MultiplanarFormat instances as clients should not generally |
| // need to care. Clients who need to distinguish for a particular |
| // SharedImageFormat `format` should call |
| // format.PrefersExternalSampler(). |
| bool prefers_external_sampler = false; |
| #endif |
| |
| bool operator==(const MultiplanarFormat& o) const; |
| std::weak_ordering operator<=>(const MultiplanarFormat& o) const; |
| }; |
| |
| SharedImageFormatUnion() {} |
| explicit constexpr SharedImageFormatUnion( |
| mojom::SingleplanarFormat singleplanar_format) |
| : singleplanar_format(singleplanar_format) {} |
| constexpr SharedImageFormatUnion(PlaneConfig plane_config, |
| Subsampling subsampling, |
| ChannelFormat channel_format) |
| : multiplanar_format({plane_config, subsampling, channel_format}) {} |
| |
| mojom::SingleplanarFormat singleplanar_format; |
| MultiplanarFormat multiplanar_format; |
| }; |
| |
| friend class LegacyMultiPlaneFormat; |
| friend class SinglePlaneFormat; |
| friend struct mojo::UnionTraits<mojom::SharedImageFormatDataView, |
| SharedImageFormat>; |
| friend struct mojo::StructTraits<mojom::MultiplanarFormatDataView, |
| SharedImageFormatUnion::MultiplanarFormat>; |
| |
| explicit constexpr SharedImageFormat( |
| mojom::SingleplanarFormat singleplanar_format) |
| : plane_type_(PlaneType::kSinglePlane), format_(singleplanar_format) {} |
| constexpr SharedImageFormat(PlaneConfig plane_config, |
| Subsampling subsampling, |
| ChannelFormat channel_format) |
| : plane_type_(PlaneType::kMultiPlane), |
| format_(plane_config, subsampling, channel_format) {} |
| |
| PlaneType plane_type() const { return plane_type_; } |
| SharedImageFormatUnion::MultiplanarFormat multiplanar_format() const { |
| DCHECK(is_multi_plane()); |
| return format_.multiplanar_format; |
| } |
| |
| mojom::SingleplanarFormat singleplanar_format() const { |
| DCHECK(is_single_plane()); |
| return format_.singleplanar_format; |
| } |
| |
| PlaneType plane_type_ = PlaneType::kUnknown; |
| // `format_` can only be SingleplanarFormat (for single plane, eg. RGBA) or |
| // MultiplanarFormat at any given time. |
| SharedImageFormatUnion format_; |
| }; |
| |
| // Constants for common single-planar formats. |
| // NOTE: This is a class rather than a namespace so that SharedImageFormat can |
| // friend it to give it access to the private constructor needed for creating |
| // these constants. |
| class SinglePlaneFormat { |
| public: |
| static constexpr SharedImageFormat kRGBA_8888 = |
| SharedImageFormat(mojom::SingleplanarFormat::RGBA_8888); |
| static constexpr SharedImageFormat kRGBA_4444 = |
| SharedImageFormat(mojom::SingleplanarFormat::RGBA_4444); |
| static constexpr SharedImageFormat kBGRA_8888 = |
| SharedImageFormat(mojom::SingleplanarFormat::BGRA_8888); |
| static constexpr SharedImageFormat kALPHA_8 = |
| SharedImageFormat(mojom::SingleplanarFormat::ALPHA_8); |
| static constexpr SharedImageFormat kLUMINANCE_8 = |
| SharedImageFormat(mojom::SingleplanarFormat::LUMINANCE_8); |
| static constexpr SharedImageFormat kRGB_565 = |
| SharedImageFormat(mojom::SingleplanarFormat::RGB_565); |
| static constexpr SharedImageFormat kBGR_565 = |
| SharedImageFormat(mojom::SingleplanarFormat::BGR_565); |
| static constexpr SharedImageFormat kETC1 = |
| SharedImageFormat(mojom::SingleplanarFormat::ETC1); |
| static constexpr SharedImageFormat kR_8 = |
| SharedImageFormat(mojom::SingleplanarFormat::R_8); |
| static constexpr SharedImageFormat kRG_88 = |
| SharedImageFormat(mojom::SingleplanarFormat::RG_88); |
| static constexpr SharedImageFormat kLUMINANCE_F16 = |
| SharedImageFormat(mojom::SingleplanarFormat::LUMINANCE_F16); |
| static constexpr SharedImageFormat kRGBA_F16 = |
| SharedImageFormat(mojom::SingleplanarFormat::RGBA_F16); |
| static constexpr SharedImageFormat kR_16 = |
| SharedImageFormat(mojom::SingleplanarFormat::R_16); |
| static constexpr SharedImageFormat kRG_1616 = |
| SharedImageFormat(mojom::SingleplanarFormat::RG_1616); |
| static constexpr SharedImageFormat kRGBX_8888 = |
| SharedImageFormat(mojom::SingleplanarFormat::RGBX_8888); |
| static constexpr SharedImageFormat kBGRX_8888 = |
| SharedImageFormat(mojom::SingleplanarFormat::BGRX_8888); |
| static constexpr SharedImageFormat kRGBA_1010102 = |
| SharedImageFormat(mojom::SingleplanarFormat::RGBA_1010102); |
| static constexpr SharedImageFormat kBGRA_1010102 = |
| SharedImageFormat(mojom::SingleplanarFormat::BGRA_1010102); |
| static constexpr SharedImageFormat kR_F16 = |
| SharedImageFormat(mojom::SingleplanarFormat::R_F16); |
| |
| // All known singleplanar formats. |
| static constexpr SharedImageFormat kAll[19] = { |
| kRGBA_8888, kRGBA_4444, kBGRA_8888, kALPHA_8, kLUMINANCE_8, |
| kRGB_565, kBGR_565, kETC1, kR_8, kRG_88, |
| kLUMINANCE_F16, kRGBA_F16, kR_16, kRG_1616, kRGBX_8888, |
| kBGRX_8888, kRGBA_1010102, kBGRA_1010102, kR_F16}; |
| }; |
| |
| // Constants for legacy single-plane representations of multiplanar formats. |
| // NOTE: This is a class rather than a namespace so that SharedImageFormat can |
| // friend it to give it access to the private constructor needed for creating |
| // these constants. |
| // TODO(crbug.com/40239769): Eliminate these once the codebase is completely |
| // converted to using MultiplanarSharedImage. |
| class LegacyMultiPlaneFormat { |
| public: |
| static constexpr SharedImageFormat kYV12 = |
| SharedImageFormat(mojom::SingleplanarFormat::YV12_LEGACY); |
| static constexpr SharedImageFormat kNV12 = |
| SharedImageFormat(mojom::SingleplanarFormat::NV12_LEGACY); |
| static constexpr SharedImageFormat kNV12A = |
| SharedImageFormat(mojom::SingleplanarFormat::NV12A_LEGACY); |
| static constexpr SharedImageFormat kP010 = |
| SharedImageFormat(mojom::SingleplanarFormat::P010_LEGACY); |
| |
| // All known legacy multiplanar formats. |
| static constexpr SharedImageFormat kAll[4] = {kYV12, kNV12, kNV12A, kP010}; |
| |
| // The number of singleplanar and legacy multiplanar formats should |
| // correspond exactly to the number of SingleplanarFormat types. |
| static_assert(std::size(SinglePlaneFormat::kAll) + std::size(kAll) == |
| static_cast<int>(mojom::SingleplanarFormat::kMaxValue) + 1); |
| }; |
| |
| // Constants for common multi-planar formats. |
| namespace MultiPlaneFormat { |
| inline constexpr SharedImageFormat kYV12 = |
| SharedImageFormat::MultiPlane(SharedImageFormat::PlaneConfig::kY_V_U, |
| SharedImageFormat::Subsampling::k420, |
| SharedImageFormat::ChannelFormat::k8); |
| inline constexpr SharedImageFormat kNV12 = |
| SharedImageFormat::MultiPlane(SharedImageFormat::PlaneConfig::kY_UV, |
| SharedImageFormat::Subsampling::k420, |
| SharedImageFormat::ChannelFormat::k8); |
| inline constexpr SharedImageFormat kNV12A = |
| SharedImageFormat::MultiPlane(SharedImageFormat::PlaneConfig::kY_UV_A, |
| SharedImageFormat::Subsampling::k420, |
| SharedImageFormat::ChannelFormat::k8); |
| inline constexpr SharedImageFormat kP010 = |
| SharedImageFormat::MultiPlane(SharedImageFormat::PlaneConfig::kY_UV, |
| SharedImageFormat::Subsampling::k420, |
| SharedImageFormat::ChannelFormat::k10); |
| // NOTE: These formats do not have an equivalent BufferFormat as they are not |
| // used with GpuMemoryBuffers. |
| inline constexpr SharedImageFormat kNV16 = |
| SharedImageFormat::MultiPlane(SharedImageFormat::PlaneConfig::kY_UV, |
| SharedImageFormat::Subsampling::k422, |
| SharedImageFormat::ChannelFormat::k8); |
| inline constexpr SharedImageFormat kNV24 = |
| SharedImageFormat::MultiPlane(SharedImageFormat::PlaneConfig::kY_UV, |
| SharedImageFormat::Subsampling::k444, |
| SharedImageFormat::ChannelFormat::k8); |
| inline constexpr SharedImageFormat kP210 = |
| SharedImageFormat::MultiPlane(SharedImageFormat::PlaneConfig::kY_UV, |
| SharedImageFormat::Subsampling::k422, |
| SharedImageFormat::ChannelFormat::k10); |
| inline constexpr SharedImageFormat kP410 = |
| SharedImageFormat::MultiPlane(SharedImageFormat::PlaneConfig::kY_UV, |
| SharedImageFormat::Subsampling::k444, |
| SharedImageFormat::ChannelFormat::k10); |
| inline constexpr SharedImageFormat kI420 = |
| SharedImageFormat::MultiPlane(SharedImageFormat::PlaneConfig::kY_U_V, |
| SharedImageFormat::Subsampling::k420, |
| SharedImageFormat::ChannelFormat::k8); |
| inline constexpr SharedImageFormat kI420A = |
| SharedImageFormat::MultiPlane(SharedImageFormat::PlaneConfig::kY_U_V_A, |
| SharedImageFormat::Subsampling::k420, |
| SharedImageFormat::ChannelFormat::k8); |
| } // namespace MultiPlaneFormat |
| |
| } // namespace viz |
| |
| #endif // COMPONENTS_VIZ_COMMON_RESOURCES_SHARED_IMAGE_FORMAT_H_ |