// // Copyright 2013 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // formatutils.h: Queries for GL image formats. #ifndef LIBANGLE_FORMATUTILS_H_ #define LIBANGLE_FORMATUTILS_H_ #include #include #include #include "angle_gl.h" #include "common/android_util.h" #include "libANGLE/Caps.h" #include "libANGLE/Config.h" #include "libANGLE/Error.h" #include "libANGLE/Version.h" #include "libANGLE/VertexAttribute.h" #include "libANGLE/angletypes.h" namespace gl { struct VertexAttribute; struct FormatType final { FormatType(); FormatType(GLenum format_, GLenum type_); FormatType(const FormatType &other) = default; FormatType &operator=(const FormatType &other) = default; bool operator<(const FormatType &other) const; GLenum format; GLenum type; }; struct Type { Type() : bytes(0), bytesShift(0), specialInterpretation(0) {} explicit Type(uint32_t packedTypeInfo) : bytes(packedTypeInfo & 0xff), bytesShift((packedTypeInfo >> 8) & 0xff), specialInterpretation((packedTypeInfo >> 16) & 1) {} GLuint bytes; GLuint bytesShift; // Bit shift by this value to effectively divide/multiply by "bytes" in a // more optimal way bool specialInterpretation; }; uint32_t GetPackedTypeInfo(GLenum type); ANGLE_INLINE GLenum GetNonLinearFormat(const GLenum format) { switch (format) { case GL_BGRA8_EXT: return GL_BGRA8_SRGB_ANGLEX; case GL_RGBA8: return GL_SRGB8_ALPHA8; case GL_RGB8: case GL_BGRX8_ANGLEX: case GL_RGBX8_ANGLE: return GL_SRGB8; case GL_RGBA16F: return GL_RGBA16F; default: return GL_NONE; } } ANGLE_INLINE bool ColorspaceFormatOverride(const EGLenum colorspace, GLenum *rendertargetformat) { // Override the rendertargetformat based on colorpsace switch (colorspace) { case EGL_GL_COLORSPACE_LINEAR: // linear colorspace no translation needed case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT: // linear colorspace no translation needed case EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT: // linear colorspace no translation needed case EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT: // App, not the HW, will specify the // transfer function case EGL_GL_COLORSPACE_SCRGB_EXT: // App, not the HW, will specify the transfer function // No translation return true; case EGL_GL_COLORSPACE_SRGB_KHR: case EGL_GL_COLORSPACE_DISPLAY_P3_EXT: { GLenum nonLinearFormat = GetNonLinearFormat(*rendertargetformat); if (nonLinearFormat != GL_NONE) { *rendertargetformat = nonLinearFormat; return true; } else { return false; } } break; default: UNREACHABLE(); return false; } } ANGLE_INLINE const Type GetTypeInfo(GLenum type) { return Type(GetPackedTypeInfo(type)); } // This helpers use tricks based on the assumption that the type has certain values. static_assert(static_cast(DrawElementsType::UnsignedByte) == 0, "Please update this code."); static_assert(static_cast(DrawElementsType::UnsignedShort) == 1, "Please update this code."); static_assert(static_cast(DrawElementsType::UnsignedInt) == 2, "Please update this code."); ANGLE_INLINE GLuint GetDrawElementsTypeSize(DrawElementsType type) { return (1 << static_cast(type)); } ANGLE_INLINE GLuint GetDrawElementsTypeShift(DrawElementsType type) { return static_cast(type); } // Information about an OpenGL internal format. Can be keyed on the internalFormat and type // members. struct InternalFormat { InternalFormat(); InternalFormat(const InternalFormat &other); InternalFormat &operator=(const InternalFormat &other); GLuint computePixelBytes(GLenum formatType) const; [[nodiscard]] bool computeBufferRowLength(uint32_t width, uint32_t *resultOut) const; [[nodiscard]] bool computeBufferImageHeight(uint32_t height, uint32_t *resultOut) const; [[nodiscard]] bool computeRowPitch(GLenum formatType, GLsizei width, GLint alignment, GLint rowLength, GLuint *resultOut) const; [[nodiscard]] bool computeDepthPitch(GLsizei height, GLint imageHeight, GLuint rowPitch, GLuint *resultOut) const; [[nodiscard]] bool computeDepthPitch(GLenum formatType, GLsizei width, GLsizei height, GLint alignment, GLint rowLength, GLint imageHeight, GLuint *resultOut) const; [[nodiscard]] bool computePalettedImageRowPitch(GLsizei width, GLuint *resultOut) const; [[nodiscard]] bool computeCompressedImageSize(const Extents &size, GLuint *resultOut) const; [[nodiscard]] std::pair getCompressedImageMinBlocks() const; [[nodiscard]] bool computeSkipBytes(GLenum formatType, GLuint rowPitch, GLuint depthPitch, const PixelStoreStateBase &state, bool is3D, GLuint *resultOut) const; [[nodiscard]] bool computePackUnpackEndByte(GLenum formatType, const Extents &size, const PixelStoreStateBase &state, bool is3D, GLuint *resultOut) const; bool isLUMA() const; GLenum getReadPixelsFormat(const Extensions &extensions) const; GLenum getReadPixelsType(const Version &version) const; // Support upload a portion of image? bool supportSubImage() const; ANGLE_INLINE bool isChannelSizeCompatible(GLuint redSize, GLuint greenSize, GLuint blueSize, GLuint alphaSize) const { // We only check for equality in all channel sizes return ((redSize == redBits) && (greenSize == greenBits) && (blueSize == blueBits) && (alphaSize == alphaBits)); } // Return true if the format is a required renderbuffer format in the given version of the core // spec. Note that it isn't always clear whether all the rules that apply to core required // renderbuffer formats also apply to additional formats added by extensions. Because of this // extension formats are conservatively not included. bool isRequiredRenderbufferFormat(const Version &version) const; bool isInt() const; bool isDepthOrStencil() const; bool operator==(const InternalFormat &other) const; bool operator!=(const InternalFormat &other) const; GLenum internalFormat; bool sized; GLenum sizedInternalFormat; GLuint redBits; GLuint greenBits; GLuint blueBits; GLuint luminanceBits; GLuint alphaBits; GLuint sharedBits; GLuint depthBits; GLuint stencilBits; GLuint pixelBytes; GLuint componentCount; bool compressed; GLuint compressedBlockWidth; GLuint compressedBlockHeight; GLuint compressedBlockDepth; bool paletted; GLuint paletteBits; GLenum format; GLenum type; GLenum componentType; GLenum colorEncoding; typedef bool (*SupportCheckFunction)(const Version &, const Extensions &); SupportCheckFunction textureSupport; SupportCheckFunction filterSupport; SupportCheckFunction textureAttachmentSupport; // glFramebufferTexture2D SupportCheckFunction renderbufferSupport; // glFramebufferRenderbuffer SupportCheckFunction blendSupport; }; // A "Format" wraps an InternalFormat struct, querying it from either a sized internal format or // unsized internal format and type. // TODO(geofflang): Remove this, it doesn't add any more information than the InternalFormat object. struct Format { // Sized types only. explicit Format(GLenum internalFormat); // Sized or unsized types. explicit Format(const InternalFormat &internalFormat); Format(GLenum internalFormat, GLenum type); Format(const Format &other); Format &operator=(const Format &other); bool valid() const; static Format Invalid(); static bool SameSized(const Format &a, const Format &b); static bool EquivalentForBlit(const Format &a, const Format &b); friend std::ostream &operator<<(std::ostream &os, const Format &fmt); // This is the sized info. const InternalFormat *info; }; const InternalFormat &GetSizedInternalFormatInfo(GLenum internalFormat); const InternalFormat &GetInternalFormatInfo(GLenum internalFormat, GLenum type); // Strip sizing information from an internal format. Doesn't necessarily validate that the internal // format is valid. GLenum GetUnsizedFormat(GLenum internalFormat); // Return whether the compressed format requires whole image/mip level to be uploaded to texture. bool CompressedFormatRequiresWholeImage(GLenum internalFormat); // In support of GetImage, check for LUMA formats and override with real format void MaybeOverrideLuminance(GLenum &format, GLenum &type, GLenum actualFormat, GLenum actualType); typedef std::set FormatSet; const FormatSet &GetAllSizedInternalFormats(); typedef angle::HashMap> InternalFormatInfoMap; const InternalFormatInfoMap &GetInternalFormatMap(); int GetAndroidHardwareBufferFormatFromChannelSizes(const egl::AttributeMap &attribMap); GLenum GetConfigColorBufferFormat(const egl::Config *config); GLenum GetConfigDepthStencilBufferFormat(const egl::Config *config); ANGLE_INLINE int GetNativeVisualID(const InternalFormat &internalFormat) { int nativeVisualId = 0; #if defined(ANGLE_PLATFORM_ANDROID) nativeVisualId = angle::android::GLInternalFormatToNativePixelFormat(internalFormat.internalFormat); #endif #if defined(ANGLE_PLATFORM_LINUX) && defined(ANGLE_USES_GBM) nativeVisualId = angle::GLInternalFormatToGbmFourCCFormat(internalFormat.internalFormat); #endif return nativeVisualId; } // From the ESSL 3.00.4 spec: // Vertex shader inputs can only be float, floating-point vectors, matrices, signed and unsigned // integers and integer vectors. Vertex shader inputs cannot be arrays or structures. enum AttributeType { ATTRIBUTE_FLOAT, ATTRIBUTE_VEC2, ATTRIBUTE_VEC3, ATTRIBUTE_VEC4, ATTRIBUTE_INT, ATTRIBUTE_IVEC2, ATTRIBUTE_IVEC3, ATTRIBUTE_IVEC4, ATTRIBUTE_UINT, ATTRIBUTE_UVEC2, ATTRIBUTE_UVEC3, ATTRIBUTE_UVEC4, ATTRIBUTE_MAT2, ATTRIBUTE_MAT3, ATTRIBUTE_MAT4, ATTRIBUTE_MAT2x3, ATTRIBUTE_MAT2x4, ATTRIBUTE_MAT3x2, ATTRIBUTE_MAT3x4, ATTRIBUTE_MAT4x2, ATTRIBUTE_MAT4x3, }; AttributeType GetAttributeType(GLenum enumValue); typedef std::vector InputLayout; struct VertexFormat : private angle::NonCopyable { VertexFormat(GLenum typeIn, GLboolean normalizedIn, GLuint componentsIn, bool pureIntegerIn); GLenum type; GLboolean normalized; GLuint components; bool pureInteger; }; angle::FormatID GetVertexFormatID(VertexAttribType type, GLboolean normalized, GLuint components, bool pureInteger); angle::FormatID GetVertexFormatID(const VertexAttribute &attrib, VertexAttribType currentValueType); angle::FormatID GetCurrentValueFormatID(VertexAttribType currentValueType); const VertexFormat &GetVertexFormatFromID(angle::FormatID vertexFormatID); size_t GetVertexFormatSize(angle::FormatID vertexFormatID); angle::FormatID ConvertFormatSignedness(const angle::Format &format); ANGLE_INLINE bool IsS3TCFormat(const GLenum format) { switch (format) { case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return true; default: return false; } } ANGLE_INLINE bool IsRGTCFormat(const GLenum format) { switch (format) { case GL_COMPRESSED_RED_RGTC1_EXT: case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT: case GL_COMPRESSED_RED_GREEN_RGTC2_EXT: case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: return true; default: return false; } } ANGLE_INLINE bool IsBPTCFormat(const GLenum format) { switch (format) { case GL_COMPRESSED_RGBA_BPTC_UNORM_EXT: case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT: case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT: case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT: return true; default: return false; } } ANGLE_INLINE bool IsASTC2DFormat(const GLenum format) { if ((format >= GL_COMPRESSED_RGBA_ASTC_4x4_KHR && format <= GL_COMPRESSED_RGBA_ASTC_12x12_KHR) || (format >= GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR && format <= GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR)) { return true; } return false; } ANGLE_INLINE bool IsETC1Format(const GLenum format) { switch (format) { case GL_ETC1_RGB8_OES: return true; default: return false; } } ANGLE_INLINE bool IsETC2EACFormat(const GLenum format) { // ES 3.1, Table 8.19 switch (format) { case GL_COMPRESSED_R11_EAC: case GL_COMPRESSED_SIGNED_R11_EAC: case GL_COMPRESSED_RG11_EAC: case GL_COMPRESSED_SIGNED_RG11_EAC: case GL_COMPRESSED_RGB8_ETC2: case GL_COMPRESSED_SRGB8_ETC2: case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: case GL_COMPRESSED_RGBA8_ETC2_EAC: case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: return true; default: return false; } } ANGLE_INLINE bool IsPVRTC1Format(const GLenum format) { switch (format) { case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: case GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT: case GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT: case GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT: case GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT: return true; default: return false; } } ANGLE_INLINE bool IsBGRAFormat(const GLenum internalFormat) { switch (internalFormat) { case GL_BGRA8_EXT: case GL_BGRA4_ANGLEX: case GL_BGR5_A1_ANGLEX: case GL_BGRA8_SRGB_ANGLEX: case GL_BGRX8_ANGLEX: case GL_RGBX8_ANGLE: case GL_BGR565_ANGLEX: case GL_BGR10_A2_ANGLEX: return true; default: return false; } } // Check if an internal format is ever valid in ES3. Makes no checks about support for a specific // context. bool ValidES3InternalFormat(GLenum internalFormat); // Implemented in format_map_autogen.cpp bool ValidES3Format(GLenum format); bool ValidES3Type(GLenum type); bool ValidES3FormatCombination(GLenum format, GLenum type, GLenum internalFormat); // Implemented in format_map_desktop.cpp bool ValidDesktopFormat(GLenum format); bool ValidDesktopType(GLenum type); bool ValidDesktopFormatCombination(GLenum format, GLenum type, GLenum internalFormat); // Implemented in es3_copy_conversion_table_autogen.cpp bool ValidES3CopyConversion(GLenum textureFormat, GLenum framebufferFormat); ANGLE_INLINE ComponentType GetVertexAttributeComponentType(bool pureInteger, VertexAttribType type) { if (pureInteger) { switch (type) { case VertexAttribType::Byte: case VertexAttribType::Short: case VertexAttribType::Int: return ComponentType::Int; case VertexAttribType::UnsignedByte: case VertexAttribType::UnsignedShort: case VertexAttribType::UnsignedInt: return ComponentType::UnsignedInt; default: UNREACHABLE(); return ComponentType::NoType; } } else { return ComponentType::Float; } } constexpr std::size_t kMaxYuvPlaneCount = 3; template using YuvPlaneArray = std::array; struct YuvFormatInfo { // Sized types only. YuvFormatInfo(GLenum internalFormat, const Extents &yPlaneExtent); GLenum glInternalFormat; uint32_t planeCount; YuvPlaneArray planeBpp; YuvPlaneArray planeExtent; YuvPlaneArray planePitch; YuvPlaneArray planeSize; YuvPlaneArray planeOffset; }; bool IsYuvFormat(GLenum format); uint32_t GetPlaneCount(GLenum format); uint32_t GetYPlaneBpp(GLenum format); uint32_t GetChromaPlaneBpp(GLenum format); void GetSubSampleFactor(GLenum format, int *horizontalSubsampleFactor, int *verticalSubsampleFactor); } // namespace gl #endif // LIBANGLE_FORMATUTILS_H_