1 //
2 // Copyright 2013 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // formatutils.h: Queries for GL image formats.
8 
9 #ifndef LIBANGLE_FORMATUTILS_H_
10 #define LIBANGLE_FORMATUTILS_H_
11 
12 #include <stdint.h>
13 #include <cstddef>
14 #include <ostream>
15 
16 #include "angle_gl.h"
17 #include "common/android_util.h"
18 #include "libANGLE/Caps.h"
19 #include "libANGLE/Error.h"
20 #include "libANGLE/Version.h"
21 #include "libANGLE/VertexAttribute.h"
22 #include "libANGLE/angletypes.h"
23 
24 namespace gl
25 {
26 struct VertexAttribute;
27 
28 struct FormatType final
29 {
30     FormatType();
31     FormatType(GLenum format_, GLenum type_);
32     FormatType(const FormatType &other) = default;
33     FormatType &operator=(const FormatType &other) = default;
34 
35     bool operator<(const FormatType &other) const;
36 
37     GLenum format;
38     GLenum type;
39 };
40 
41 struct Type
42 {
TypeType43     Type() : bytes(0), bytesShift(0), specialInterpretation(0) {}
44 
TypeType45     explicit Type(uint32_t packedTypeInfo)
46         : bytes(packedTypeInfo & 0xff),
47           bytesShift((packedTypeInfo >> 8) & 0xff),
48           specialInterpretation((packedTypeInfo >> 16) & 1)
49     {}
50 
51     GLuint bytes;
52     GLuint bytesShift;  // Bit shift by this value to effectively divide/multiply by "bytes" in a
53                         // more optimal way
54     bool specialInterpretation;
55 };
56 
57 uint32_t GetPackedTypeInfo(GLenum type);
58 
GetNonLinearFormat(const GLenum format)59 ANGLE_INLINE GLenum GetNonLinearFormat(const GLenum format)
60 {
61     switch (format)
62     {
63         case GL_BGRA8_EXT:
64             return GL_BGRA8_SRGB_ANGLEX;
65         case GL_RGBA8:
66             return GL_SRGB8_ALPHA8;
67         case GL_RGB8:
68         case GL_BGRX8_ANGLEX:
69             return GL_SRGB8;
70         case GL_RGBA16F:
71             return GL_RGBA16F;
72         default:
73             return GL_NONE;
74     }
75 }
76 
ColorspaceFormatOverride(const EGLenum colorspace,GLenum * rendertargetformat)77 ANGLE_INLINE bool ColorspaceFormatOverride(const EGLenum colorspace, GLenum *rendertargetformat)
78 {
79     // Override the rendertargetformat based on colorpsace
80     switch (colorspace)
81     {
82         case EGL_GL_COLORSPACE_LINEAR:                 // linear colorspace no translation needed
83         case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT:       // linear colorspace no translation needed
84         case EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT:  // linear colorspace no translation needed
85         case EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT:  // App, not the HW, will specify the
86                                                             // transfer function
87         case EGL_GL_COLORSPACE_SCRGB_EXT:  // App, not the HW, will specify the transfer function
88             // No translation
89             return true;
90         case EGL_GL_COLORSPACE_SRGB_KHR:
91         case EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
92         {
93             GLenum nonLinearFormat = GetNonLinearFormat(*rendertargetformat);
94             if (nonLinearFormat != GL_NONE)
95             {
96                 *rendertargetformat = nonLinearFormat;
97                 return true;
98             }
99             else
100             {
101                 return false;
102             }
103         }
104         break;
105         default:
106             UNREACHABLE();
107             return false;
108     }
109 }
110 
GetTypeInfo(GLenum type)111 ANGLE_INLINE const Type GetTypeInfo(GLenum type)
112 {
113     return Type(GetPackedTypeInfo(type));
114 }
115 
116 // This helpers use tricks based on the assumption that the type has certain values.
117 static_assert(static_cast<GLuint>(DrawElementsType::UnsignedByte) == 0, "Please update this code.");
118 static_assert(static_cast<GLuint>(DrawElementsType::UnsignedShort) == 1,
119               "Please update this code.");
120 static_assert(static_cast<GLuint>(DrawElementsType::UnsignedInt) == 2, "Please update this code.");
GetDrawElementsTypeSize(DrawElementsType type)121 ANGLE_INLINE GLuint GetDrawElementsTypeSize(DrawElementsType type)
122 {
123     return (1 << static_cast<GLuint>(type));
124 }
125 
GetDrawElementsTypeShift(DrawElementsType type)126 ANGLE_INLINE GLuint GetDrawElementsTypeShift(DrawElementsType type)
127 {
128     return static_cast<GLuint>(type);
129 }
130 
131 // Information about an OpenGL internal format.  Can be keyed on the internalFormat and type
132 // members.
133 struct InternalFormat
134 {
135     InternalFormat();
136     InternalFormat(const InternalFormat &other);
137     InternalFormat &operator=(const InternalFormat &other);
138 
139     GLuint computePixelBytes(GLenum formatType) const;
140 
141     ANGLE_NO_DISCARD bool computeBufferRowLength(uint32_t width, uint32_t *resultOut) const;
142     ANGLE_NO_DISCARD bool computeBufferImageHeight(uint32_t height, uint32_t *resultOut) const;
143 
144     ANGLE_NO_DISCARD bool computeRowPitch(GLenum formatType,
145                                           GLsizei width,
146                                           GLint alignment,
147                                           GLint rowLength,
148                                           GLuint *resultOut) const;
149     ANGLE_NO_DISCARD bool computeDepthPitch(GLsizei height,
150                                             GLint imageHeight,
151                                             GLuint rowPitch,
152                                             GLuint *resultOut) const;
153     ANGLE_NO_DISCARD bool computeDepthPitch(GLenum formatType,
154                                             GLsizei width,
155                                             GLsizei height,
156                                             GLint alignment,
157                                             GLint rowLength,
158                                             GLint imageHeight,
159                                             GLuint *resultOut) const;
160 
161     ANGLE_NO_DISCARD bool computeCompressedImageSize(const Extents &size, GLuint *resultOut) const;
162 
163     ANGLE_NO_DISCARD std::pair<GLuint, GLuint> getCompressedImageMinBlocks() const;
164 
165     ANGLE_NO_DISCARD bool computeSkipBytes(GLenum formatType,
166                                            GLuint rowPitch,
167                                            GLuint depthPitch,
168                                            const PixelStoreStateBase &state,
169                                            bool is3D,
170                                            GLuint *resultOut) const;
171 
172     ANGLE_NO_DISCARD bool computePackUnpackEndByte(GLenum formatType,
173                                                    const Extents &size,
174                                                    const PixelStoreStateBase &state,
175                                                    bool is3D,
176                                                    GLuint *resultOut) const;
177 
178     bool isLUMA() const;
179     GLenum getReadPixelsFormat(const Extensions &extensions) const;
180     GLenum getReadPixelsType(const Version &version) const;
181 
182     // Support upload a portion of image?
183     bool supportSubImage() const;
184 
isChannelSizeCompatibleInternalFormat185     ANGLE_INLINE bool isChannelSizeCompatible(GLuint redSize,
186                                               GLuint greenSize,
187                                               GLuint blueSize,
188                                               GLuint alphaSize) const
189     {
190         // We only check for equality in all channel sizes
191         return ((redSize == redBits) && (greenSize == greenBits) && (blueSize == blueBits) &&
192                 (alphaSize == alphaBits));
193     }
194 
195     // Return true if the format is a required renderbuffer format in the given version of the core
196     // spec. Note that it isn't always clear whether all the rules that apply to core required
197     // renderbuffer formats also apply to additional formats added by extensions. Because of this
198     // extension formats are conservatively not included.
199     bool isRequiredRenderbufferFormat(const Version &version) const;
200 
201     bool isInt() const;
202     bool isDepthOrStencil() const;
203 
204     bool operator==(const InternalFormat &other) const;
205     bool operator!=(const InternalFormat &other) const;
206 
207     GLenum internalFormat;
208 
209     bool sized;
210     GLenum sizedInternalFormat;
211 
212     GLuint redBits;
213     GLuint greenBits;
214     GLuint blueBits;
215 
216     GLuint luminanceBits;
217 
218     GLuint alphaBits;
219     GLuint sharedBits;
220 
221     GLuint depthBits;
222     GLuint stencilBits;
223 
224     GLuint pixelBytes;
225 
226     GLuint componentCount;
227 
228     bool compressed;
229     GLuint compressedBlockWidth;
230     GLuint compressedBlockHeight;
231     GLuint compressedBlockDepth;
232 
233     GLenum format;
234     GLenum type;
235 
236     GLenum componentType;
237     GLenum colorEncoding;
238 
239     typedef bool (*SupportCheckFunction)(const Version &, const Extensions &);
240     SupportCheckFunction textureSupport;
241     SupportCheckFunction filterSupport;
242     SupportCheckFunction textureAttachmentSupport;  // glFramebufferTexture2D
243     SupportCheckFunction renderbufferSupport;       // glFramebufferRenderbuffer
244     SupportCheckFunction blendSupport;
245 };
246 
247 // A "Format" wraps an InternalFormat struct, querying it from either a sized internal format or
248 // unsized internal format and type.
249 // TODO(geofflang): Remove this, it doesn't add any more information than the InternalFormat object.
250 struct Format
251 {
252     // Sized types only.
253     explicit Format(GLenum internalFormat);
254 
255     // Sized or unsized types.
256     explicit Format(const InternalFormat &internalFormat);
257     Format(GLenum internalFormat, GLenum type);
258 
259     Format(const Format &other);
260     Format &operator=(const Format &other);
261 
262     bool valid() const;
263 
264     static Format Invalid();
265     static bool SameSized(const Format &a, const Format &b);
266     static bool EquivalentForBlit(const Format &a, const Format &b);
267 
268     friend std::ostream &operator<<(std::ostream &os, const Format &fmt);
269 
270     // This is the sized info.
271     const InternalFormat *info;
272 };
273 
274 const InternalFormat &GetSizedInternalFormatInfo(GLenum internalFormat);
275 const InternalFormat &GetInternalFormatInfo(GLenum internalFormat, GLenum type);
276 
277 // Strip sizing information from an internal format.  Doesn't necessarily validate that the internal
278 // format is valid.
279 GLenum GetUnsizedFormat(GLenum internalFormat);
280 
281 // Return whether the compressed format requires whole image/mip level to be uploaded to texture.
282 bool CompressedFormatRequiresWholeImage(GLenum internalFormat);
283 
284 // In support of GetImage, check for LUMA formats and override with real format
285 void MaybeOverrideLuminance(GLenum &format, GLenum &type, GLenum actualFormat, GLenum actualType);
286 
287 typedef std::set<GLenum> FormatSet;
288 const FormatSet &GetAllSizedInternalFormats();
289 
290 typedef angle::HashMap<GLenum, angle::HashMap<GLenum, InternalFormat>> InternalFormatInfoMap;
291 const InternalFormatInfoMap &GetInternalFormatMap();
292 
293 int GetAndroidHardwareBufferFormatFromChannelSizes(const egl::AttributeMap &attribMap);
294 
GetNativeVisualID(const InternalFormat & internalFormat)295 ANGLE_INLINE int GetNativeVisualID(const InternalFormat &internalFormat)
296 {
297     int nativeVisualId = 0;
298 #if defined(ANGLE_PLATFORM_ANDROID)
299     nativeVisualId =
300         angle::android::GLInternalFormatToNativePixelFormat(internalFormat.internalFormat);
301 #endif
302     return nativeVisualId;
303 }
304 
305 // From the ESSL 3.00.4 spec:
306 // Vertex shader inputs can only be float, floating-point vectors, matrices, signed and unsigned
307 // integers and integer vectors. Vertex shader inputs cannot be arrays or structures.
308 
309 enum AttributeType
310 {
311     ATTRIBUTE_FLOAT,
312     ATTRIBUTE_VEC2,
313     ATTRIBUTE_VEC3,
314     ATTRIBUTE_VEC4,
315     ATTRIBUTE_INT,
316     ATTRIBUTE_IVEC2,
317     ATTRIBUTE_IVEC3,
318     ATTRIBUTE_IVEC4,
319     ATTRIBUTE_UINT,
320     ATTRIBUTE_UVEC2,
321     ATTRIBUTE_UVEC3,
322     ATTRIBUTE_UVEC4,
323     ATTRIBUTE_MAT2,
324     ATTRIBUTE_MAT3,
325     ATTRIBUTE_MAT4,
326     ATTRIBUTE_MAT2x3,
327     ATTRIBUTE_MAT2x4,
328     ATTRIBUTE_MAT3x2,
329     ATTRIBUTE_MAT3x4,
330     ATTRIBUTE_MAT4x2,
331     ATTRIBUTE_MAT4x3,
332 };
333 
334 AttributeType GetAttributeType(GLenum enumValue);
335 
336 typedef std::vector<angle::FormatID> InputLayout;
337 
338 struct VertexFormat : private angle::NonCopyable
339 {
340     VertexFormat(GLenum typeIn, GLboolean normalizedIn, GLuint componentsIn, bool pureIntegerIn);
341 
342     GLenum type;
343     GLboolean normalized;
344     GLuint components;
345     bool pureInteger;
346 };
347 
348 angle::FormatID GetVertexFormatID(VertexAttribType type,
349                                   GLboolean normalized,
350                                   GLuint components,
351                                   bool pureInteger);
352 
353 angle::FormatID GetVertexFormatID(const VertexAttribute &attrib, VertexAttribType currentValueType);
354 angle::FormatID GetCurrentValueFormatID(VertexAttribType currentValueType);
355 const VertexFormat &GetVertexFormatFromID(angle::FormatID vertexFormatID);
356 size_t GetVertexFormatSize(angle::FormatID vertexFormatID);
357 angle::FormatID ConvertFormatSignedness(const angle::Format &format);
358 
IsS3TCFormat(const GLenum format)359 ANGLE_INLINE bool IsS3TCFormat(const GLenum format)
360 {
361     switch (format)
362     {
363         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
364         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
365         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
366         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
367         case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
368         case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
369         case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
370         case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
371             return true;
372 
373         default:
374             return false;
375     }
376 }
377 
IsRGTCFormat(const GLenum format)378 ANGLE_INLINE bool IsRGTCFormat(const GLenum format)
379 {
380     switch (format)
381     {
382         case GL_COMPRESSED_RED_RGTC1_EXT:
383         case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT:
384         case GL_COMPRESSED_RED_GREEN_RGTC2_EXT:
385         case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
386             return true;
387 
388         default:
389             return false;
390     }
391 }
392 
IsASTC2DFormat(const GLenum format)393 ANGLE_INLINE bool IsASTC2DFormat(const GLenum format)
394 {
395     if ((format >= GL_COMPRESSED_RGBA_ASTC_4x4_KHR &&
396          format <= GL_COMPRESSED_RGBA_ASTC_12x12_KHR) ||
397         (format >= GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR &&
398          format <= GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR))
399     {
400         return true;
401     }
402     return false;
403 }
404 
IsETC2EACFormat(const GLenum format)405 ANGLE_INLINE bool IsETC2EACFormat(const GLenum format)
406 {
407     // ES 3.1, Table 8.19
408     switch (format)
409     {
410         case GL_COMPRESSED_R11_EAC:
411         case GL_COMPRESSED_SIGNED_R11_EAC:
412         case GL_COMPRESSED_RG11_EAC:
413         case GL_COMPRESSED_SIGNED_RG11_EAC:
414         case GL_COMPRESSED_RGB8_ETC2:
415         case GL_COMPRESSED_SRGB8_ETC2:
416         case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
417         case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
418         case GL_COMPRESSED_RGBA8_ETC2_EAC:
419         case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
420             return true;
421 
422         default:
423             return false;
424     }
425 }
426 
IsPVRTC1Format(const GLenum format)427 ANGLE_INLINE bool IsPVRTC1Format(const GLenum format)
428 {
429     switch (format)
430     {
431         case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
432         case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
433         case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
434         case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
435         case GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT:
436         case GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT:
437         case GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT:
438         case GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT:
439             return true;
440 
441         default:
442             return false;
443     }
444 }
445 
446 // Check if an internal format is ever valid in ES3.  Makes no checks about support for a specific
447 // context.
448 bool ValidES3InternalFormat(GLenum internalFormat);
449 
450 // Implemented in format_map_autogen.cpp
451 bool ValidES3Format(GLenum format);
452 bool ValidES3Type(GLenum type);
453 bool ValidES3FormatCombination(GLenum format, GLenum type, GLenum internalFormat);
454 
455 // Implemented in format_map_desktop.cpp
456 bool ValidDesktopFormat(GLenum format);
457 bool ValidDesktopType(GLenum type);
458 bool ValidDesktopFormatCombination(GLenum format, GLenum type, GLenum internalFormat);
459 
460 // Implemented in es3_copy_conversion_table_autogen.cpp
461 bool ValidES3CopyConversion(GLenum textureFormat, GLenum framebufferFormat);
462 
GetVertexAttributeComponentType(bool pureInteger,VertexAttribType type)463 ANGLE_INLINE ComponentType GetVertexAttributeComponentType(bool pureInteger, VertexAttribType type)
464 {
465     if (pureInteger)
466     {
467         switch (type)
468         {
469             case VertexAttribType::Byte:
470             case VertexAttribType::Short:
471             case VertexAttribType::Int:
472                 return ComponentType::Int;
473 
474             case VertexAttribType::UnsignedByte:
475             case VertexAttribType::UnsignedShort:
476             case VertexAttribType::UnsignedInt:
477                 return ComponentType::UnsignedInt;
478 
479             default:
480                 UNREACHABLE();
481                 return ComponentType::NoType;
482         }
483     }
484     else
485     {
486         return ComponentType::Float;
487     }
488 }
489 
490 constexpr std::size_t kMaxYuvPlaneCount = 3;
491 template <typename T>
492 using YuvPlaneArray = std::array<T, kMaxYuvPlaneCount>;
493 
494 struct YuvFormatInfo
495 {
496     // Sized types only.
497     YuvFormatInfo(GLenum internalFormat, const Extents &yPlaneExtent);
498 
499     GLenum glInternalFormat;
500     uint32_t planeCount;
501     YuvPlaneArray<uint32_t> planeBpp;
502     YuvPlaneArray<Extents> planeExtent;
503     YuvPlaneArray<uint32_t> planePitch;
504     YuvPlaneArray<uint32_t> planeSize;
505     YuvPlaneArray<uint32_t> planeOffset;
506 };
507 
508 bool IsYuvFormat(GLenum format);
509 uint32_t GetPlaneCount(GLenum format);
510 uint32_t GetYPlaneBpp(GLenum format);
511 uint32_t GetChromaPlaneBpp(GLenum format);
512 void GetSubSampleFactor(GLenum format,
513                         int *horizontalSubsampleFactor,
514                         int *verticalSubsampleFactor);
515 }  // namespace gl
516 
517 #endif  // LIBANGLE_FORMATUTILS_H_
518