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