xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fImplementationLimitTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Implementation-defined limit tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3fImplementationLimitTests.hpp"
25 #include "tcuTestLog.hpp"
26 #include "gluDefs.hpp"
27 #include "gluStrUtil.hpp"
28 #include "gluRenderContext.hpp"
29 
30 #include <vector>
31 #include <set>
32 #include <algorithm>
33 #include <iterator>
34 #include <limits>
35 
36 #include "glwEnums.hpp"
37 #include "glwFunctions.hpp"
38 
39 namespace deqp
40 {
41 namespace gles3
42 {
43 namespace Functional
44 {
45 
46 using std::set;
47 using std::string;
48 using std::vector;
49 using namespace glw; // GL types
50 
51 namespace LimitQuery
52 {
53 
54 // Query function template.
55 template <typename T>
56 T query(const glw::Functions &gl, uint32_t param);
57 
58 // Compare template.
59 template <typename T>
compare(const T & min,const T & reported)60 inline bool compare(const T &min, const T &reported)
61 {
62     return min <= reported;
63 }
64 
65 // Types for queries
66 
67 struct NegInt
68 {
69     GLint value;
NegIntdeqp::gles3::Functional::LimitQuery::NegInt70     NegInt(GLint value_) : value(value_)
71     {
72     }
73 };
74 
operator <<(std::ostream & str,const NegInt & v)75 std::ostream &operator<<(std::ostream &str, const NegInt &v)
76 {
77     return str << v.value;
78 }
79 
80 struct FloatRange
81 {
82     float min;
83     float max;
FloatRangedeqp::gles3::Functional::LimitQuery::FloatRange84     FloatRange(float min_, float max_) : min(min_), max(max_)
85     {
86     }
87 };
88 
operator <<(std::ostream & str,const FloatRange & range)89 std::ostream &operator<<(std::ostream &str, const FloatRange &range)
90 {
91     return str << range.min << ", " << range.max;
92 }
93 
94 struct AlignmentInt
95 {
96     GLint value;
AlignmentIntdeqp::gles3::Functional::LimitQuery::AlignmentInt97     AlignmentInt(GLint value_) : value(value_)
98     {
99     }
100 };
101 
operator <<(std::ostream & str,const AlignmentInt & v)102 std::ostream &operator<<(std::ostream &str, const AlignmentInt &v)
103 {
104     return str << v.value;
105 }
106 
107 // For custom formatting
108 struct Boolean
109 {
110     GLboolean value;
Booleandeqp::gles3::Functional::LimitQuery::Boolean111     Boolean(GLboolean value_) : value(value_)
112     {
113     }
114 };
115 
operator <<(std::ostream & str,const Boolean & boolean)116 std::ostream &operator<<(std::ostream &str, const Boolean &boolean)
117 {
118     return str << (boolean.value ? "GL_TRUE" : "GL_FALSE");
119 }
120 
121 // Query function implementations.
122 template <>
query(const glw::Functions & gl,uint32_t param)123 GLint query<GLint>(const glw::Functions &gl, uint32_t param)
124 {
125     GLint val = -1;
126     gl.getIntegerv(param, &val);
127     return val;
128 }
129 
130 template <>
query(const glw::Functions & gl,uint32_t param)131 GLint64 query<GLint64>(const glw::Functions &gl, uint32_t param)
132 {
133     GLint64 val = -1;
134     gl.getInteger64v(param, &val);
135     return val;
136 }
137 
138 template <>
query(const glw::Functions & gl,uint32_t param)139 GLuint64 query<GLuint64>(const glw::Functions &gl, uint32_t param)
140 {
141     GLint64 val = 0;
142     gl.getInteger64v(param, &val);
143     return (GLuint64)val;
144 }
145 
146 template <>
query(const glw::Functions & gl,uint32_t param)147 GLfloat query<GLfloat>(const glw::Functions &gl, uint32_t param)
148 {
149     GLfloat val = -1000.f;
150     gl.getFloatv(param, &val);
151     return val;
152 }
153 
154 template <>
query(const glw::Functions & gl,uint32_t param)155 NegInt query<NegInt>(const glw::Functions &gl, uint32_t param)
156 {
157     return NegInt(query<GLint>(gl, param));
158 }
159 
160 template <>
query(const glw::Functions & gl,uint32_t param)161 Boolean query<Boolean>(const glw::Functions &gl, uint32_t param)
162 {
163     GLboolean val = GL_FALSE;
164     gl.getBooleanv(param, &val);
165     return Boolean(val);
166 }
167 
168 template <>
query(const glw::Functions & gl,uint32_t param)169 FloatRange query<FloatRange>(const glw::Functions &gl, uint32_t param)
170 {
171     float v[2] = {-1.0f, -1.0f};
172     gl.getFloatv(param, &v[0]);
173     return FloatRange(v[0], v[1]);
174 }
175 
176 template <>
query(const glw::Functions & gl,uint32_t param)177 AlignmentInt query<AlignmentInt>(const glw::Functions &gl, uint32_t param)
178 {
179     return AlignmentInt(query<GLint>(gl, param));
180 }
181 
182 // Special comparison operators
183 template <>
compare(const Boolean & min,const Boolean & reported)184 bool compare<Boolean>(const Boolean &min, const Boolean &reported)
185 {
186     return !min.value || (min.value && reported.value);
187 }
188 
189 template <>
compare(const NegInt & min,const NegInt & reported)190 bool compare<NegInt>(const NegInt &min, const NegInt &reported)
191 {
192     // Reverse comparison.
193     return reported.value <= min.value;
194 }
195 
196 template <>
compare(const FloatRange & min,const FloatRange & reported)197 bool compare<FloatRange>(const FloatRange &min, const FloatRange &reported)
198 {
199     return reported.min <= min.min && min.max <= reported.max;
200 }
201 
202 template <>
compare(const AlignmentInt & min,const AlignmentInt & reported)203 bool compare<AlignmentInt>(const AlignmentInt &min, const AlignmentInt &reported)
204 {
205     // Reverse comparison.
206     return reported.value <= min.value;
207 }
208 
209 // Special error descriptions
210 
211 enum QueryClass
212 {
213     CLASS_VALUE = 0,
214     CLASS_RANGE,
215     CLASS_ALIGNMENT,
216 };
217 
218 template <QueryClass Class>
219 struct QueryClassTraits
220 {
221     static const char *const s_errorDescription;
222 };
223 
224 template <>
225 const char *const QueryClassTraits<CLASS_VALUE>::s_errorDescription =
226     "reported value is less than minimum required value!";
227 
228 template <>
229 const char *const QueryClassTraits<CLASS_RANGE>::s_errorDescription =
230     "reported range does not contain the minimum required range!";
231 
232 template <>
233 const char *const QueryClassTraits<CLASS_ALIGNMENT>::s_errorDescription =
234     "reported alignment is larger than minimum required aligmnent!";
235 
236 template <typename T>
237 struct QueryTypeTraits
238 {
239 };
240 
241 template <>
242 struct QueryTypeTraits<GLint>
243 {
244     enum
245     {
246         CLASS = CLASS_VALUE
247     };
248 };
249 template <>
250 struct QueryTypeTraits<GLint64>
251 {
252     enum
253     {
254         CLASS = CLASS_VALUE
255     };
256 };
257 template <>
258 struct QueryTypeTraits<GLuint64>
259 {
260     enum
261     {
262         CLASS = CLASS_VALUE
263     };
264 };
265 template <>
266 struct QueryTypeTraits<GLfloat>
267 {
268     enum
269     {
270         CLASS = CLASS_VALUE
271     };
272 };
273 template <>
274 struct QueryTypeTraits<Boolean>
275 {
276     enum
277     {
278         CLASS = CLASS_VALUE
279     };
280 };
281 template <>
282 struct QueryTypeTraits<NegInt>
283 {
284     enum
285     {
286         CLASS = CLASS_VALUE
287     };
288 };
289 template <>
290 struct QueryTypeTraits<FloatRange>
291 {
292     enum
293     {
294         CLASS = CLASS_RANGE
295     };
296 };
297 template <>
298 struct QueryTypeTraits<AlignmentInt>
299 {
300     enum
301     {
302         CLASS = CLASS_ALIGNMENT
303     };
304 };
305 
306 } // namespace LimitQuery
307 
308 using namespace LimitQuery;
309 using tcu::TestLog;
310 
311 template <typename T>
312 class LimitQueryCase : public TestCase
313 {
314 public:
LimitQueryCase(Context & context,const char * name,const char * description,uint32_t limit,const T & minRequiredValue)315     LimitQueryCase(Context &context, const char *name, const char *description, uint32_t limit,
316                    const T &minRequiredValue)
317         : TestCase(context, name, description)
318         , m_limit(limit)
319         , m_minRequiredValue(minRequiredValue)
320     {
321     }
322 
iterate(void)323     IterateResult iterate(void)
324     {
325         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
326         const T value            = query<T>(m_context.getRenderContext().getFunctions(), m_limit);
327         GLU_EXPECT_NO_ERROR(gl.getError(), "Query failed");
328 
329         const bool isOk = compare<T>(m_minRequiredValue, value);
330 
331         m_testCtx.getLog() << TestLog::Message << "Reported: " << value << TestLog::EndMessage;
332         m_testCtx.getLog() << TestLog::Message << "Minimum required: " << m_minRequiredValue << TestLog::EndMessage;
333 
334         if (!isOk)
335             m_testCtx.getLog() << TestLog::Message << "FAIL: "
336                                << QueryClassTraits<(QueryClass)QueryTypeTraits<T>::CLASS>::s_errorDescription
337                                << TestLog::EndMessage;
338 
339         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
340                                 isOk ? "Pass" : "Requirement not satisfied");
341         return STOP;
342     }
343 
344 private:
345     uint32_t m_limit;
346     T m_minRequiredValue;
347 };
348 
349 static const uint32_t s_requiredCompressedTexFormats[] = {GL_COMPRESSED_R11_EAC,
350                                                           GL_COMPRESSED_SIGNED_R11_EAC,
351                                                           GL_COMPRESSED_RG11_EAC,
352                                                           GL_COMPRESSED_SIGNED_RG11_EAC,
353                                                           GL_COMPRESSED_RGB8_ETC2,
354                                                           GL_COMPRESSED_SRGB8_ETC2,
355                                                           GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
356                                                           GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
357                                                           GL_COMPRESSED_RGBA8_ETC2_EAC,
358                                                           GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC};
359 
360 class CompressedTextureFormatsQueryCase : public TestCase
361 {
362 public:
CompressedTextureFormatsQueryCase(Context & context)363     CompressedTextureFormatsQueryCase(Context &context)
364         : TestCase(context, "compressed_texture_formats", "GL_COMPRESSED_TEXTURE_FORMATS")
365     {
366     }
367 
iterate(void)368     IterateResult iterate(void)
369     {
370         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
371         const GLint numFormats   = query<GLint>(gl, GL_NUM_COMPRESSED_TEXTURE_FORMATS);
372         vector<GLint> formats(numFormats);
373         bool allFormatsOk = true;
374 
375         if (numFormats > 0)
376             gl.getIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, &formats[0]);
377 
378         GLU_EXPECT_NO_ERROR(gl.getError(), "Query failed");
379 
380         // Log formats.
381         m_testCtx.getLog() << TestLog::Message << "Reported:" << TestLog::EndMessage;
382         for (vector<GLint>::const_iterator fmt = formats.begin(); fmt != formats.end(); fmt++)
383             m_testCtx.getLog() << TestLog::Message << glu::getCompressedTextureFormatStr(*fmt) << TestLog::EndMessage;
384 
385         // Check that all required formats are in list.
386         {
387             set<GLint> formatSet(formats.begin(), formats.end());
388 
389             for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_requiredCompressedTexFormats); ndx++)
390             {
391                 const uint32_t fmt = s_requiredCompressedTexFormats[ndx];
392                 const bool found   = formatSet.find(fmt) != formatSet.end();
393 
394                 if (!found)
395                 {
396                     m_testCtx.getLog() << TestLog::Message << "ERROR: " << glu::getCompressedTextureFormatStr(fmt)
397                                        << " is missing!" << TestLog::EndMessage;
398                     allFormatsOk = false;
399                 }
400             }
401         }
402 
403         m_testCtx.setTestResult(allFormatsOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
404                                 allFormatsOk ? "Pass" : "Requirement not satisfied");
405         return STOP;
406     }
407 };
408 
queryExtensionsNonIndexed(const glw::Functions & gl)409 static vector<string> queryExtensionsNonIndexed(const glw::Functions &gl)
410 {
411     const string extensionStr = (const char *)gl.getString(GL_EXTENSIONS);
412     vector<string> extensionList;
413     size_t pos = 0;
414 
415     for (;;)
416     {
417         const size_t nextPos = extensionStr.find(' ', pos);
418         const size_t len     = nextPos == string::npos ? extensionStr.length() - pos : nextPos - pos;
419 
420         if (len > 0)
421             extensionList.push_back(extensionStr.substr(pos, len));
422 
423         if (nextPos == string::npos)
424             break;
425         else
426             pos = nextPos + 1;
427     }
428 
429     return extensionList;
430 }
431 
queryExtensionsIndexed(const glw::Functions & gl)432 static vector<string> queryExtensionsIndexed(const glw::Functions &gl)
433 {
434     const int numExtensions = query<GLint>(gl, GL_NUM_EXTENSIONS);
435     vector<string> extensions(numExtensions);
436 
437     GLU_EXPECT_NO_ERROR(gl.getError(), "GL_NUM_EXTENSIONS query failed");
438 
439     for (int ndx = 0; ndx < numExtensions; ndx++)
440         extensions[ndx] = (const char *)gl.getStringi(GL_EXTENSIONS, (GLuint)ndx);
441 
442     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetStringi(GL_EXTENSIONS) failed");
443 
444     return extensions;
445 }
446 
compareExtensionLists(const vector<string> & a,const vector<string> & b)447 static bool compareExtensionLists(const vector<string> &a, const vector<string> &b)
448 {
449     if (a.size() != b.size())
450         return false;
451 
452     set<string> extsInB(b.begin(), b.end());
453 
454     for (vector<string>::const_iterator i = a.begin(); i != a.end(); ++i)
455     {
456         if (extsInB.find(*i) == extsInB.end())
457             return false;
458     }
459 
460     return true;
461 }
462 
463 class ExtensionQueryCase : public TestCase
464 {
465 public:
ExtensionQueryCase(Context & context)466     ExtensionQueryCase(Context &context) : TestCase(context, "extensions", "GL_EXTENSIONS")
467     {
468     }
469 
iterate(void)470     IterateResult iterate(void)
471     {
472         const glw::Functions &gl            = m_context.getRenderContext().getFunctions();
473         const vector<string> nonIndexedExts = queryExtensionsNonIndexed(gl);
474         const vector<string> indexedExts    = queryExtensionsIndexed(gl);
475         const bool isOk                     = compareExtensionLists(nonIndexedExts, indexedExts);
476 
477         m_testCtx.getLog() << TestLog::Message
478                            << "Extensions as reported by glGetStringi(GL_EXTENSIONS):" << TestLog::EndMessage;
479         for (vector<string>::const_iterator ext = indexedExts.begin(); ext != indexedExts.end(); ++ext)
480             m_testCtx.getLog() << TestLog::Message << *ext << TestLog::EndMessage;
481 
482         if (!isOk)
483         {
484             m_testCtx.getLog() << TestLog::Message
485                                << "Extensions as reported by glGetString(GL_EXTENSIONS):" << TestLog::EndMessage;
486             for (vector<string>::const_iterator ext = nonIndexedExts.begin(); ext != nonIndexedExts.end(); ++ext)
487                 m_testCtx.getLog() << TestLog::Message << *ext << TestLog::EndMessage;
488 
489             m_testCtx.getLog() << TestLog::Message << "ERROR: Extension lists do not match!" << TestLog::EndMessage;
490         }
491 
492         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
493                                 isOk ? "Pass" : "Invalid extension list");
494         return STOP;
495     }
496 };
497 
ImplementationLimitTests(Context & context)498 ImplementationLimitTests::ImplementationLimitTests(Context &context)
499     : TestCaseGroup(context, "implementation_limits", "Implementation-defined limits")
500 {
501 }
502 
~ImplementationLimitTests(void)503 ImplementationLimitTests::~ImplementationLimitTests(void)
504 {
505 }
506 
init(void)507 void ImplementationLimitTests::init(void)
508 {
509     const int minVertexUniformBlocks     = 12;
510     const int minVertexUniformComponents = 1024;
511 
512     const int minFragmentUniformBlocks     = 12;
513     const int minFragmentUniformComponents = 896;
514 
515     const int minUniformBlockSize = 16384;
516     const int minCombinedVertexUniformComponents =
517         (minVertexUniformBlocks * minUniformBlockSize) / 4 + minVertexUniformComponents;
518     const int minCombinedFragmentUniformComponents =
519         (minFragmentUniformBlocks * minUniformBlockSize) / 4 + minFragmentUniformComponents;
520 
521 #define LIMIT_CASE(NAME, PARAM, TYPE, MIN_VAL) \
522     addChild(new LimitQueryCase<TYPE>(m_context, #NAME, #PARAM, PARAM, MIN_VAL))
523 
524     LIMIT_CASE(max_element_index, GL_MAX_ELEMENT_INDEX, GLint64, (1 << 24) - 1);
525     LIMIT_CASE(subpixel_bits, GL_SUBPIXEL_BITS, GLint, 4);
526     LIMIT_CASE(max_3d_texture_size, GL_MAX_3D_TEXTURE_SIZE, GLint, 256);
527     LIMIT_CASE(max_texture_size, GL_MAX_TEXTURE_SIZE, GLint, 2048);
528     LIMIT_CASE(max_array_texture_layers, GL_MAX_ARRAY_TEXTURE_LAYERS, GLint, 256);
529     LIMIT_CASE(max_texture_lod_bias, GL_MAX_TEXTURE_LOD_BIAS, GLfloat, 2.0f);
530     LIMIT_CASE(max_cube_map_texture_size, GL_MAX_CUBE_MAP_TEXTURE_SIZE, GLint, 2048);
531     LIMIT_CASE(max_renderbuffer_size, GL_MAX_RENDERBUFFER_SIZE, GLint, 2048);
532     LIMIT_CASE(max_draw_buffers, GL_MAX_DRAW_BUFFERS, GLint, 4);
533     LIMIT_CASE(max_color_attachments, GL_MAX_COLOR_ATTACHMENTS, GLint, 4);
534     // GL_MAX_VIEWPORT_DIMS
535     LIMIT_CASE(aliased_point_size_range, GL_ALIASED_POINT_SIZE_RANGE, FloatRange, FloatRange(1, 1));
536     LIMIT_CASE(aliased_line_width_range, GL_ALIASED_LINE_WIDTH_RANGE, FloatRange, FloatRange(1, 1));
537     LIMIT_CASE(max_elements_indices, GL_MAX_ELEMENTS_INDICES, GLint, 0);
538     LIMIT_CASE(max_elements_vertices, GL_MAX_ELEMENTS_VERTICES, GLint, 0);
539     LIMIT_CASE(num_compressed_texture_formats, GL_NUM_COMPRESSED_TEXTURE_FORMATS, GLint,
540                DE_LENGTH_OF_ARRAY(s_requiredCompressedTexFormats));
541     addChild(new CompressedTextureFormatsQueryCase(m_context)); // GL_COMPRESSED_TEXTURE_FORMATS
542     // GL_PROGRAM_BINARY_FORMATS
543     LIMIT_CASE(num_program_binary_formats, GL_NUM_PROGRAM_BINARY_FORMATS, GLint, 0);
544     // GL_SHADER_BINARY_FORMATS
545     LIMIT_CASE(num_shader_binary_formats, GL_NUM_SHADER_BINARY_FORMATS, GLint, 0);
546     LIMIT_CASE(shader_compiler, GL_SHADER_COMPILER, Boolean, GL_TRUE);
547     // Shader data type ranges & precisions
548     LIMIT_CASE(max_server_wait_timeout, GL_MAX_SERVER_WAIT_TIMEOUT, GLuint64, 0);
549 
550     // Version and extension support
551     addChild(new ExtensionQueryCase(m_context)); // GL_EXTENSIONS + consistency validation
552     LIMIT_CASE(num_extensions, GL_NUM_EXTENSIONS, GLint, 0);
553     LIMIT_CASE(major_version, GL_MAJOR_VERSION, GLint, 3);
554     LIMIT_CASE(minor_version, GL_MINOR_VERSION, GLint, 0);
555     // GL_RENDERER
556     // GL_SHADING_LANGUAGE_VERSION
557     // GL_VENDOR
558     // GL_VERSION
559 
560     // Vertex shader limits
561     LIMIT_CASE(max_vertex_attribs, GL_MAX_VERTEX_ATTRIBS, GLint, 16);
562     LIMIT_CASE(max_vertex_uniform_components, GL_MAX_VERTEX_UNIFORM_COMPONENTS, GLint, minVertexUniformComponents);
563     LIMIT_CASE(max_vertex_uniform_vectors, GL_MAX_VERTEX_UNIFORM_VECTORS, GLint, minVertexUniformComponents / 4);
564     LIMIT_CASE(max_vertex_uniform_blocks, GL_MAX_VERTEX_UNIFORM_BLOCKS, GLint, minVertexUniformBlocks);
565     LIMIT_CASE(max_vertex_output_components, GL_MAX_VERTEX_OUTPUT_COMPONENTS, GLint, 64);
566     LIMIT_CASE(max_vertex_texture_image_units, GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, GLint, 16);
567 
568     // Fragment shader limits
569     LIMIT_CASE(max_fragment_uniform_components, GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, GLint,
570                minFragmentUniformComponents);
571     LIMIT_CASE(max_fragment_uniform_vectors, GL_MAX_FRAGMENT_UNIFORM_VECTORS, GLint, minFragmentUniformComponents / 4);
572     LIMIT_CASE(max_fragment_uniform_blocks, GL_MAX_FRAGMENT_UNIFORM_BLOCKS, GLint, minFragmentUniformBlocks);
573     LIMIT_CASE(max_fragment_input_components, GL_MAX_FRAGMENT_INPUT_COMPONENTS, GLint, 60);
574     LIMIT_CASE(max_texture_image_units, GL_MAX_TEXTURE_IMAGE_UNITS, GLint, 16);
575     LIMIT_CASE(min_program_texel_offset, GL_MIN_PROGRAM_TEXEL_OFFSET, NegInt, -8);
576     LIMIT_CASE(max_program_texel_offset, GL_MAX_PROGRAM_TEXEL_OFFSET, GLint, 7);
577 
578     // Aggregate shader limits
579     LIMIT_CASE(max_uniform_buffer_bindings, GL_MAX_UNIFORM_BUFFER_BINDINGS, GLint, 24);
580     LIMIT_CASE(max_uniform_block_size, GL_MAX_UNIFORM_BLOCK_SIZE, GLint64, minUniformBlockSize);
581     LIMIT_CASE(uniform_buffer_offset_alignment, GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, AlignmentInt, 256);
582     LIMIT_CASE(max_combined_uniform_blocks, GL_MAX_COMBINED_UNIFORM_BLOCKS, GLint, 24);
583     LIMIT_CASE(max_combined_vertex_uniform_components, GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, GLint64,
584                minCombinedVertexUniformComponents);
585     LIMIT_CASE(max_combined_fragment_uniform_components, GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, GLint64,
586                minCombinedFragmentUniformComponents);
587     LIMIT_CASE(max_varying_components, GL_MAX_VARYING_COMPONENTS, GLint, 60);
588     LIMIT_CASE(max_varying_vectors, GL_MAX_VARYING_VECTORS, GLint, 15);
589     LIMIT_CASE(max_combined_texture_image_units, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, GLint, 32);
590 
591     // Transform feedback limits
592     LIMIT_CASE(max_transform_feedback_interleaved_components, GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, GLint,
593                64);
594     LIMIT_CASE(max_transform_feedback_separate_attribs, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, GLint, 4);
595     LIMIT_CASE(max_transform_feedback_separate_components, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, GLint, 4);
596 }
597 
598 } // namespace Functional
599 } // namespace gles3
600 } // namespace deqp
601