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