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