• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2016 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
21  * \brief
22  */ /*-------------------------------------------------------------------*/
23 
24 /**
25  */ /*!
26  * \file  gl4cSparseTextureClampTests.cpp
27  * \brief Conformance tests for the GL_ARB_sparse_texture2 functionality.
28  */ /*-------------------------------------------------------------------*/
29 
30 #include "gl4cSparseTextureClampTests.hpp"
31 #include "deStringUtil.hpp"
32 #include "gl4cSparseTexture2Tests.hpp"
33 #include "gl4cSparseTextureTests.hpp"
34 #include "gluContextInfo.hpp"
35 #include "gluDefs.hpp"
36 #include "glwEnums.hpp"
37 #include "glwFunctions.hpp"
38 #include "tcuImageIO.hpp"
39 #include "tcuTestLog.hpp"
40 
41 #include <cmath>
42 #include <string.h>
43 #include <vector>
44 
45 using namespace glw;
46 using namespace glu;
47 
48 namespace gl4cts
49 {
50 
51 const char* stc_compute_textureFill = "#version 430 core\n"
52 									  "\n"
53 									  "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
54 									  "\n"
55 									  "layout (location = 1) writeonly uniform highp <INPUT_TYPE> uni_image;\n"
56 									  "\n"
57 									  "void main()\n"
58 									  "{\n"
59 									  "    <POINT_TYPE> point = <POINT_TYPE>(<POINT_DEF>);\n"
60 									  "    memoryBarrier();\n"
61 									  "    <RETURN_TYPE> color = <RETURN_TYPE><RESULT_EXPECTED>;\n"
62 									  "    imageStore(uni_image, point<SAMPLE_DEF>, color);\n"
63 									  "}\n";
64 
65 const char* stc_vertex_common = "#version 450\n"
66 								"\n"
67 								"in vec3 vertex;\n"
68 								"in <COORD_TYPE> inCoord;\n"
69 								"out <COORD_TYPE> texCoord;\n"
70 								"\n"
71 								"void main()\n"
72 								"{\n"
73 								"    texCoord = inCoord;\n"
74 								"    gl_Position = vec4(vertex, 1);\n"
75 								"}\n";
76 
77 const char* stc_fragment_lookupResidency = "#version 450 core\n"
78 										   "\n"
79 										   "#extension GL_ARB_sparse_texture2 : enable\n"
80 										   "#extension GL_ARB_sparse_texture_clamp : enable\n"
81 										   "\n"
82 										   "in <COORD_TYPE> texCoord;\n"
83 										   "out vec4 fragColor;\n"
84 										   "\n"
85 										   "layout (location = 1<FORMAT_DEF>) uniform <INPUT_TYPE> uni_in;\n"
86 										   "layout (location = 2) uniform int widthCommitted;\n"
87 										   "\n"
88 										   "void main()\n"
89 										   "{\n"
90 										   "    <COORD_TYPE> coord = texCoord;\n"
91 										   "    <ICOORD_TYPE> texSize = <ICOORD_TYPE>(<SIZE_DEF>);\n"
92 										   "    <POINT_TYPE> point = <POINT_TYPE>(coord * texSize);\n"
93 										   "    <RETURN_TYPE> retValue,\n"
94 										   "                  expValue,\n"
95 										   "                  epsilon;\n"
96 										   "    retValue = <RETURN_TYPE>(0);\n"
97 										   "    expValue = <RETURN_TYPE><RESULT_EXPECTED>;\n"
98 										   "    epsilon = <RETURN_TYPE>(<EPSILON>);\n"
99 										   "\n"
100 										   "<CUBE_MAP_COORD_DEF>\n"
101 										   "<OFFSET_ARRAY_DEF>\n"
102 										   "\n"
103 										   "    ivec2 corner1 = ivec2(1, 1);\n"
104 										   "    ivec2 corner2 = ivec2(texSize.x - 1, texSize.y - 1);\n"
105 										   "\n"
106 										   "    int code = <FUNCTION>(uni_in,\n"
107 										   "                          <POINT_COORD><SAMPLE_DEF><ARGUMENTS>,\n"
108 										   "                          retValue<COMPONENT_DEF>);\n"
109 										   "\n"
110 										   "    fragColor = vec4(1);\n"
111 										   "\n"
112 										   "    if (point.x > corner1.x && point.y > corner1.y &&\n"
113 										   "        point.x < corner2.x && point.y < corner2.y &&\n"
114 										   "        point.x < widthCommitted - 1)\n"
115 										   "    {\n"
116 										   "        if (!sparseTexelsResidentARB(code) ||\n"
117 										   "            any(greaterThan(retValue, expValue + epsilon)) ||\n"
118 										   "            any(lessThan(retValue, expValue - epsilon)))\n"
119 										   "        {\n"
120 										   "            fragColor = vec4(0);\n"
121 										   "        }\n"
122 										   "    }\n"
123 										   "\n"
124 										   "    if (point.x > corner1.x && point.y > corner1.y &&\n"
125 										   "        point.x < corner2.x && point.y < corner2.y &&\n"
126 										   "        point.x >= widthCommitted + 1)\n"
127 										   "    {\n"
128 										   "        if (sparseTexelsResidentARB(code))\n"
129 										   "        {\n"
130 										   "            fragColor = vec4(0);\n"
131 										   "        }\n"
132 										   "    }\n"
133 										   "}\n";
134 
135 const char* stc_fragment_lookupColor = "#version 450 core\n"
136 									   "\n"
137 									   "#extension GL_ARB_sparse_texture2 : enable\n"
138 									   "#extension GL_ARB_sparse_texture_clamp : enable\n"
139 									   "\n"
140 									   "in <COORD_TYPE> texCoord;\n"
141 									   "out vec4 fragColor;\n"
142 									   "\n"
143 									   "layout (location = 1<FORMAT_DEF>) uniform <INPUT_TYPE> uni_in;\n"
144 									   "\n"
145 									   "void main()\n"
146 									   "{\n"
147 									   "    <COORD_TYPE> coord = texCoord;\n"
148 									   "    <ICOORD_TYPE> texSize = <ICOORD_TYPE>(<SIZE_DEF>);\n"
149 									   "    <POINT_TYPE> point = <POINT_TYPE>(coord * texSize);\n"
150 									   "    <RETURN_TYPE> retValue,\n"
151 									   "                  expValue,\n"
152 									   "                  epsilon;\n"
153 									   "    retValue = <RETURN_TYPE>(0);\n"
154 									   "    expValue = <RETURN_TYPE><RESULT_EXPECTED>;\n"
155 									   "    epsilon = <RETURN_TYPE>(<EPSILON>);\n"
156 									   "\n"
157 									   "<CUBE_MAP_COORD_DEF>\n"
158 									   "<OFFSET_ARRAY_DEF>\n"
159 									   "\n"
160 									   "<FUNCTION_DEF>\n"
161 									   "\n"
162 									   "    fragColor = vec4(1);\n"
163 									   "\n"
164 									   "    if (any(greaterThan(retValue, expValue + epsilon)) ||\n"
165 									   "        any(lessThan(retValue, expValue - epsilon)))\n"
166 									   "    {\n"
167 									   "        fragColor = vec4(0);\n"
168 									   "    }\n"
169 									   "}\n";
170 
171 /** Constructor.
172  *
173  *  @param context     Rendering context
174  */
SparseTextureClampLookupResidencyTestCase(deqp::Context & context)175 SparseTextureClampLookupResidencyTestCase::SparseTextureClampLookupResidencyTestCase(deqp::Context& context)
176 	: SparseTexture2LookupTestCase(
177 		  context, "SparseTextureClampLookupResidency",
178 		  "Verifies if sparse texture clamp lookup functions generates access residency information")
179 {
180 	/* Left blank intentionally */
181 }
182 
183 /** Constructor.
184  *
185  *  @param context     Rendering context
186  */
SparseTextureClampLookupResidencyTestCase(deqp::Context & context,const char * name,const char * description)187 SparseTextureClampLookupResidencyTestCase::SparseTextureClampLookupResidencyTestCase(deqp::Context& context,
188 																					 const char*	name,
189 																					 const char*	description)
190 	: SparseTexture2LookupTestCase(context, name, description)
191 {
192 	/* Left blank intentionally */
193 }
194 
195 /** Stub init method */
init()196 void SparseTextureClampLookupResidencyTestCase::init()
197 {
198 	SparseTextureCommitmentTestCase::init();
199 	mSupportedInternalFormats.push_back(GL_DEPTH_COMPONENT16);
200 
201 	FunctionToken f;
202 	f = FunctionToken("sparseTextureClampARB", "<CUBE_REFZ_DEF>, <LOD>");
203 	f.allowedTargets.insert(GL_TEXTURE_2D);
204 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
205 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP);
206 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP_ARRAY);
207 	f.allowedTargets.insert(GL_TEXTURE_3D);
208 	mFunctions.push_back(f);
209 
210 	f = FunctionToken("sparseTextureOffsetClampARB", ", <OFFSET_TYPE><OFFSET_DIM>(0), <LOD>");
211 	f.allowedTargets.insert(GL_TEXTURE_2D);
212 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
213 	f.allowedTargets.insert(GL_TEXTURE_3D);
214 	mFunctions.push_back(f);
215 
216 	f = FunctionToken("sparseTextureGradClampARB",
217 					  ", <NOFFSET_TYPE><OFFSET_DIM>(0), <NOFFSET_TYPE><OFFSET_DIM>(0), <LOD>");
218 	f.allowedTargets.insert(GL_TEXTURE_2D);
219 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
220 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP);
221 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP_ARRAY);
222 	f.allowedTargets.insert(GL_TEXTURE_3D);
223 	mFunctions.push_back(f);
224 
225 	f = FunctionToken(
226 		"sparseTextureGradOffsetClampARB",
227 		", <NOFFSET_TYPE><OFFSET_DIM>(0), <NOFFSET_TYPE><OFFSET_DIM>(0), <OFFSET_TYPE><OFFSET_DIM>(0), <LOD>");
228 	f.allowedTargets.insert(GL_TEXTURE_2D);
229 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
230 	f.allowedTargets.insert(GL_TEXTURE_3D);
231 	mFunctions.push_back(f);
232 }
233 
234 /** Executes test iteration.
235  *
236  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
237  */
iterate()238 tcu::TestNode::IterateResult SparseTextureClampLookupResidencyTestCase::iterate()
239 {
240 	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_texture_clamp"))
241 	{
242 		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
243 		return STOP;
244 	}
245 
246 	return SparseTexture2LookupTestCase::iterate();
247 }
248 
249 /** Check if specific lookup function is allowed for specific target and format
250  *
251  * @param target       Target for which texture is binded
252  * @param format       Texture internal format
253  * @param funcToken    Texture lookup function structure
254  *
255  * @return Returns true if target/format combination is allowed, false otherwise.
256  */
funcAllowed(GLint target,GLint format,FunctionToken & funcToken)257 bool SparseTextureClampLookupResidencyTestCase::funcAllowed(GLint target, GLint format, FunctionToken& funcToken)
258 {
259 	if (funcToken.allowedTargets.find(target) == funcToken.allowedTargets.end())
260 		return false;
261 
262 	if (format == GL_DEPTH_COMPONENT16)
263 	{
264 		if (target == GL_TEXTURE_CUBE_MAP_ARRAY &&
265 			(funcToken.name == "sparseTextureGradClampARB" || funcToken.name == "textureGradClampARB"))
266 			return false;
267 	}
268 
269 	return true;
270 }
271 
272 /** Verify if data stored in texture is as expected
273  *
274  * @param gl           GL API functions
275  * @param target       Target for which texture is binded
276  * @param format       Texture internal format
277  * @param texture      Texture object
278  * @param level        Texture mipmap level
279  * @param funcToken    Lookup function tokenize structure
280  *
281  * @return Returns true if data is as expected, false if not, throws an exception if error occurred.
282  */
verifyLookupTextureData(const Functions & gl,GLint target,GLint format,GLuint & texture,GLint level,FunctionToken & funcToken)283 bool SparseTextureClampLookupResidencyTestCase::verifyLookupTextureData(const Functions& gl, GLint target, GLint format,
284 																		GLuint& texture, GLint level,
285 																		FunctionToken& funcToken)
286 {
287 	mLog << "Verify Lookup Residency Texture Data [function: " << funcToken.name << ", level: " << level << "] - ";
288 
289 	if (level > mState.levels - 1)
290 		TCU_FAIL("Invalid level");
291 
292 	GLint width;
293 	GLint height;
294 	GLint depth;
295 	SparseTextureUtils::getTextureLevelSize(target, mState, level, width, height, depth);
296 
297 	//Committed region is limited to 1/2 of width
298 	GLint widthCommitted = width / 2;
299 
300 	if (widthCommitted == 0 || height == 0 || depth < mState.minDepth)
301 		return true;
302 
303 	bool result = true;
304 
305 	if (target == GL_TEXTURE_CUBE_MAP)
306 		depth = depth * 6;
307 
308 	GLint texSize = width * height;
309 
310 	std::vector<GLubyte> vecExpData;
311 	std::vector<GLubyte> vecOutData;
312 	vecExpData.resize(texSize);
313 	vecOutData.resize(texSize);
314 	GLubyte* exp_data = vecExpData.data();
315 	GLubyte* out_data = vecOutData.data();
316 
317 	// Expected data is 255 because
318 	deMemset(exp_data, 255, texSize);
319 
320 	// Create verifying texture
321 	GLint  verifyTarget = GL_TEXTURE_2D;
322 	GLuint verifyTexture;
323 	Texture::Generate(gl, verifyTexture);
324 	Texture::Bind(gl, verifyTexture, verifyTarget);
325 	Texture::Storage(gl, verifyTarget, 1, GL_R8, width, height, depth);
326 	GLU_EXPECT_NO_ERROR(gl.getError(), "Texture::Storage");
327 
328 	GLuint fbo;
329 	gl.genFramebuffers(1, &fbo);
330 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers");
331 	gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
332 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer");
333 	gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, verifyTarget, verifyTexture, 0);
334 	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D");
335 
336 	gl.viewport(0, 0, width, height);
337 
338 	for (int sample = 0; sample < mState.samples; ++sample)
339 	{
340 		std::string vertex   = stc_vertex_common;
341 		std::string fragment = stc_fragment_lookupResidency;
342 
343 		// Make token copy to work on
344 		FunctionToken f = funcToken;
345 
346 		// Adjust shader source to texture format
347 		TokenStringsExt s = createLookupShaderTokens(target, verifyTarget, format, level, sample, f);
348 
349 		replaceToken("<COORD_TYPE>", s.coordType.c_str(), vertex);
350 
351 		replaceToken("<FUNCTION>", f.name.c_str(), fragment);
352 		replaceToken("<ARGUMENTS>", f.arguments.c_str(), fragment);
353 
354 		replaceToken("<OUTPUT_TYPE>", s.outputType.c_str(), fragment);
355 		replaceToken("<INPUT_TYPE>", s.inputType.c_str(), fragment);
356 		replaceToken("<SIZE_DEF>", s.sizeDef.c_str(), fragment);
357 		replaceToken("<LOD>", s.lod.c_str(), fragment);
358 		replaceToken("<LOD_DEF>", s.lodDef.c_str(), fragment);
359 		replaceToken("<COORD_TYPE>", s.coordType.c_str(), fragment);
360 		replaceToken("<ICOORD_TYPE>", s.iCoordType.c_str(), fragment);
361 		replaceToken("<COORD_DEF>", s.coordDef.c_str(), fragment);
362 		replaceToken("<POINT_TYPE>", s.pointType.c_str(), fragment);
363 		replaceToken("<POINT_DEF>", s.pointDef.c_str(), fragment);
364 		replaceToken("<RETURN_TYPE>", s.returnType.c_str(), fragment);
365 		replaceToken("<RESULT_EXPECTED>", s.resultExpected.c_str(), fragment);
366 		replaceToken("<EPSILON>", s.epsilon.c_str(), fragment);
367 		replaceToken("<SAMPLE_DEF>", s.sampleDef.c_str(), fragment);
368 		replaceToken("<REFZ_DEF>", s.refZDef.c_str(), fragment);
369 		replaceToken("<CUBE_REFZ_DEF>", s.cubeMapArrayRefZDef.c_str(), fragment);
370 		replaceToken("<POINT_COORD>", s.pointCoord.c_str(), fragment);
371 		replaceToken("<COMPONENT_DEF>", s.componentDef.c_str(), fragment);
372 		replaceToken("<CUBE_MAP_COORD_DEF>", s.cubeMapCoordDef.c_str(), fragment);
373 		replaceToken("<OFFSET_ARRAY_DEF>", s.offsetArrayDef.c_str(), fragment);
374 		replaceToken("<FORMAT_DEF>", s.formatDef.c_str(), fragment);
375 		replaceToken("<OFFSET_TYPE>", s.offsetType.c_str(), fragment);
376 		replaceToken("<NOFFSET_TYPE>", s.nOffsetType.c_str(), fragment);
377 		replaceToken("<OFFSET_DIM>", s.offsetDim.c_str(), fragment);
378 
379 		replaceToken("<TEX_WIDTH>", de::toString(width).c_str(), fragment);
380 		replaceToken("<TEX_HEIGHT>", de::toString(height).c_str(), fragment);
381 		replaceToken("<TEX_DEPTH>", de::toString(depth).c_str(), fragment);
382 
383 		ProgramSources sources = makeVtxFragSources(vertex.c_str(), fragment.c_str());
384 
385 		// Build and run shader
386 		ShaderProgram program(m_context.getRenderContext(), sources);
387 		if (program.isOk())
388 		{
389 			for (GLint z = 0; z < depth; ++z)
390 			{
391 				deMemset(out_data, 0, texSize);
392 
393 				Texture::Bind(gl, verifyTexture, verifyTarget);
394 				Texture::SubImage(gl, verifyTarget, 0, 0, 0, 0, width, height, 0, GL_RED, GL_UNSIGNED_BYTE,
395 								  (GLvoid*)out_data);
396 				GLU_EXPECT_NO_ERROR(gl.getError(), "Texture::SubImage");
397 
398 				// Use shader
399 				gl.useProgram(program.getProgram());
400 				GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
401 
402 				// Pass input sampler/image to shader
403 				gl.activeTexture(GL_TEXTURE0);
404 				GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveTexture");
405 				gl.uniform1i(1, 0 /* sampler_unit */);
406 				GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i");
407 
408 				// Pass committed region width to shader
409 				gl.uniform1i(2, widthCommitted /* committed region width */);
410 				GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i");
411 
412 				gl.bindTexture(target, texture);
413 				GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture");
414 				gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
415 				gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
416 
417 				gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
418 				draw(target, z, program);
419 
420 				Texture::Bind(gl, verifyTexture, verifyTarget);
421 				Texture::GetData(gl, 0, verifyTarget, GL_RED, GL_UNSIGNED_BYTE, (GLvoid*)out_data);
422 				GLU_EXPECT_NO_ERROR(gl.getError(), "Texture::GetData");
423 
424 				//Verify only committed region
425 				for (GLint y = 0; y < height; ++y)
426 					for (GLint x = 0; x < width; ++x)
427 					{
428 						GLubyte* dataRegion	= exp_data + x + y * width;
429 						GLubyte* outDataRegion = out_data + x + y * width;
430 						if (dataRegion[0] != outDataRegion[0]) {
431 							m_testCtx.getLog() << tcu::TestLog::Message << mLog.str() <<
432 								"Error detected at " << x << "," << y << "," << z <<
433 								": expected [" << (unsigned)dataRegion[0] << "] got [" <<
434 								(unsigned)outDataRegion[0] << "]" << tcu::TestLog::EndMessage;
435 							result = false;
436 							goto out;
437 						}
438 					}
439 			}
440 		}
441 		else
442 		{
443 			mLog << "Shader compilation failed (lookup residency) for target: " << target << ", format: " << format
444 				 << ", vertexInfoLog: " << program.getShaderInfo(SHADERTYPE_VERTEX).infoLog
445 				 << ", fragmentInfoLog: " << program.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog
446 				 << ", programInfoLog: " << program.getProgramInfo().infoLog << ", fragmentSource: " << fragment.c_str()
447 				 << " - ";
448 
449 			result = false;
450 		}
451 	}
452 out:
453 	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
454 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer");
455 
456 	gl.deleteFramebuffers(1, &fbo);
457 	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteFramebuffers");
458 
459 	Texture::Delete(gl, verifyTexture);
460 
461 	return result;
462 }
463 
draw(GLint target,GLint layer,const ShaderProgram & program)464 void SparseTextureClampLookupResidencyTestCase::draw(GLint target, GLint layer, const ShaderProgram& program)
465 {
466 	const GLfloat texCoord1D[] = { 0.0f, 1.0f, 0.0f, 1.0f };
467 
468 	const GLfloat texCoord2D[] = {
469 		0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
470 	};
471 
472 	const GLfloat texCoord3D[] = { 0.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.5f, 0.0f, 1.0f, 0.5f, 1.0f, 1.0f, 0.5f };
473 
474 	const GLfloat texCoordCubeMap[6][12] = {
475 		{ 0.0f, 0.0f, 0.00f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f },
476 		{ 0.0f, 0.0f, 0.17f, 1.0f, 0.0f, 0.17f, 0.0f, 1.0f, 0.17f, 1.0f, 1.0f, 0.17f },
477 		{ 0.0f, 0.0f, 0.33f, 1.0f, 0.0f, 0.33f, 0.0f, 1.0f, 0.33f, 1.0f, 1.0f, 0.33f },
478 		{ 0.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.5f, 0.0f, 1.0f, 0.5f, 1.0f, 1.0f, 0.5f },
479 		{ 0.0f, 0.0f, 0.67f, 1.0f, 0.0f, 0.67f, 0.0f, 1.0f, 0.67f, 1.0f, 1.0f, 0.67f },
480 		{ 0.0f, 0.0f, 0.83f, 1.0f, 0.0f, 0.83f, 0.0f, 1.0f, 0.83f, 1.0f, 1.0f, 0.83f }
481 	};
482 
483 	// The fragment shader uses (z * 6) % 6 to calculate a cube face index.
484 	GLfloat cubeMapArrayZCoord = GLfloat(layer) / 6.0f + 0.01f;
485 	// The fragment shader does not modify w for layer selection.
486 	GLfloat cubeMapArrayWCoord = GLfloat(layer / 6); // Note: integer division
487 	const GLfloat texCoordCubeMapArray[16] = { 0.0f, 0.0f, cubeMapArrayZCoord, cubeMapArrayWCoord,
488 											   1.0f, 0.0f, cubeMapArrayZCoord, cubeMapArrayWCoord,
489 											   0.0f, 1.0f, cubeMapArrayZCoord, cubeMapArrayWCoord,
490 											   1.0f, 1.0f, cubeMapArrayZCoord, cubeMapArrayWCoord };
491 
492 	const GLfloat vertices[] = {
493 		-1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f,
494 	};
495 
496 	const GLuint indices[] = { 0, 1, 2, 1, 2, 3 };
497 
498 	VertexArrayBinding floatCoord;
499 
500 	if (target == GL_TEXTURE_1D || target == GL_TEXTURE_1D_ARRAY)
501 		floatCoord = glu::va::Float("inCoord", 1, 4, 0, texCoord1D);
502 	else if (target == GL_TEXTURE_3D)
503 		floatCoord = glu::va::Float("inCoord", 3, 4, 0, texCoord3D);
504 	else if (target == GL_TEXTURE_CUBE_MAP)
505 		floatCoord = glu::va::Float("inCoord", 3, 4, 0, texCoordCubeMap[layer]);
506 	else if (target == GL_TEXTURE_CUBE_MAP_ARRAY)
507 		floatCoord = glu::va::Float("inCoord", 4, 4, 0, texCoordCubeMapArray);
508 	else
509 		floatCoord = glu::va::Float("inCoord", 2, 4, 0, texCoord2D);
510 
511 	glu::VertexArrayBinding vertexArrays[] = { glu::va::Float("vertex", 3, 4, 0, vertices), floatCoord };
512 
513 	glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), vertexArrays,
514 			  glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(indices), indices));
515 }
516 
517 /** Constructor.
518  *
519  *  @param context     Rendering context
520  */
SparseTextureClampLookupColorTestCase(deqp::Context & context)521 SparseTextureClampLookupColorTestCase::SparseTextureClampLookupColorTestCase(deqp::Context& context)
522 	: SparseTextureClampLookupResidencyTestCase(
523 		  context, "SparseTextureClampLookupColor",
524 		  "Verifies if sparse and non-sparse texture clamp lookup functions works as expected")
525 {
526 	/* Left blank intentionally */
527 }
528 
529 /** Stub init method */
init()530 void SparseTextureClampLookupColorTestCase::init()
531 {
532 	SparseTextureCommitmentTestCase::init();
533 	mSupportedTargets.push_back(GL_TEXTURE_1D);
534 	mSupportedTargets.push_back(GL_TEXTURE_1D_ARRAY);
535 	mSupportedInternalFormats.push_back(GL_DEPTH_COMPONENT16);
536 
537 	FunctionToken f;
538 	f = FunctionToken("sparseTextureClampARB", "<CUBE_REFZ_DEF>, <LOD>");
539 	f.allowedTargets.insert(GL_TEXTURE_2D);
540 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
541 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP);
542 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP_ARRAY);
543 	f.allowedTargets.insert(GL_TEXTURE_3D);
544 	mFunctions.push_back(f);
545 
546 	f = FunctionToken("textureClampARB", "<CUBE_REFZ_DEF>, <LOD>");
547 	f.allowedTargets.insert(GL_TEXTURE_1D);
548 	f.allowedTargets.insert(GL_TEXTURE_1D_ARRAY);
549 	f.allowedTargets.insert(GL_TEXTURE_2D);
550 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
551 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP);
552 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP_ARRAY);
553 	f.allowedTargets.insert(GL_TEXTURE_3D);
554 	mFunctions.push_back(f);
555 
556 	f = FunctionToken("sparseTextureOffsetClampARB", ", <OFFSET_TYPE><OFFSET_DIM>(0), <LOD>");
557 	f.allowedTargets.insert(GL_TEXTURE_2D);
558 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
559 	f.allowedTargets.insert(GL_TEXTURE_3D);
560 	mFunctions.push_back(f);
561 
562 	f = FunctionToken("textureOffsetClampARB", ", <OFFSET_TYPE><OFFSET_DIM>(0), <LOD>");
563 	f.allowedTargets.insert(GL_TEXTURE_1D);
564 	f.allowedTargets.insert(GL_TEXTURE_1D_ARRAY);
565 	f.allowedTargets.insert(GL_TEXTURE_2D);
566 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
567 	f.allowedTargets.insert(GL_TEXTURE_3D);
568 	mFunctions.push_back(f);
569 
570 	f = FunctionToken("sparseTextureGradClampARB",
571 					  ", <NOFFSET_TYPE><OFFSET_DIM>(0), <NOFFSET_TYPE><OFFSET_DIM>(0), <LOD>");
572 	f.allowedTargets.insert(GL_TEXTURE_2D);
573 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
574 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP);
575 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP_ARRAY);
576 	f.allowedTargets.insert(GL_TEXTURE_3D);
577 	mFunctions.push_back(f);
578 
579 	f = FunctionToken("textureGradClampARB", ", <NOFFSET_TYPE><OFFSET_DIM>(0), <NOFFSET_TYPE><OFFSET_DIM>(0), <LOD>");
580 	f.allowedTargets.insert(GL_TEXTURE_1D);
581 	f.allowedTargets.insert(GL_TEXTURE_1D_ARRAY);
582 	f.allowedTargets.insert(GL_TEXTURE_2D);
583 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
584 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP);
585 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP_ARRAY);
586 	f.allowedTargets.insert(GL_TEXTURE_3D);
587 	mFunctions.push_back(f);
588 
589 	f = FunctionToken(
590 		"sparseTextureGradOffsetClampARB",
591 		", <NOFFSET_TYPE><OFFSET_DIM>(0), <NOFFSET_TYPE><OFFSET_DIM>(0), <OFFSET_TYPE><OFFSET_DIM>(0), <LOD>");
592 	f.allowedTargets.insert(GL_TEXTURE_2D);
593 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
594 	f.allowedTargets.insert(GL_TEXTURE_3D);
595 	mFunctions.push_back(f);
596 
597 	f = FunctionToken(
598 		"textureGradOffsetClampARB",
599 		", <NOFFSET_TYPE><OFFSET_DIM>(0), <NOFFSET_TYPE><OFFSET_DIM>(0), <OFFSET_TYPE><OFFSET_DIM>(0), <LOD>");
600 	f.allowedTargets.insert(GL_TEXTURE_1D);
601 	f.allowedTargets.insert(GL_TEXTURE_1D_ARRAY);
602 	f.allowedTargets.insert(GL_TEXTURE_2D);
603 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
604 	f.allowedTargets.insert(GL_TEXTURE_3D);
605 	mFunctions.push_back(f);
606 }
607 
608 /** Executes test iteration.
609  *
610  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
611  */
iterate()612 tcu::TestNode::IterateResult SparseTextureClampLookupColorTestCase::iterate()
613 {
614 	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_texture_clamp"))
615 	{
616 		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
617 		return STOP;
618 	}
619 
620 	const Functions& gl = m_context.getRenderContext().getFunctions();
621 
622 	bool result = true;
623 
624 	GLuint texture;
625 
626 	for (std::vector<glw::GLint>::const_iterator iter = mSupportedTargets.begin(); iter != mSupportedTargets.end();
627 		 ++iter)
628 	{
629 		const GLint& target = *iter;
630 
631 		for (std::vector<glw::GLint>::const_iterator formIter = mSupportedInternalFormats.begin();
632 			 formIter != mSupportedInternalFormats.end(); ++formIter)
633 		{
634 			const GLint& format = *formIter;
635 
636 			if (!caseAllowed(target, format))
637 				continue;
638 
639 			for (std::vector<FunctionToken>::const_iterator tokIter = mFunctions.begin(); tokIter != mFunctions.end();
640 				 ++tokIter)
641 			{
642 				// Check if target is allowed for current lookup function
643 				FunctionToken funcToken = *tokIter;
644 				if (!funcAllowed(target, format, funcToken))
645 					continue;
646 
647 				bool isSparse = false;
648 				if (funcToken.name.find("sparse", 0) != std::string::npos)
649 					isSparse = true;
650 
651 				mLog.str("");
652 				mLog << "Testing sparse texture lookup color functions for target: " << target << ", format: " << format
653 					 << " - ";
654 
655 				if (isSparse)
656 					sparseAllocateTexture(gl, target, format, texture, 3);
657 				else
658 					allocateTexture(gl, target, format, texture, 3);
659 
660 				if (format == GL_DEPTH_COMPONENT16)
661 					setupDepthMode(gl, target, texture);
662 
663 				int l;
664 				int maxLevels = 0;
665 				for (l = 0; l < mState.levels; ++l)
666 				{
667 					if (!isSparse || commitTexturePage(gl, target, format, texture, l))
668 					{
669 						writeDataToTexture(gl, target, format, texture, l);
670 						maxLevels = l;
671 					}
672 				}
673 
674 				for (l = 0; l <= maxLevels; ++l)
675 				{
676 					result = result && verifyLookupTextureData(gl, target, format, texture, l, funcToken);
677 
678 					if (!result)
679 						break;
680 				}
681 
682 				Texture::Delete(gl, texture);
683 
684 				if (!result)
685 				{
686 					m_testCtx.getLog() << tcu::TestLog::Message << mLog.str() << "Fail" << tcu::TestLog::EndMessage;
687 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
688 					return STOP;
689 				}
690 			}
691 		}
692 	}
693 
694 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
695 	return STOP;
696 }
697 
698 /** Writing data to generated texture using compute shader
699  *
700  * @param gl           GL API functions
701  * @param target       Target for which texture is binded
702  * @param format       Texture internal format
703  * @param texture      Texture object
704  *
705  * @return Returns true if no error occurred, otherwise throws an exception.
706  */
writeDataToTexture(const Functions & gl,GLint target,GLint format,GLuint & texture,GLint level)707 bool SparseTextureClampLookupColorTestCase::writeDataToTexture(const Functions& gl, GLint target, GLint format,
708 															   GLuint& texture, GLint level)
709 {
710 	mLog << "Fill Texture with shader [level: " << level << "] - ";
711 
712 	if (level > mState.levels - 1)
713 		TCU_FAIL("Invalid level");
714 
715 	GLint width;
716 	GLint height;
717 	GLint depth;
718 	SparseTextureUtils::getTextureLevelSize(target, mState, level, width, height, depth);
719 
720 	if (width > 0 && height > 0 && depth >= mState.minDepth)
721 	{
722 		if (target == GL_TEXTURE_CUBE_MAP)
723 			depth = depth * 6;
724 
725 		GLint texSize = width * height * depth * mState.format.getPixelSize();
726 
727 		std::vector<GLubyte> vecData;
728 		vecData.resize(texSize);
729 		GLubyte* data = vecData.data();
730 
731 		deMemset(data, 255, texSize);
732 
733 		for (GLint sample = 0; sample < mState.samples; ++sample)
734 		{
735 			std::string shader = stc_compute_textureFill;
736 
737 			// Adjust shader source to texture format
738 			GLint verifyTarget;
739 			if (target == GL_TEXTURE_2D_MULTISAMPLE || target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE)
740 				verifyTarget = GL_TEXTURE_2D;
741 			else
742 				verifyTarget = GL_TEXTURE_2D_ARRAY;
743 			TokenStrings s = createShaderTokens(target, verifyTarget, format, sample);
744 
745 			GLint convFormat = format;
746 			if (format == GL_DEPTH_COMPONENT16)
747 				convFormat = GL_R16;
748 
749 			// Change expected result as it has to be adjusted to different levels
750 			s.resultExpected = generateExpectedResult(s.returnType, level, convFormat);
751 
752 			replaceToken("<INPUT_TYPE>", s.inputType.c_str(), shader);
753 			replaceToken("<POINT_TYPE>", s.pointType.c_str(), shader);
754 			replaceToken("<POINT_DEF>", s.pointDef.c_str(), shader);
755 			replaceToken("<RETURN_TYPE>", s.returnType.c_str(), shader);
756 			replaceToken("<RESULT_EXPECTED>", s.resultExpected.c_str(), shader);
757 			replaceToken("<SAMPLE_DEF>", s.sampleDef.c_str(), shader);
758 
759 			ProgramSources sources;
760 			sources << ComputeSource(shader);
761 
762 			// Build and run shader
763 			ShaderProgram program(m_context.getRenderContext(), sources);
764 			if (program.isOk())
765 			{
766 				gl.useProgram(program.getProgram());
767 				GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
768 				gl.bindImageTexture(0 /* unit */, texture, level /* level */, GL_TRUE /* layered */, 0 /* layer */,
769 									GL_WRITE_ONLY, convFormat);
770 				GLU_EXPECT_NO_ERROR(gl.getError(), "glBindImageTexture");
771 				gl.uniform1i(1, 0 /* image_unit */);
772 				GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i");
773 				gl.dispatchCompute(width, height, depth);
774 				GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute");
775 				gl.memoryBarrier(GL_ALL_BARRIER_BITS);
776 				GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier");
777 			}
778 			else
779 			{
780 				mLog << "Compute shader compilation failed (writing) for target: " << target << ", format: " << format
781 					 << ", sample: " << sample << ", infoLog: " << program.getShaderInfo(SHADERTYPE_COMPUTE).infoLog
782 					 << ", shaderSource: " << shader.c_str() << " - ";
783 			}
784 		}
785 	}
786 
787 	return true;
788 }
789 
790 /** Verify if data stored in texture is as expected
791  *
792  * @param gl           GL API functions
793  * @param target       Target for which texture is binded
794  * @param format       Texture internal format
795  * @param texture      Texture object
796  * @param level        Texture mipmap level
797  * @param funcToken    Lookup function tokenize structure
798  *
799  * @return Returns true if data is as expected, false if not, throws an exception if error occurred.
800  */
verifyLookupTextureData(const Functions & gl,GLint target,GLint format,GLuint & texture,GLint level,FunctionToken & funcToken)801 bool SparseTextureClampLookupColorTestCase::verifyLookupTextureData(const Functions& gl, GLint target, GLint format,
802 																	GLuint& texture, GLint level,
803 																	FunctionToken& funcToken)
804 {
805 	mLog << "Verify Lookup Color Texture Data [function: " << funcToken.name << ", level: " << level << "] - ";
806 
807 	if (level > mState.levels - 1)
808 		TCU_FAIL("Invalid level");
809 
810 	GLint width;
811 	GLint height;
812 	GLint depth;
813 	SparseTextureUtils::getTextureLevelSize(target, mState, level, width, height, depth);
814 
815 	if (width == 0 || height == 0 || depth < mState.minDepth)
816 		return true;
817 
818 	bool result = true;
819 
820 	if (target == GL_TEXTURE_CUBE_MAP)
821 		depth = depth * 6;
822 
823 	GLint texSize = width * height;
824 
825 	std::vector<GLubyte> vecExpData;
826 	std::vector<GLubyte> vecOutData;
827 	vecExpData.resize(texSize);
828 	vecOutData.resize(texSize);
829 	GLubyte* exp_data = vecExpData.data();
830 	GLubyte* out_data = vecOutData.data();
831 
832 	// Expected data is 255 because
833 	deMemset(exp_data, 255, texSize);
834 
835 	// Create verifying texture
836 	GLint  verifyTarget = GL_TEXTURE_2D;
837 	GLuint verifyTexture;
838 	Texture::Generate(gl, verifyTexture);
839 	Texture::Bind(gl, verifyTexture, verifyTarget);
840 	Texture::Storage(gl, verifyTarget, 1, GL_R8, width, height, depth);
841 	GLU_EXPECT_NO_ERROR(gl.getError(), "Texture::Storage");
842 
843 	GLuint fbo;
844 	gl.genFramebuffers(1, &fbo);
845 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers");
846 	gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
847 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer");
848 	gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, verifyTarget, verifyTexture, 0);
849 	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D");
850 
851 	gl.viewport(0, 0, width, height);
852 
853 	for (int sample = 0; sample < mState.samples; ++sample)
854 	{
855 		std::string vertex   = stc_vertex_common;
856 		std::string fragment = stc_fragment_lookupColor;
857 
858 		// Make token copy to work on
859 		FunctionToken f = funcToken;
860 
861 		std::string functionDef = generateFunctionDef(f.name);
862 
863 		// Adjust shader source to texture format
864 		TokenStringsExt s = createLookupShaderTokens(target, verifyTarget, format, level, sample, f);
865 
866 		// Change expected result as it has to be adjusted to different levels
867 		s.resultExpected = generateExpectedResult(s.returnType, level, format);
868 
869 		replaceToken("<COORD_TYPE>", s.coordType.c_str(), vertex);
870 
871 		replaceToken("<FUNCTION_DEF>", functionDef.c_str(), fragment);
872 		replaceToken("<FUNCTION>", f.name.c_str(), fragment);
873 		replaceToken("<ARGUMENTS>", f.arguments.c_str(), fragment);
874 
875 		replaceToken("<OUTPUT_TYPE>", s.outputType.c_str(), fragment);
876 		replaceToken("<INPUT_TYPE>", s.inputType.c_str(), fragment);
877 		replaceToken("<SIZE_DEF>", s.sizeDef.c_str(), fragment);
878 		replaceToken("<LOD>", s.lod.c_str(), fragment);
879 		replaceToken("<LOD_DEF>", s.lodDef.c_str(), fragment);
880 		replaceToken("<COORD_TYPE>", s.coordType.c_str(), fragment);
881 		replaceToken("<ICOORD_TYPE>", s.coordType.c_str(), fragment);
882 		replaceToken("<COORD_DEF>", s.coordDef.c_str(), fragment);
883 		replaceToken("<POINT_TYPE>", s.pointType.c_str(), fragment);
884 		replaceToken("<POINT_DEF>", s.pointDef.c_str(), fragment);
885 		replaceToken("<RETURN_TYPE>", s.returnType.c_str(), fragment);
886 		replaceToken("<RESULT_EXPECTED>", s.resultExpected.c_str(), fragment);
887 		replaceToken("<EPSILON>", s.epsilon.c_str(), fragment);
888 		replaceToken("<SAMPLE_DEF>", s.sampleDef.c_str(), fragment);
889 		replaceToken("<REFZ_DEF>", s.refZDef.c_str(), fragment);
890 		replaceToken("<CUBE_REFZ_DEF>", s.cubeMapArrayRefZDef.c_str(), fragment);
891 		replaceToken("<POINT_COORD>", s.pointCoord.c_str(), fragment);
892 		replaceToken("<COMPONENT_DEF>", s.componentDef.c_str(), fragment);
893 		replaceToken("<CUBE_MAP_COORD_DEF>", s.cubeMapCoordDef.c_str(), fragment);
894 		replaceToken("<OFFSET_ARRAY_DEF>", s.offsetArrayDef.c_str(), fragment);
895 		replaceToken("<FORMAT_DEF>", s.formatDef.c_str(), fragment);
896 		replaceToken("<OFFSET_TYPE>", s.offsetType.c_str(), fragment);
897 		replaceToken("<NOFFSET_TYPE>", s.nOffsetType.c_str(), fragment);
898 		replaceToken("<OFFSET_DIM>", s.offsetDim.c_str(), fragment);
899 
900 		replaceToken("<TEX_WIDTH>", de::toString(width).c_str(), fragment);
901 		replaceToken("<TEX_HEIGHT>", de::toString(height).c_str(), fragment);
902 		replaceToken("<TEX_DEPTH>", de::toString(depth).c_str(), fragment);
903 
904 		ProgramSources sources = makeVtxFragSources(vertex.c_str(), fragment.c_str());
905 
906 		// Build and run shader
907 		ShaderProgram program(m_context.getRenderContext(), sources);
908 
909 		if (program.isOk())
910 		{
911 			for (GLint z = 0; z < depth; ++z)
912 			{
913 				deMemset(out_data, 0, texSize);
914 
915 				Texture::Bind(gl, verifyTexture, verifyTarget);
916 				Texture::SubImage(gl, verifyTarget, 0, 0, 0, 0, width, height, 0, GL_RED, GL_UNSIGNED_BYTE,
917 								  (GLvoid*)out_data);
918 				GLU_EXPECT_NO_ERROR(gl.getError(), "Texture::SubImage");
919 
920 				// Use shader
921 				gl.useProgram(program.getProgram());
922 				GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
923 
924 				// Pass input sampler/image to shader
925 				gl.activeTexture(GL_TEXTURE0);
926 				GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveTexture");
927 				gl.uniform1i(1, 0 /* sampler_unit */);
928 				GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i");
929 
930 				gl.bindTexture(target, texture);
931 				GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture");
932 				gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
933 				gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
934 
935 				gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
936 				draw(target, z, program);
937 
938 				Texture::Bind(gl, verifyTexture, verifyTarget);
939 				Texture::GetData(gl, 0, verifyTarget, GL_RED, GL_UNSIGNED_BYTE, (GLvoid*)out_data);
940 				GLU_EXPECT_NO_ERROR(gl.getError(), "Texture::GetData");
941 
942 				//Verify only committed region
943 				for (GLint y = 0; y < height; ++y)
944 					for (GLint x = 0; x < width; ++x)
945 					{
946 						GLubyte* dataRegion	= exp_data + x + y * width;
947 						GLubyte* outDataRegion = out_data + x + y * width;
948 						if (dataRegion[0] != outDataRegion[0])
949 							result = false;
950 					}
951 			}
952 		}
953 		else
954 		{
955 			mLog << "Shader compilation failed (lookup color) for target: " << target << ", format: " << format
956 				 << ", vertexInfoLog: " << program.getShaderInfo(SHADERTYPE_VERTEX).infoLog
957 				 << ", fragmentInfoLog: " << program.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog
958 				 << ", programInfoLog: " << program.getProgramInfo().infoLog << ", fragmentSource: " << fragment.c_str()
959 				 << " - ";
960 
961 			result = false;
962 		}
963 	}
964 
965 	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
966 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer");
967 
968 	gl.deleteFramebuffers(1, &fbo);
969 	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteFramebuffers");
970 
971 	Texture::Delete(gl, verifyTexture);
972 
973 	return result;
974 }
975 
976 /** Preparing texture. Function overridden to increase textures size.
977  *
978  * @param gl           GL API functions
979  * @param target       Target for which texture is binded
980  * @param format       Texture internal format
981  * @param texture      Texture object
982  *
983  * @return Returns true if no error occurred, otherwise throws an exception.
984  */
prepareTexture(const Functions & gl,GLint target,GLint format,GLuint & texture)985 bool SparseTextureClampLookupColorTestCase::prepareTexture(const Functions& gl, GLint target, GLint format,
986 														   GLuint& texture)
987 {
988 	Texture::Generate(gl, texture);
989 	Texture::Bind(gl, texture, target);
990 
991 	mState.minDepth = SparseTextureUtils::getTargetDepth(target);
992 	SparseTextureUtils::getTexturePageSizes(gl, target, format, mState.pageSizeX, mState.pageSizeY, mState.pageSizeZ);
993 
994 	//The <width> and <height> has to be equal for cube map textures
995 	if (target == GL_TEXTURE_CUBE_MAP || target == GL_TEXTURE_CUBE_MAP_ARRAY)
996 	{
997 		if (mState.pageSizeX > mState.pageSizeY)
998 			mState.pageSizeY = mState.pageSizeX;
999 		else if (mState.pageSizeX < mState.pageSizeY)
1000 			mState.pageSizeX = mState.pageSizeY;
1001 	}
1002 
1003 	mState.width  = 4 * mState.pageSizeX;
1004 	mState.height = 4 * mState.pageSizeY;
1005 	mState.depth  = 4 * mState.pageSizeZ * mState.minDepth;
1006 
1007 	mState.format = glu::mapGLInternalFormat(format);
1008 
1009 	return true;
1010 }
1011 
1012 /** Commit texture page using texPageCommitment function. Function overridden to commit whole texture region.
1013  *
1014  * @param gl           GL API functions
1015  * @param target       Target for which texture is binded
1016  * @param format       Texture internal format
1017  * @param texture      Texture object
1018  * @param level        Texture mipmap level
1019  *
1020  * @return Returns true if commitment is done properly, false if commitment is not allowed or throws exception if error occurred.
1021  */
commitTexturePage(const Functions & gl,GLint target,GLint format,GLuint & texture,GLint level)1022 bool SparseTextureClampLookupColorTestCase::commitTexturePage(const Functions& gl, GLint target, GLint format,
1023 															  GLuint& texture, GLint level)
1024 {
1025 	mLog << "Commit Region [level: " << level << "] - ";
1026 
1027 	if (level > mState.levels - 1)
1028 		TCU_FAIL("Invalid level");
1029 
1030 	// Avoid not allowed commitments
1031 	if (!isInPageSizesRange(target, level) || !isPageSizesMultiplication(target, level))
1032 	{
1033 		mLog << "Skip commitment [level: " << level << "] - ";
1034 		return false;
1035 	}
1036 
1037 	GLint width;
1038 	GLint height;
1039 	GLint depth;
1040 	SparseTextureUtils::getTextureLevelSize(target, mState, level, width, height, depth);
1041 
1042 	if (target == GL_TEXTURE_CUBE_MAP)
1043 		depth = 6 * depth;
1044 
1045 	Texture::Bind(gl, texture, target);
1046 	texPageCommitment(gl, target, format, texture, level, 0, 0, 0, width, height, depth, GL_TRUE);
1047 	GLU_EXPECT_NO_ERROR(gl.getError(), "texPageCommitment");
1048 
1049 	return true;
1050 }
1051 
1052 /** Check if current texture size for level is greater or equal page size in a corresponding direction
1053  *
1054  * @param target  Target for which texture is binded
1055  * @param level   Texture mipmap level
1056  *
1057  * @return Returns true if the texture size condition is fulfilled, false otherwise.
1058  */
isInPageSizesRange(GLint target,GLint level)1059 bool SparseTextureClampLookupColorTestCase::isInPageSizesRange(GLint target, GLint level)
1060 {
1061 	GLint width;
1062 	GLint height;
1063 	GLint depth;
1064 	SparseTextureUtils::getTextureLevelSize(target, mState, level, width, height, depth);
1065 
1066 	if (target == GL_TEXTURE_CUBE_MAP)
1067 		depth = 6 * depth;
1068 
1069 	if (width >= mState.pageSizeX && height >= mState.pageSizeY && (mState.minDepth == 0 || depth >= mState.pageSizeZ))
1070 	{
1071 		return true;
1072 	}
1073 
1074 	return false;
1075 }
1076 
1077 /** Check if current texture size for level is page size multiplication in a corresponding direction
1078  *
1079  * @param target  Target for which texture is binded
1080  * @param level   Texture mipmap level
1081  *
1082  * @return Returns true if the texture size condition is fulfilled, false otherwise.
1083  */
isPageSizesMultiplication(GLint target,GLint level)1084 bool SparseTextureClampLookupColorTestCase::isPageSizesMultiplication(GLint target, GLint level)
1085 {
1086 	GLint width;
1087 	GLint height;
1088 	GLint depth;
1089 	SparseTextureUtils::getTextureLevelSize(target, mState, level, width, height, depth);
1090 
1091 	if (target == GL_TEXTURE_CUBE_MAP)
1092 		depth = 6 * depth;
1093 
1094 	if ((width % mState.pageSizeX) == 0 && (height % mState.pageSizeY) == 0 && (depth % mState.pageSizeZ) == 0)
1095 	{
1096 		return true;
1097 	}
1098 
1099 	return false;
1100 }
1101 
1102 /** Constructor.
1103  *
1104  * @param funcName Tested function name.
1105  *
1106  * @return Returns shader source code part that uses lookup function to fetch texel from texture.
1107  */
generateFunctionDef(std::string funcName)1108 std::string SparseTextureClampLookupColorTestCase::generateFunctionDef(std::string funcName)
1109 {
1110 	if (funcName.find("sparse", 0) != std::string::npos)
1111 	{
1112 		return std::string("    <FUNCTION>(uni_in,\n"
1113 						   "               <POINT_COORD><SAMPLE_DEF><ARGUMENTS>,\n"
1114 						   "               retValue<COMPONENT_DEF>);\n");
1115 	}
1116 	else
1117 	{
1118 		return std::string("    retValue<COMPONENT_DEF> = <FUNCTION>(uni_in,\n"
1119 						   "                                         <POINT_COORD><SAMPLE_DEF><ARGUMENTS>);\n");
1120 	}
1121 }
1122 
1123 /** Constructor.
1124  *
1125  * @param returnType Expected result variable type.
1126  *
1127  * @return Returns shader source token that represent expected lookup result value.
1128  */
generateExpectedResult(std::string returnType,GLint level,GLint format)1129 std::string SparseTextureClampLookupColorTestCase::generateExpectedResult(std::string returnType, GLint level,
1130 																		  GLint format)
1131 {
1132 	if (format == GL_DEPTH_COMPONENT16)
1133 		return std::string("(1, 0, 0, 0)");
1134 	else if (returnType == "vec4")
1135 		return std::string("(") + de::toString(0.5f + (float)level / 10) + std::string(", 0, 0, 1)");
1136 	else
1137 		return std::string("(") + de::toString(level * 10) + std::string(", 0, 0, 1)");
1138 }
1139 
1140 /** Constructor.
1141  *
1142  *  @param context Rendering context.
1143  */
SparseTextureClampTests(deqp::Context & context)1144 SparseTextureClampTests::SparseTextureClampTests(deqp::Context& context)
1145 	: TestCaseGroup(context, "sparse_texture_clamp_tests",
1146 					"Verify conformance of CTS_ARB_sparse_texture_clamp implementation")
1147 {
1148 }
1149 
1150 /** Initializes the test group contents. */
init()1151 void SparseTextureClampTests::init()
1152 {
1153 	addChild(new ShaderExtensionTestCase(m_context, "GL_ARB_sparse_texture_clamp"));
1154 	addChild(new SparseTextureClampLookupResidencyTestCase(m_context));
1155 	addChild(new SparseTextureClampLookupColorTestCase(m_context));
1156 }
1157 
1158 } /* gl4cts namespace */
1159