• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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