Home | History | Annotate | Download | only in functional
      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::vector;
     47 using std::string;
     48 using std::set;
     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, deUint32 param);
     57 
     58 // Compare template.
     59 template<typename T>
     60 inline bool compare (const T& min, const T& reported) { return min <= reported; }
     61 
     62 // Types for queries
     63 
     64 struct NegInt
     65 {
     66 	GLint value;
     67 	NegInt (GLint value_) : value(value_) {}
     68 };
     69 
     70 std::ostream& operator<< (std::ostream& str, const NegInt& v) { return str << v.value; }
     71 
     72 struct FloatRange
     73 {
     74 	float min;
     75 	float max;
     76 	FloatRange (float min_, float max_) : min(min_), max(max_) {}
     77 };
     78 
     79 std::ostream& operator<< (std::ostream& str, const FloatRange& range) { return str << range.min << ", " << range.max; }
     80 
     81 struct AlignmentInt
     82 {
     83 	GLint value;
     84 	AlignmentInt (GLint value_) : value(value_) {}
     85 };
     86 
     87 std::ostream& operator<< (std::ostream& str, const AlignmentInt& v) { return str << v.value; }
     88 
     89 // For custom formatting
     90 struct Boolean
     91 {
     92 	GLboolean value;
     93 	Boolean (GLboolean value_) : value(value_) {}
     94 };
     95 
     96 std::ostream& operator<< (std::ostream& str, const Boolean& boolean) { return str << (boolean.value ? "GL_TRUE" : "GL_FALSE"); }
     97 
     98 // Query function implementations.
     99 template<>
    100 GLint query<GLint> (const glw::Functions& gl, deUint32 param)
    101 {
    102 	GLint val = -1;
    103 	gl.getIntegerv(param, &val);
    104 	return val;
    105 }
    106 
    107 template<>
    108 GLint64 query<GLint64> (const glw::Functions& gl, deUint32 param)
    109 {
    110 	GLint64 val = -1;
    111 	gl.getInteger64v(param, &val);
    112 	return val;
    113 }
    114 
    115 template<>
    116 GLuint64 query<GLuint64> (const glw::Functions& gl, deUint32 param)
    117 {
    118 	GLint64 val = 0;
    119 	gl.getInteger64v(param, &val);
    120 	return (GLuint64)val;
    121 }
    122 
    123 template<>
    124 GLfloat query<GLfloat> (const glw::Functions& gl,deUint32 param)
    125 {
    126 	GLfloat val = -1000.f;
    127 	gl.getFloatv(param, &val);
    128 	return val;
    129 }
    130 
    131 template<>
    132 NegInt query<NegInt> (const glw::Functions& gl, deUint32 param)
    133 {
    134 	return NegInt(query<GLint>(gl, param));
    135 }
    136 
    137 template<>
    138 Boolean query<Boolean> (const glw::Functions& gl, deUint32 param)
    139 {
    140 	GLboolean val = GL_FALSE;
    141 	gl.getBooleanv(param, &val);
    142 	return Boolean(val);
    143 }
    144 
    145 template<>
    146 FloatRange query<FloatRange> (const glw::Functions& gl, deUint32 param)
    147 {
    148 	float v[2] = { -1.0f, -1.0f };
    149 	gl.getFloatv(param, &v[0]);
    150 	return FloatRange(v[0], v[1]);
    151 }
    152 
    153 template<>
    154 AlignmentInt query<AlignmentInt> (const glw::Functions& gl, deUint32 param)
    155 {
    156 	return AlignmentInt(query<GLint>(gl, param));
    157 }
    158 
    159 // Special comparison operators
    160 template<>
    161 bool compare<Boolean> (const Boolean& min, const Boolean& reported)
    162 {
    163 	return !min.value || (min.value && reported.value);
    164 }
    165 
    166 template<>
    167 bool compare<NegInt> (const NegInt& min, const NegInt& reported)
    168 {
    169 	// Reverse comparison.
    170 	return reported.value <= min.value;
    171 }
    172 
    173 template<>
    174 bool compare<FloatRange> (const FloatRange& min, const FloatRange& reported)
    175 {
    176 	return reported.min <= min.min && min.max <= reported.max;
    177 }
    178 
    179 template<>
    180 bool compare<AlignmentInt> (const AlignmentInt& min, const AlignmentInt& reported)
    181 {
    182 	// Reverse comparison.
    183 	return reported.value <= min.value;
    184 }
    185 
    186 // Special error descriptions
    187 
    188 enum QueryClass
    189 {
    190 	CLASS_VALUE = 0,
    191 	CLASS_RANGE,
    192 	CLASS_ALIGNMENT,
    193 };
    194 
    195 template <QueryClass Class>
    196 struct QueryClassTraits
    197 {
    198 	static const char* const s_errorDescription;
    199 };
    200 
    201 template <>
    202 const char* const QueryClassTraits<CLASS_VALUE>::s_errorDescription = "reported value is less than minimum required value!";
    203 
    204 template <>
    205 const char* const QueryClassTraits<CLASS_RANGE>::s_errorDescription = "reported range does not contain the minimum required range!";
    206 
    207 template <>
    208 const char* const QueryClassTraits<CLASS_ALIGNMENT>::s_errorDescription = "reported alignment is larger than minimum required aligmnent!";
    209 
    210 template <typename T>
    211 struct QueryTypeTraits
    212 {
    213 };
    214 
    215 template <> struct QueryTypeTraits<GLint>			{	enum { CLASS = CLASS_VALUE };		};
    216 template <> struct QueryTypeTraits<GLint64>			{	enum { CLASS = CLASS_VALUE };		};
    217 template <> struct QueryTypeTraits<GLuint64>		{	enum { CLASS = CLASS_VALUE };		};
    218 template <> struct QueryTypeTraits<GLfloat>			{	enum { CLASS = CLASS_VALUE };		};
    219 template <> struct QueryTypeTraits<Boolean>			{	enum { CLASS = CLASS_VALUE };		};
    220 template <> struct QueryTypeTraits<NegInt>			{	enum { CLASS = CLASS_VALUE };		};
    221 template <> struct QueryTypeTraits<FloatRange>		{	enum { CLASS = CLASS_RANGE };		};
    222 template <> struct QueryTypeTraits<AlignmentInt>	{	enum { CLASS = CLASS_ALIGNMENT };	};
    223 
    224 } // LimitQuery
    225 
    226 using namespace LimitQuery;
    227 using tcu::TestLog;
    228 
    229 template<typename T>
    230 class LimitQueryCase : public TestCase
    231 {
    232 public:
    233 	LimitQueryCase (Context& context, const char* name, const char* description, deUint32 limit, const T& minRequiredValue)
    234 		: TestCase				(context, name, description)
    235 		, m_limit				(limit)
    236 		, m_minRequiredValue	(minRequiredValue)
    237 	{
    238 	}
    239 
    240 	IterateResult iterate (void)
    241 	{
    242 		const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
    243 		const T					value	= query<T>(m_context.getRenderContext().getFunctions(), m_limit);
    244 		GLU_EXPECT_NO_ERROR(gl.getError(), "Query failed");
    245 
    246 		const bool isOk = compare<T>(m_minRequiredValue, value);
    247 
    248 		m_testCtx.getLog() << TestLog::Message << "Reported: " << value << TestLog::EndMessage;
    249 		m_testCtx.getLog() << TestLog::Message << "Minimum required: " << m_minRequiredValue << TestLog::EndMessage;
    250 
    251 		if (!isOk)
    252 			m_testCtx.getLog() << TestLog::Message << "FAIL: " << QueryClassTraits<(QueryClass)QueryTypeTraits<T>::CLASS>::s_errorDescription << TestLog::EndMessage;
    253 
    254 		m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    255 								isOk ? "Pass"				: "Requirement not satisfied");
    256 		return STOP;
    257 	}
    258 
    259 private:
    260 	deUint32	m_limit;
    261 	T			m_minRequiredValue;
    262 };
    263 
    264 static const deUint32 s_requiredCompressedTexFormats[] =
    265 {
    266 	GL_COMPRESSED_R11_EAC,
    267 	GL_COMPRESSED_SIGNED_R11_EAC,
    268 	GL_COMPRESSED_RG11_EAC,
    269 	GL_COMPRESSED_SIGNED_RG11_EAC,
    270 	GL_COMPRESSED_RGB8_ETC2,
    271 	GL_COMPRESSED_SRGB8_ETC2,
    272 	GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
    273 	GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
    274 	GL_COMPRESSED_RGBA8_ETC2_EAC,
    275 	GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC
    276 };
    277 
    278 class CompressedTextureFormatsQueryCase : public TestCase
    279 {
    280 public:
    281 	CompressedTextureFormatsQueryCase (Context& context)
    282 		: TestCase(context, "compressed_texture_formats", "GL_COMPRESSED_TEXTURE_FORMATS")
    283 	{
    284 	}
    285 
    286 	IterateResult iterate (void)
    287 	{
    288 		const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
    289 		const GLint				numFormats		= query<GLint>(gl, GL_NUM_COMPRESSED_TEXTURE_FORMATS);
    290 		vector<GLint>			formats			(numFormats);
    291 		bool					allFormatsOk	= true;
    292 
    293 		if (numFormats > 0)
    294 			gl.getIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, &formats[0]);
    295 
    296 		GLU_EXPECT_NO_ERROR(gl.getError(), "Query failed");
    297 
    298 		// Log formats.
    299 		m_testCtx.getLog() << TestLog::Message << "Reported:" << TestLog::EndMessage;
    300 		for (vector<GLint>::const_iterator fmt = formats.begin(); fmt != formats.end(); fmt++)
    301 			m_testCtx.getLog() << TestLog::Message << glu::getCompressedTextureFormatStr(*fmt) << TestLog::EndMessage;
    302 
    303 		// Check that all required formats are in list.
    304 		{
    305 			set<GLint> formatSet(formats.begin(), formats.end());
    306 
    307 			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_requiredCompressedTexFormats); ndx++)
    308 			{
    309 				const deUint32	fmt		= s_requiredCompressedTexFormats[ndx];
    310 				const bool		found	= formatSet.find(fmt) != formatSet.end();
    311 
    312 				if (!found)
    313 				{
    314 					m_testCtx.getLog() << TestLog::Message << "ERROR: " << glu::getCompressedTextureFormatStr(fmt) << " is missing!" << TestLog::EndMessage;
    315 					allFormatsOk = false;
    316 				}
    317 			}
    318 		}
    319 
    320 		m_testCtx.setTestResult(allFormatsOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    321 								allFormatsOk ? "Pass"				: "Requirement not satisfied");
    322 		return STOP;
    323 	}
    324 };
    325 
    326 static vector<string> queryExtensionsNonIndexed (const glw::Functions& gl)
    327 {
    328 	const string	extensionStr	= (const char*)gl.getString(GL_EXTENSIONS);
    329 	vector<string>	extensionList;
    330 	size_t			pos				= 0;
    331 
    332 	for (;;)
    333 	{
    334 		const size_t	nextPos	= extensionStr.find(' ', pos);
    335 		const size_t	len		= nextPos == string::npos ? extensionStr.length()-pos : nextPos-pos;
    336 
    337 		if (len > 0)
    338 			extensionList.push_back(extensionStr.substr(pos, len));
    339 
    340 		if (nextPos == string::npos)
    341 			break;
    342 		else
    343 			pos = nextPos+1;
    344 	}
    345 
    346 	return extensionList;
    347 }
    348 
    349 static vector<string> queryExtensionsIndexed (const glw::Functions& gl)
    350 {
    351 	const int		numExtensions		= query<GLint>(gl, GL_NUM_EXTENSIONS);
    352 	vector<string>	extensions			(numExtensions);
    353 
    354 	GLU_EXPECT_NO_ERROR(gl.getError(), "GL_NUM_EXTENSIONS query failed");
    355 
    356 	for (int ndx = 0; ndx < numExtensions; ndx++)
    357 		extensions[ndx] = (const char*)gl.getStringi(GL_EXTENSIONS, (GLuint)ndx);
    358 
    359 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetStringi(GL_EXTENSIONS) failed");
    360 
    361 	return extensions;
    362 }
    363 
    364 static bool compareExtensionLists (const vector<string>& a, const vector<string>& b)
    365 {
    366 	if (a.size() != b.size())
    367 		return false;
    368 
    369 	set<string> extsInB(b.begin(), b.end());
    370 
    371 	for (vector<string>::const_iterator i = a.begin(); i != a.end(); ++i)
    372 	{
    373 		if (extsInB.find(*i) == extsInB.end())
    374 			return false;
    375 	}
    376 
    377 	return true;
    378 }
    379 
    380 class ExtensionQueryCase : public TestCase
    381 {
    382 public:
    383 	ExtensionQueryCase (Context& context)
    384 		: TestCase(context, "extensions", "GL_EXTENSIONS")
    385 	{
    386 	}
    387 
    388 	IterateResult iterate (void)
    389 	{
    390 		const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
    391 		const vector<string>	nonIndexedExts		= queryExtensionsNonIndexed(gl);
    392 		const vector<string>	indexedExts			= queryExtensionsIndexed(gl);
    393 		const bool				isOk				= compareExtensionLists(nonIndexedExts, indexedExts);
    394 
    395 		m_testCtx.getLog() << TestLog::Message << "Extensions as reported by glGetStringi(GL_EXTENSIONS):" << TestLog::EndMessage;
    396 		for (vector<string>::const_iterator ext = indexedExts.begin(); ext != indexedExts.end(); ++ext)
    397 			m_testCtx.getLog() << TestLog::Message << *ext << TestLog::EndMessage;
    398 
    399 		if (!isOk)
    400 		{
    401 			m_testCtx.getLog() << TestLog::Message << "Extensions as reported by glGetString(GL_EXTENSIONS):" << TestLog::EndMessage;
    402 			for (vector<string>::const_iterator ext = nonIndexedExts.begin(); ext != nonIndexedExts.end(); ++ext)
    403 				m_testCtx.getLog() << TestLog::Message << *ext << TestLog::EndMessage;
    404 
    405 			m_testCtx.getLog() << TestLog::Message << "ERROR: Extension lists do not match!" << TestLog::EndMessage;
    406 		}
    407 
    408 		m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    409 								isOk ? "Pass"				: "Invalid extension list");
    410 		return STOP;
    411 	}
    412 };
    413 
    414 ImplementationLimitTests::ImplementationLimitTests (Context& context)
    415 	: TestCaseGroup(context, "implementation_limits", "Implementation-defined limits")
    416 {
    417 }
    418 
    419 ImplementationLimitTests::~ImplementationLimitTests (void)
    420 {
    421 }
    422 
    423 void ImplementationLimitTests::init (void)
    424 {
    425 	const int	minVertexUniformBlocks					= 12;
    426 	const int	minVertexUniformComponents				= 1024;
    427 
    428 	const int	minFragmentUniformBlocks				= 12;
    429 	const int	minFragmentUniformComponents			= 896;
    430 
    431 	const int	minUniformBlockSize						= 16384;
    432 	const int	minCombinedVertexUniformComponents		= (minVertexUniformBlocks*minUniformBlockSize)/4 + minVertexUniformComponents;
    433 	const int	minCombinedFragmentUniformComponents	= (minFragmentUniformBlocks*minUniformBlockSize)/4 + minFragmentUniformComponents;
    434 
    435 #define LIMIT_CASE(NAME, PARAM, TYPE, MIN_VAL)	\
    436 	addChild(new LimitQueryCase<TYPE>(m_context, #NAME, #PARAM, PARAM, MIN_VAL))
    437 
    438 	LIMIT_CASE(max_element_index,				GL_MAX_ELEMENT_INDEX,					GLint64,	(1<<24)-1);
    439 	LIMIT_CASE(subpixel_bits,					GL_SUBPIXEL_BITS,						GLint,		4);
    440 	LIMIT_CASE(max_3d_texture_size,				GL_MAX_3D_TEXTURE_SIZE,					GLint,		256);
    441 	LIMIT_CASE(max_texture_size,				GL_MAX_TEXTURE_SIZE,					GLint,		2048);
    442 	LIMIT_CASE(max_array_texture_layers,		GL_MAX_ARRAY_TEXTURE_LAYERS,			GLint,		256);
    443 	LIMIT_CASE(max_texture_lod_bias,			GL_MAX_TEXTURE_LOD_BIAS,				GLfloat,	2.0f);
    444 	LIMIT_CASE(max_cube_map_texture_size,		GL_MAX_CUBE_MAP_TEXTURE_SIZE,			GLint,		2048);
    445 	LIMIT_CASE(max_renderbuffer_size,			GL_MAX_RENDERBUFFER_SIZE,				GLint,		2048);
    446 	LIMIT_CASE(max_draw_buffers,				GL_MAX_DRAW_BUFFERS,					GLint,		4);
    447 	LIMIT_CASE(max_color_attachments,			GL_MAX_COLOR_ATTACHMENTS,				GLint,		4);
    448 	// GL_MAX_VIEWPORT_DIMS
    449 	LIMIT_CASE(aliased_point_size_range,		GL_ALIASED_POINT_SIZE_RANGE,			FloatRange,	FloatRange(1,1));
    450 	LIMIT_CASE(aliased_line_width_range,		GL_ALIASED_LINE_WIDTH_RANGE,			FloatRange,	FloatRange(1,1));
    451 	LIMIT_CASE(max_elements_indices,			GL_MAX_ELEMENTS_INDICES,				GLint,		0);
    452 	LIMIT_CASE(max_elements_vertices,			GL_MAX_ELEMENTS_VERTICES,				GLint,		0);
    453 	LIMIT_CASE(num_compressed_texture_formats,	GL_NUM_COMPRESSED_TEXTURE_FORMATS,		GLint,		DE_LENGTH_OF_ARRAY(s_requiredCompressedTexFormats));
    454 	addChild(new CompressedTextureFormatsQueryCase(m_context)); // GL_COMPRESSED_TEXTURE_FORMATS
    455 	// GL_PROGRAM_BINARY_FORMATS
    456 	LIMIT_CASE(num_program_binary_formats,		GL_NUM_PROGRAM_BINARY_FORMATS,			GLint,		0);
    457 	// GL_SHADER_BINARY_FORMATS
    458 	LIMIT_CASE(num_shader_binary_formats,		GL_NUM_SHADER_BINARY_FORMATS,			GLint,		0);
    459 	LIMIT_CASE(shader_compiler,					GL_SHADER_COMPILER,						Boolean,	GL_TRUE);
    460 	// Shader data type ranges & precisions
    461 	LIMIT_CASE(max_server_wait_timeout,			GL_MAX_SERVER_WAIT_TIMEOUT,				GLuint64,	0);
    462 
    463 	// Version and extension support
    464 	addChild(new ExtensionQueryCase(m_context)); // GL_EXTENSIONS + consistency validation
    465 	LIMIT_CASE(num_extensions,					GL_NUM_EXTENSIONS,						GLint,		0);
    466 	LIMIT_CASE(major_version,					GL_MAJOR_VERSION,						GLint,		3);
    467 	LIMIT_CASE(minor_version,					GL_MINOR_VERSION,						GLint,		0);
    468 	// GL_RENDERER
    469 	// GL_SHADING_LANGUAGE_VERSION
    470 	// GL_VENDOR
    471 	// GL_VERSION
    472 
    473 	// Vertex shader limits
    474 	LIMIT_CASE(max_vertex_attribs,				GL_MAX_VERTEX_ATTRIBS,					GLint,		16);
    475 	LIMIT_CASE(max_vertex_uniform_components,	GL_MAX_VERTEX_UNIFORM_COMPONENTS,		GLint,		minVertexUniformComponents);
    476 	LIMIT_CASE(max_vertex_uniform_vectors,		GL_MAX_VERTEX_UNIFORM_VECTORS,			GLint,		minVertexUniformComponents/4);
    477 	LIMIT_CASE(max_vertex_uniform_blocks,		GL_MAX_VERTEX_UNIFORM_BLOCKS,			GLint,		minVertexUniformBlocks);
    478 	LIMIT_CASE(max_vertex_output_components,	GL_MAX_VERTEX_OUTPUT_COMPONENTS,		GLint,		64);
    479 	LIMIT_CASE(max_vertex_texture_image_units,	GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,		GLint,		16);
    480 
    481 	// Fragment shader limits
    482 	LIMIT_CASE(max_fragment_uniform_components,	GL_MAX_FRAGMENT_UNIFORM_COMPONENTS,		GLint,		minFragmentUniformComponents);
    483 	LIMIT_CASE(max_fragment_uniform_vectors,	GL_MAX_FRAGMENT_UNIFORM_VECTORS,		GLint,		minFragmentUniformComponents/4);
    484 	LIMIT_CASE(max_fragment_uniform_blocks,		GL_MAX_FRAGMENT_UNIFORM_BLOCKS,			GLint,		minFragmentUniformBlocks);
    485 	LIMIT_CASE(max_fragment_input_components,	GL_MAX_FRAGMENT_INPUT_COMPONENTS,		GLint,		60);
    486 	LIMIT_CASE(max_texture_image_units,			GL_MAX_TEXTURE_IMAGE_UNITS,				GLint,		16);
    487 	LIMIT_CASE(min_program_texel_offset,		GL_MIN_PROGRAM_TEXEL_OFFSET,			NegInt,		-8);
    488 	LIMIT_CASE(max_program_texel_offset,		GL_MAX_PROGRAM_TEXEL_OFFSET,			GLint,		7);
    489 
    490 	// Aggregate shader limits
    491 	LIMIT_CASE(max_uniform_buffer_bindings,						GL_MAX_UNIFORM_BUFFER_BINDINGS,						GLint,				24);
    492 	LIMIT_CASE(max_uniform_block_size,							GL_MAX_UNIFORM_BLOCK_SIZE,							GLint64,			minUniformBlockSize);
    493 	LIMIT_CASE(uniform_buffer_offset_alignment,					GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,					AlignmentInt,		256);
    494 	LIMIT_CASE(max_combined_uniform_blocks,						GL_MAX_COMBINED_UNIFORM_BLOCKS,						GLint,				24);
    495 	LIMIT_CASE(max_combined_vertex_uniform_components,			GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS,			GLint64,			minCombinedVertexUniformComponents);
    496 	LIMIT_CASE(max_combined_fragment_uniform_components,		GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS,		GLint64,			minCombinedFragmentUniformComponents);
    497 	LIMIT_CASE(max_varying_components,							GL_MAX_VARYING_COMPONENTS,							GLint,				60);
    498 	LIMIT_CASE(max_varying_vectors,								GL_MAX_VARYING_VECTORS,								GLint,				15);
    499 	LIMIT_CASE(max_combined_texture_image_units,				GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,				GLint,				32);
    500 
    501 	// Transform feedback limits
    502 	LIMIT_CASE(max_transform_feedback_interleaved_components,	GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,	GLint,				64);
    503 	LIMIT_CASE(max_transform_feedback_separate_attribs,			GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,			GLint,				4);
    504 	LIMIT_CASE(max_transform_feedback_separate_components,		GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,		GLint,				4);
    505 }
    506 
    507 } // Functional
    508 } // gles3
    509 } // deqp
    510