• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2017 The Khronos Group Inc.
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 glcLimitTest.cpp
21 * \brief Definition of template class.
22 */ /*-------------------------------------------------------------------*/
23
24using namespace glw;
25
26template<typename DataType>
27LimitCase<DataType>::LimitCase(deqp::Context& context,
28							   const char* caseName,
29							   deUint32 limitToken,
30							   DataType limitBoundary,
31							   bool isBoundaryMaximum,
32							   const char* glslVersion,
33							   const char* glslBuiltin,
34							   const char* glslExtension)
35	: deqp::TestCase(context, caseName, "Token limit validation.")
36	, m_limitToken(limitToken)
37	, m_limitBoundary(limitBoundary)
38	, m_isBoundaryMaximum(isBoundaryMaximum)
39	, m_glslVersion(glslVersion)
40	, m_glslBuiltin(glslBuiltin)
41	, m_glslExtension(glslExtension)
42{
43	// GL_MAX_FRAGMENT_INTERPOLATION_OFFSET is special in that its limit is dependent on
44	// GL_FRAGMENT_INTERPOLATION_OFFSET_BITS.  Adjust the limit automatically here.
45	adjustBoundaryForMaxFragmentInterpolationOffset();
46}
47
48template<typename DataType>
49LimitCase<DataType>::~LimitCase(void)
50{
51}
52
53template<typename DataType>
54void LimitCase<DataType>::adjustBoundaryForMaxFragmentInterpolationOffset()
55{
56}
57
58template<>
59void LimitCase<GLfloat>::adjustBoundaryForMaxFragmentInterpolationOffset()
60{
61	if (m_limitToken == GL_MAX_FRAGMENT_INTERPOLATION_OFFSET)
62	{
63		const Functions& gl = m_context.getRenderContext().getFunctions();
64
65		GLfloat fragmentInterpolationOffsetBits = 0;
66		gl.getFloatv(GL_FRAGMENT_INTERPOLATION_OFFSET_BITS, &fragmentInterpolationOffsetBits);
67		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv");
68
69		GLfloat ULP = 1.0f / powf(2, fragmentInterpolationOffsetBits);
70		m_limitBoundary -= ULP;
71	}
72}
73
74template<typename DataType>
75tcu::TestNode::IterateResult LimitCase<DataType>::iterate(void)
76{
77	DataType limitValue = DataType();
78	const Functions& gl = m_context.getRenderContext().getFunctions();
79
80	// make sure that limit or builtin was specified
81	DE_ASSERT(m_limitToken || !m_glslBuiltin.empty());
82
83	// check if limit was specified
84	if (m_limitToken)
85	{
86		// check if limit is not smaller or greater then boundary defined in specification
87		limitValue = getLimitValue(gl);
88		if (!isWithinBoundary(limitValue))
89		{
90			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
91			return STOP;
92		}
93
94		// if glsl builtin wasn't defined then test already passed
95		if (m_glslBuiltin.empty())
96		{
97			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
98			return STOP;
99		}
100	}
101
102	// create compute shader to check glsl builtin
103	std::string shaderSource = createShader();
104	const GLchar* source = shaderSource.c_str();
105	const GLuint program = gl.createProgram();
106	GLuint shader = gl.createShader(GL_COMPUTE_SHADER);
107	gl.attachShader(program, shader);
108	gl.deleteShader(shader);
109	gl.shaderSource(shader, 1, &source, NULL);
110	gl.compileShader(shader);
111	gl.linkProgram(program);
112
113	GLint status;
114	gl.getProgramiv(program, GL_LINK_STATUS, &status);
115	GLint length;
116	gl.getProgramiv(program, GL_INFO_LOG_LENGTH, &length);
117	if (length > 1)
118	{
119		std::vector<GLchar> log(length);
120		gl.getProgramInfoLog(program, length, NULL, &log[0]);
121		m_testCtx.getLog() << tcu::TestLog::Message
122						   << &log[0]
123						   << tcu::TestLog::EndMessage;
124	}
125	if (status == GL_FALSE)
126	{
127		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
128		return STOP;
129	}
130
131	gl.useProgram(program);
132
133	GLuint buffer;
134	gl.genBuffers(1, &buffer);
135	gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer);
136	gl.bufferData(GL_SHADER_STORAGE_BUFFER, sizeof(DataType), NULL, GL_DYNAMIC_DRAW);
137	gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
138
139	gl.dispatchCompute(1, 1, 1);
140
141	gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
142	gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
143	DataType* data = static_cast<DataType*>(gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(DataType), GL_MAP_READ_BIT));
144	DataType builtinValue = data[0];
145	gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
146	gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
147
148	if (m_limitToken)
149	{
150		// limit token was specified - compare builtin to it
151		if (isEqual(limitValue, builtinValue))
152		{
153			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
154		}
155		else
156		{
157			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
158			m_testCtx.getLog() << tcu::TestLog::Message
159							   << "Shader builtin has value: "
160							   << builtinValue
161							   << " which is different from the value of corresponding limit: "
162							   << limitValue
163							   << tcu::TestLog::EndMessage;
164		}
165	}
166	else
167	{
168		// limit token was not specified - compare builtin to the boundary
169		if (isWithinBoundary(builtinValue, true))
170		{
171			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
172		}
173		else
174		{
175			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
176			m_testCtx.getLog() << tcu::TestLog::Message
177							   << "Shader builtin value is: "
178							   << builtinValue
179							   << " which is outside of specified boundary."
180							   << tcu::TestLog::EndMessage;
181		}
182	}
183
184	return STOP;
185}
186
187template<typename DataType>
188bool LimitCase<DataType>::isWithinBoundary(DataType value, bool isBuiltin) const
189{
190	if (m_isBoundaryMaximum)
191	{
192		// value should be smaller or euqual to boundary
193		if (isGreater(value, m_limitBoundary))
194		{
195			m_testCtx.getLog() << tcu::TestLog::Message
196							   << (isBuiltin ? "Builtin" : "Limit")
197							   << " value is: "
198							   << value
199							   << " when it should not be greater than "
200							   << m_limitBoundary
201							   << tcu::TestLog::EndMessage;
202			return false;
203		}
204	}
205	else
206	{
207		// value should be greater or euqual to boundary
208		if (isSmaller(value, m_limitBoundary))
209		{
210			m_testCtx.getLog() << tcu::TestLog::Message
211							   << (isBuiltin ? "Builtin" : "Limit")
212							   << " value is: "
213							   << value
214							   << "when it should not be smaller than "
215							   << m_limitBoundary
216							   << tcu::TestLog::EndMessage;
217			return false;
218		}
219	}
220
221	return true;
222}
223
224template<typename DataType>
225std::string LimitCase<DataType>::createShader() const
226{
227		std::stringstream shader;
228		shader << "#version " << m_glslVersion << "\n";
229		if (!m_glslExtension.empty())
230			shader << "#extension " + m_glslExtension + " : require\n";
231		shader << "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
232				  "layout(std430) buffer Output {\n"
233			   << getGLSLDataType() <<" data; } g_out;"
234				  "void main() { "
235				  "g_out.data = " << m_glslBuiltin << "; }";
236		return shader.str();
237}
238
239template<typename DataType>
240std::string LimitCase<DataType>::getGLSLDataType() const
241{
242	return "int";
243}
244
245template<>
246std::string LimitCase<GLfloat>::getGLSLDataType() const
247{
248	return "float";
249}
250
251template<>
252std::string LimitCase<tcu::IVec3>::getGLSLDataType() const
253{
254	return "ivec3";
255}
256
257template<typename DataType>
258bool LimitCase<DataType>::isEqual(DataType a, DataType b) const
259{
260	return a == b;
261}
262
263template<>
264bool LimitCase<tcu::IVec3>::isEqual(tcu::IVec3 a, tcu::IVec3 b) const
265{
266	tcu::BVec3 bVec = tcu::equal(a, b);
267	return tcu::boolAll(bVec);
268}
269
270template<typename DataType>
271bool LimitCase<DataType>::isGreater(DataType a, DataType b) const
272{
273	return a > b;
274}
275
276template<>
277bool LimitCase<tcu::IVec3>::isGreater(tcu::IVec3 a, tcu::IVec3 b) const
278{
279	tcu::BVec3 bVec = tcu::greaterThan(a, b);
280	return tcu::boolAll(bVec);
281}
282
283template<typename DataType>
284bool LimitCase<DataType>::isSmaller(DataType a, DataType b) const
285{
286	return a < b;
287}
288
289template<>
290bool LimitCase<tcu::IVec3>::isSmaller(tcu::IVec3 a, tcu::IVec3 b) const
291{
292	tcu::BVec3 bVec = tcu::lessThan(a, b);
293	return tcu::boolAll(bVec);
294}
295
296template<typename DataType>
297DataType LimitCase<DataType>::getLimitValue(const Functions&) const
298{
299	return DataType();
300}
301
302template<>
303GLint LimitCase<GLint>::getLimitValue(const Functions& gl) const
304{
305	GLint value = -1;
306	gl.getIntegerv(m_limitToken, &value);
307	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv");
308	return value;
309}
310
311template<>
312GLint64 LimitCase<GLint64>::getLimitValue(const Functions& gl) const
313{
314	GLint64 value = -1;
315	gl.getInteger64v(m_limitToken, &value);
316	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInteger64v");
317	return value;
318}
319
320template<>
321GLuint64 LimitCase<GLuint64>::getLimitValue(const Functions& gl) const
322{
323	GLint64 value = -1;
324	gl.getInteger64v(m_limitToken, &value);
325	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInteger64v");
326	return static_cast<GLuint64>(value);
327}
328
329template<>
330GLfloat LimitCase<GLfloat>::getLimitValue(const Functions& gl) const
331{
332	GLfloat value = -1;
333	gl.getFloatv(m_limitToken, &value);
334	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv");
335	return value;
336}
337
338template<>
339tcu::IVec3 LimitCase<tcu::IVec3>::getLimitValue(const Functions& gl) const
340{
341	tcu::IVec3 value(-1);
342	for (int i = 0; i < 3; i++)
343		gl.getIntegeri_v(m_limitToken, (GLuint)i, &value[i]);
344	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegeri_v");
345	return value;
346}
347
348