• 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, 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 
415 				gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
416 				draw(target, z, program);
417 
418 				Texture::Bind(gl, verifyTexture, verifyTarget);
419 				Texture::GetData(gl, 0, verifyTarget, GL_RED, GL_UNSIGNED_BYTE, (GLvoid*)out_data);
420 				GLU_EXPECT_NO_ERROR(gl.getError(), "Texture::GetData");
421 
422 				//Verify only committed region
423 				for (GLint y = 0; y < height; ++y)
424 					for (GLint x = 0; x < width; ++x)
425 					{
426 						GLubyte* dataRegion	= exp_data + x + y * width;
427 						GLubyte* outDataRegion = out_data + x + y * width;
428 						if (dataRegion[0] != outDataRegion[0])
429 							result = false;
430 					}
431 			}
432 		}
433 		else
434 		{
435 			mLog << "Shader compilation failed (lookup residency) for target: " << target << ", format: " << format
436 				 << ", vertexInfoLog: " << program.getShaderInfo(SHADERTYPE_VERTEX).infoLog
437 				 << ", fragmentInfoLog: " << program.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog
438 				 << ", programInfoLog: " << program.getProgramInfo().infoLog << ", fragmentSource: " << fragment.c_str()
439 				 << " - ";
440 
441 			result = false;
442 		}
443 	}
444 
445 	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
446 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer");
447 
448 	gl.deleteFramebuffers(1, &fbo);
449 	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteFramebuffers");
450 
451 	Texture::Delete(gl, verifyTexture);
452 
453 	return result;
454 }
455 
draw(GLint target,GLint layer,const ShaderProgram & program)456 void SparseTextureClampLookupResidencyTestCase::draw(GLint target, GLint layer, const ShaderProgram& program)
457 {
458 	const GLfloat texCoord1D[] = { 0.0f, 1.0f, 0.0f, 1.0f };
459 
460 	const GLfloat texCoord2D[] = {
461 		0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
462 	};
463 
464 	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 };
465 
466 	const GLfloat texCoordCubeMap[6][12] = {
467 		{ 0.0f, 0.0f, 0.00f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f },
468 		{ 0.0f, 0.0f, 0.17f, 1.0f, 0.0f, 0.17f, 0.0f, 1.0f, 0.17f, 1.0f, 1.0f, 0.17f },
469 		{ 0.0f, 0.0f, 0.33f, 1.0f, 0.0f, 0.33f, 0.0f, 1.0f, 0.33f, 1.0f, 1.0f, 0.33f },
470 		{ 0.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.5f, 0.0f, 1.0f, 0.5f, 1.0f, 1.0f, 0.5f },
471 		{ 0.0f, 0.0f, 0.67f, 1.0f, 0.0f, 0.67f, 0.0f, 1.0f, 0.67f, 1.0f, 1.0f, 0.67f },
472 		{ 0.0f, 0.0f, 0.83f, 1.0f, 0.0f, 0.83f, 0.0f, 1.0f, 0.83f, 1.0f, 1.0f, 0.83f }
473 	};
474 
475 	// The fragment shader uses (z * 6) % 6 to calculate a cube face index.
476 	GLfloat cubeMapArrayZCoord = GLfloat(layer) / 6.0f + 0.01f;
477 	// The fragment shader does not modify w for layer selection.
478 	GLfloat cubeMapArrayWCoord = GLfloat(layer / 6); // Note: integer division
479 	const GLfloat texCoordCubeMapArray[16] = { 0.0f, 0.0f, cubeMapArrayZCoord, cubeMapArrayWCoord,
480 											   1.0f, 0.0f, cubeMapArrayZCoord, cubeMapArrayWCoord,
481 											   0.0f, 1.0f, cubeMapArrayZCoord, cubeMapArrayWCoord,
482 											   1.0f, 1.0f, cubeMapArrayZCoord, cubeMapArrayWCoord };
483 
484 	const GLfloat vertices[] = {
485 		-1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f,
486 	};
487 
488 	const GLuint indices[] = { 0, 1, 2, 1, 2, 3 };
489 
490 	VertexArrayBinding floatCoord;
491 
492 	if (target == GL_TEXTURE_1D || target == GL_TEXTURE_1D_ARRAY)
493 		floatCoord = glu::va::Float("inCoord", 1, 4, 0, texCoord1D);
494 	else if (target == GL_TEXTURE_3D)
495 		floatCoord = glu::va::Float("inCoord", 3, 4, 0, texCoord3D);
496 	else if (target == GL_TEXTURE_CUBE_MAP)
497 		floatCoord = glu::va::Float("inCoord", 3, 4, 0, texCoordCubeMap[layer]);
498 	else if (target == GL_TEXTURE_CUBE_MAP_ARRAY)
499 		floatCoord = glu::va::Float("inCoord", 4, 4, 0, texCoordCubeMapArray);
500 	else
501 		floatCoord = glu::va::Float("inCoord", 2, 4, 0, texCoord2D);
502 
503 	glu::VertexArrayBinding vertexArrays[] = { glu::va::Float("vertex", 3, 4, 0, vertices), floatCoord };
504 
505 	glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), vertexArrays,
506 			  glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(indices), indices));
507 }
508 
509 /** Constructor.
510  *
511  *  @param context     Rendering context
512  */
SparseTextureClampLookupColorTestCase(deqp::Context & context)513 SparseTextureClampLookupColorTestCase::SparseTextureClampLookupColorTestCase(deqp::Context& context)
514 	: SparseTextureClampLookupResidencyTestCase(
515 		  context, "SparseTextureClampLookupColor",
516 		  "Verifies if sparse and non-sparse texture clamp lookup functions works as expected")
517 {
518 	/* Left blank intentionally */
519 }
520 
521 /** Stub init method */
init()522 void SparseTextureClampLookupColorTestCase::init()
523 {
524 	SparseTextureCommitmentTestCase::init();
525 	mSupportedTargets.push_back(GL_TEXTURE_1D);
526 	mSupportedTargets.push_back(GL_TEXTURE_1D_ARRAY);
527 	mSupportedInternalFormats.push_back(GL_DEPTH_COMPONENT16);
528 
529 	FunctionToken f;
530 	f = FunctionToken("sparseTextureClampARB", "<CUBE_REFZ_DEF>, <LOD>");
531 	f.allowedTargets.insert(GL_TEXTURE_2D);
532 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
533 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP);
534 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP_ARRAY);
535 	f.allowedTargets.insert(GL_TEXTURE_3D);
536 	mFunctions.push_back(f);
537 
538 	f = FunctionToken("textureClampARB", "<CUBE_REFZ_DEF>, <LOD>");
539 	f.allowedTargets.insert(GL_TEXTURE_1D);
540 	f.allowedTargets.insert(GL_TEXTURE_1D_ARRAY);
541 	f.allowedTargets.insert(GL_TEXTURE_2D);
542 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
543 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP);
544 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP_ARRAY);
545 	f.allowedTargets.insert(GL_TEXTURE_3D);
546 	mFunctions.push_back(f);
547 
548 	f = FunctionToken("sparseTextureOffsetClampARB", ", <OFFSET_TYPE><OFFSET_DIM>(0), <LOD>");
549 	f.allowedTargets.insert(GL_TEXTURE_2D);
550 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
551 	f.allowedTargets.insert(GL_TEXTURE_3D);
552 	mFunctions.push_back(f);
553 
554 	f = FunctionToken("textureOffsetClampARB", ", <OFFSET_TYPE><OFFSET_DIM>(0), <LOD>");
555 	f.allowedTargets.insert(GL_TEXTURE_1D);
556 	f.allowedTargets.insert(GL_TEXTURE_1D_ARRAY);
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("sparseTextureGradClampARB",
563 					  ", <NOFFSET_TYPE><OFFSET_DIM>(0), <NOFFSET_TYPE><OFFSET_DIM>(0), <LOD>");
564 	f.allowedTargets.insert(GL_TEXTURE_2D);
565 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
566 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP);
567 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP_ARRAY);
568 	f.allowedTargets.insert(GL_TEXTURE_3D);
569 	mFunctions.push_back(f);
570 
571 	f = FunctionToken("textureGradClampARB", ", <NOFFSET_TYPE><OFFSET_DIM>(0), <NOFFSET_TYPE><OFFSET_DIM>(0), <LOD>");
572 	f.allowedTargets.insert(GL_TEXTURE_1D);
573 	f.allowedTargets.insert(GL_TEXTURE_1D_ARRAY);
574 	f.allowedTargets.insert(GL_TEXTURE_2D);
575 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
576 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP);
577 	f.allowedTargets.insert(GL_TEXTURE_CUBE_MAP_ARRAY);
578 	f.allowedTargets.insert(GL_TEXTURE_3D);
579 	mFunctions.push_back(f);
580 
581 	f = FunctionToken(
582 		"sparseTextureGradOffsetClampARB",
583 		", <NOFFSET_TYPE><OFFSET_DIM>(0), <NOFFSET_TYPE><OFFSET_DIM>(0), <OFFSET_TYPE><OFFSET_DIM>(0), <LOD>");
584 	f.allowedTargets.insert(GL_TEXTURE_2D);
585 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
586 	f.allowedTargets.insert(GL_TEXTURE_3D);
587 	mFunctions.push_back(f);
588 
589 	f = FunctionToken(
590 		"textureGradOffsetClampARB",
591 		", <NOFFSET_TYPE><OFFSET_DIM>(0), <NOFFSET_TYPE><OFFSET_DIM>(0), <OFFSET_TYPE><OFFSET_DIM>(0), <LOD>");
592 	f.allowedTargets.insert(GL_TEXTURE_1D);
593 	f.allowedTargets.insert(GL_TEXTURE_1D_ARRAY);
594 	f.allowedTargets.insert(GL_TEXTURE_2D);
595 	f.allowedTargets.insert(GL_TEXTURE_2D_ARRAY);
596 	f.allowedTargets.insert(GL_TEXTURE_3D);
597 	mFunctions.push_back(f);
598 }
599 
600 /** Executes test iteration.
601  *
602  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
603  */
iterate()604 tcu::TestNode::IterateResult SparseTextureClampLookupColorTestCase::iterate()
605 {
606 	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_texture_clamp"))
607 	{
608 		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
609 		return STOP;
610 	}
611 
612 	const Functions& gl = m_context.getRenderContext().getFunctions();
613 
614 	bool result = true;
615 
616 	GLuint texture;
617 
618 	for (std::vector<glw::GLint>::const_iterator iter = mSupportedTargets.begin(); iter != mSupportedTargets.end();
619 		 ++iter)
620 	{
621 		const GLint& target = *iter;
622 
623 		for (std::vector<glw::GLint>::const_iterator formIter = mSupportedInternalFormats.begin();
624 			 formIter != mSupportedInternalFormats.end(); ++formIter)
625 		{
626 			const GLint& format = *formIter;
627 
628 			if (!caseAllowed(target, format))
629 				continue;
630 
631 			for (std::vector<FunctionToken>::const_iterator tokIter = mFunctions.begin(); tokIter != mFunctions.end();
632 				 ++tokIter)
633 			{
634 				// Check if target is allowed for current lookup function
635 				FunctionToken funcToken = *tokIter;
636 				if (!funcAllowed(target, format, funcToken))
637 					continue;
638 
639 				bool isSparse = false;
640 				if (funcToken.name.find("sparse", 0) != std::string::npos)
641 					isSparse = true;
642 
643 				mLog.str("");
644 				mLog << "Testing sparse texture lookup color functions for target: " << target << ", format: " << format
645 					 << " - ";
646 
647 				if (isSparse)
648 					sparseAllocateTexture(gl, target, format, texture, 3);
649 				else
650 					allocateTexture(gl, target, format, texture, 3);
651 
652 				if (format == GL_DEPTH_COMPONENT16)
653 					setupDepthMode(gl, target, texture);
654 
655 				int l;
656 				int maxLevels = 0;
657 				for (l = 0; l < mState.levels; ++l)
658 				{
659 					if (!isSparse || commitTexturePage(gl, target, format, texture, l))
660 					{
661 						writeDataToTexture(gl, target, format, texture, l);
662 						maxLevels = l;
663 					}
664 				}
665 
666 				for (l = 0; l <= maxLevels; ++l)
667 				{
668 					result = result && verifyLookupTextureData(gl, target, format, texture, l, funcToken);
669 
670 					if (!result)
671 						break;
672 				}
673 
674 				Texture::Delete(gl, texture);
675 
676 				if (!result)
677 				{
678 					m_testCtx.getLog() << tcu::TestLog::Message << mLog.str() << "Fail" << tcu::TestLog::EndMessage;
679 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
680 					return STOP;
681 				}
682 			}
683 		}
684 	}
685 
686 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
687 	return STOP;
688 }
689 
690 /** Writing data to generated texture using compute shader
691  *
692  * @param gl           GL API functions
693  * @param target       Target for which texture is binded
694  * @param format       Texture internal format
695  * @param texture      Texture object
696  *
697  * @return Returns true if no error occurred, otherwise throws an exception.
698  */
writeDataToTexture(const Functions & gl,GLint target,GLint format,GLuint & texture,GLint level)699 bool SparseTextureClampLookupColorTestCase::writeDataToTexture(const Functions& gl, GLint target, GLint format,
700 															   GLuint& texture, GLint level)
701 {
702 	mLog << "Fill Texture with shader [level: " << level << "] - ";
703 
704 	if (level > mState.levels - 1)
705 		TCU_FAIL("Invalid level");
706 
707 	GLint width;
708 	GLint height;
709 	GLint depth;
710 	SparseTextureUtils::getTextureLevelSize(target, mState, level, width, height, depth);
711 
712 	if (width > 0 && height > 0 && depth >= mState.minDepth)
713 	{
714 		if (target == GL_TEXTURE_CUBE_MAP)
715 			depth = depth * 6;
716 
717 		GLint texSize = width * height * depth * mState.format.getPixelSize();
718 
719 		std::vector<GLubyte> vecData;
720 		vecData.resize(texSize);
721 		GLubyte* data = vecData.data();
722 
723 		deMemset(data, 255, texSize);
724 
725 		for (GLint sample = 0; sample < mState.samples; ++sample)
726 		{
727 			std::string shader = stc_compute_textureFill;
728 
729 			// Adjust shader source to texture format
730 			TokenStrings s = createShaderTokens(target, format, sample);
731 
732 			GLint convFormat = format;
733 			if (format == GL_DEPTH_COMPONENT16)
734 				convFormat = GL_R16;
735 
736 			// Change expected result as it has to be adjusted to different levels
737 			s.resultExpected = generateExpectedResult(s.returnType, level, convFormat);
738 
739 			replaceToken("<INPUT_TYPE>", s.inputType.c_str(), shader);
740 			replaceToken("<POINT_TYPE>", s.pointType.c_str(), shader);
741 			replaceToken("<POINT_DEF>", s.pointDef.c_str(), shader);
742 			replaceToken("<RETURN_TYPE>", s.returnType.c_str(), shader);
743 			replaceToken("<RESULT_EXPECTED>", s.resultExpected.c_str(), shader);
744 			replaceToken("<SAMPLE_DEF>", s.sampleDef.c_str(), shader);
745 
746 			ProgramSources sources;
747 			sources << ComputeSource(shader);
748 
749 			// Build and run shader
750 			ShaderProgram program(m_context.getRenderContext(), sources);
751 			if (program.isOk())
752 			{
753 				gl.useProgram(program.getProgram());
754 				GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
755 				gl.bindImageTexture(0 /* unit */, texture, level /* level */, GL_TRUE /* layered */, 0 /* layer */,
756 									GL_WRITE_ONLY, convFormat);
757 				GLU_EXPECT_NO_ERROR(gl.getError(), "glBindImageTexture");
758 				gl.uniform1i(1, 0 /* image_unit */);
759 				GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i");
760 				gl.dispatchCompute(width, height, depth);
761 				GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute");
762 				gl.memoryBarrier(GL_ALL_BARRIER_BITS);
763 				GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier");
764 			}
765 			else
766 			{
767 				mLog << "Compute shader compilation failed (writing) for target: " << target << ", format: " << format
768 					 << ", sample: " << sample << ", infoLog: " << program.getShaderInfo(SHADERTYPE_COMPUTE).infoLog
769 					 << ", shaderSource: " << shader.c_str() << " - ";
770 			}
771 		}
772 	}
773 
774 	return true;
775 }
776 
777 /** Verify if data stored in texture is as expected
778  *
779  * @param gl           GL API functions
780  * @param target       Target for which texture is binded
781  * @param format       Texture internal format
782  * @param texture      Texture object
783  * @param level        Texture mipmap level
784  * @param funcToken    Lookup function tokenize structure
785  *
786  * @return Returns true if data is as expected, false if not, throws an exception if error occurred.
787  */
verifyLookupTextureData(const Functions & gl,GLint target,GLint format,GLuint & texture,GLint level,FunctionToken & funcToken)788 bool SparseTextureClampLookupColorTestCase::verifyLookupTextureData(const Functions& gl, GLint target, GLint format,
789 																	GLuint& texture, GLint level,
790 																	FunctionToken& funcToken)
791 {
792 	mLog << "Verify Lookup Color Texture Data [function: " << funcToken.name << ", level: " << level << "] - ";
793 
794 	if (level > mState.levels - 1)
795 		TCU_FAIL("Invalid level");
796 
797 	GLint width;
798 	GLint height;
799 	GLint depth;
800 	SparseTextureUtils::getTextureLevelSize(target, mState, level, width, height, depth);
801 
802 	if (width == 0 || height == 0 || depth < mState.minDepth)
803 		return true;
804 
805 	bool result = true;
806 
807 	if (target == GL_TEXTURE_CUBE_MAP)
808 		depth = depth * 6;
809 
810 	GLint texSize = width * height;
811 
812 	std::vector<GLubyte> vecExpData;
813 	std::vector<GLubyte> vecOutData;
814 	vecExpData.resize(texSize);
815 	vecOutData.resize(texSize);
816 	GLubyte* exp_data = vecExpData.data();
817 	GLubyte* out_data = vecOutData.data();
818 
819 	// Expected data is 255 because
820 	deMemset(exp_data, 255, texSize);
821 
822 	// Create verifying texture
823 	GLint  verifyTarget = GL_TEXTURE_2D;
824 	GLuint verifyTexture;
825 	Texture::Generate(gl, verifyTexture);
826 	Texture::Bind(gl, verifyTexture, verifyTarget);
827 	Texture::Storage(gl, verifyTarget, 1, GL_R8, width, height, depth);
828 	GLU_EXPECT_NO_ERROR(gl.getError(), "Texture::Storage");
829 
830 	GLuint fbo;
831 	gl.genFramebuffers(1, &fbo);
832 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers");
833 	gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
834 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer");
835 	gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, verifyTarget, verifyTexture, 0);
836 	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D");
837 
838 	gl.viewport(0, 0, width, height);
839 
840 	for (int sample = 0; sample < mState.samples; ++sample)
841 	{
842 		std::string vertex   = stc_vertex_common;
843 		std::string fragment = stc_fragment_lookupColor;
844 
845 		// Make token copy to work on
846 		FunctionToken f = funcToken;
847 
848 		std::string functionDef = generateFunctionDef(f.name);
849 
850 		// Adjust shader source to texture format
851 		TokenStringsExt s = createLookupShaderTokens(target, format, level, sample, f);
852 
853 		// Change expected result as it has to be adjusted to different levels
854 		s.resultExpected = generateExpectedResult(s.returnType, level, format);
855 
856 		replaceToken("<COORD_TYPE>", s.coordType.c_str(), vertex);
857 
858 		replaceToken("<FUNCTION_DEF>", functionDef.c_str(), fragment);
859 		replaceToken("<FUNCTION>", f.name.c_str(), fragment);
860 		replaceToken("<ARGUMENTS>", f.arguments.c_str(), fragment);
861 
862 		replaceToken("<OUTPUT_TYPE>", s.outputType.c_str(), fragment);
863 		replaceToken("<INPUT_TYPE>", s.inputType.c_str(), fragment);
864 		replaceToken("<SIZE_DEF>", s.sizeDef.c_str(), fragment);
865 		replaceToken("<LOD>", s.lod.c_str(), fragment);
866 		replaceToken("<LOD_DEF>", s.lodDef.c_str(), fragment);
867 		replaceToken("<COORD_TYPE>", s.coordType.c_str(), fragment);
868 		replaceToken("<ICOORD_TYPE>", s.coordType.c_str(), fragment);
869 		replaceToken("<COORD_DEF>", s.coordDef.c_str(), fragment);
870 		replaceToken("<POINT_TYPE>", s.pointType.c_str(), fragment);
871 		replaceToken("<POINT_DEF>", s.pointDef.c_str(), fragment);
872 		replaceToken("<RETURN_TYPE>", s.returnType.c_str(), fragment);
873 		replaceToken("<RESULT_EXPECTED>", s.resultExpected.c_str(), fragment);
874 		replaceToken("<EPSILON>", s.epsilon.c_str(), fragment);
875 		replaceToken("<SAMPLE_DEF>", s.sampleDef.c_str(), fragment);
876 		replaceToken("<REFZ_DEF>", s.refZDef.c_str(), fragment);
877 		replaceToken("<CUBE_REFZ_DEF>", s.cubeMapArrayRefZDef.c_str(), fragment);
878 		replaceToken("<POINT_COORD>", s.pointCoord.c_str(), fragment);
879 		replaceToken("<COMPONENT_DEF>", s.componentDef.c_str(), fragment);
880 		replaceToken("<CUBE_MAP_COORD_DEF>", s.cubeMapCoordDef.c_str(), fragment);
881 		replaceToken("<OFFSET_ARRAY_DEF>", s.offsetArrayDef.c_str(), fragment);
882 		replaceToken("<FORMAT_DEF>", s.formatDef.c_str(), fragment);
883 		replaceToken("<OFFSET_TYPE>", s.offsetType.c_str(), fragment);
884 		replaceToken("<NOFFSET_TYPE>", s.nOffsetType.c_str(), fragment);
885 		replaceToken("<OFFSET_DIM>", s.offsetDim.c_str(), fragment);
886 
887 		replaceToken("<TEX_WIDTH>", de::toString(width).c_str(), fragment);
888 		replaceToken("<TEX_HEIGHT>", de::toString(height).c_str(), fragment);
889 		replaceToken("<TEX_DEPTH>", de::toString(depth).c_str(), fragment);
890 
891 		ProgramSources sources = makeVtxFragSources(vertex.c_str(), fragment.c_str());
892 
893 		// Build and run shader
894 		ShaderProgram program(m_context.getRenderContext(), sources);
895 
896 		if (program.isOk())
897 		{
898 			for (GLint z = 0; z < depth; ++z)
899 			{
900 				deMemset(out_data, 0, texSize);
901 
902 				Texture::Bind(gl, verifyTexture, verifyTarget);
903 				Texture::SubImage(gl, verifyTarget, 0, 0, 0, 0, width, height, 0, GL_RED, GL_UNSIGNED_BYTE,
904 								  (GLvoid*)out_data);
905 				GLU_EXPECT_NO_ERROR(gl.getError(), "Texture::SubImage");
906 
907 				// Use shader
908 				gl.useProgram(program.getProgram());
909 				GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
910 
911 				// Pass input sampler/image to shader
912 				gl.activeTexture(GL_TEXTURE0);
913 				GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveTexture");
914 				gl.uniform1i(1, 0 /* sampler_unit */);
915 				GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i");
916 
917 				gl.bindTexture(target, texture);
918 				GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture");
919 
920 				gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
921 				draw(target, z, program);
922 
923 				Texture::Bind(gl, verifyTexture, verifyTarget);
924 				Texture::GetData(gl, 0, verifyTarget, GL_RED, GL_UNSIGNED_BYTE, (GLvoid*)out_data);
925 				GLU_EXPECT_NO_ERROR(gl.getError(), "Texture::GetData");
926 
927 				//Verify only committed region
928 				for (GLint y = 0; y < height; ++y)
929 					for (GLint x = 0; x < width; ++x)
930 					{
931 						GLubyte* dataRegion	= exp_data + x + y * width;
932 						GLubyte* outDataRegion = out_data + x + y * width;
933 						if (dataRegion[0] != outDataRegion[0])
934 							result = false;
935 					}
936 			}
937 		}
938 		else
939 		{
940 			mLog << "Shader compilation failed (lookup color) for target: " << target << ", format: " << format
941 				 << ", vertexInfoLog: " << program.getShaderInfo(SHADERTYPE_VERTEX).infoLog
942 				 << ", fragmentInfoLog: " << program.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog
943 				 << ", programInfoLog: " << program.getProgramInfo().infoLog << ", fragmentSource: " << fragment.c_str()
944 				 << " - ";
945 
946 			result = false;
947 		}
948 	}
949 
950 	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
951 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer");
952 
953 	gl.deleteFramebuffers(1, &fbo);
954 	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteFramebuffers");
955 
956 	Texture::Delete(gl, verifyTexture);
957 
958 	return result;
959 }
960 
961 /** Preparing texture. Function overridden to increase textures size.
962  *
963  * @param gl           GL API functions
964  * @param target       Target for which texture is binded
965  * @param format       Texture internal format
966  * @param texture      Texture object
967  *
968  * @return Returns true if no error occurred, otherwise throws an exception.
969  */
prepareTexture(const Functions & gl,GLint target,GLint format,GLuint & texture)970 bool SparseTextureClampLookupColorTestCase::prepareTexture(const Functions& gl, GLint target, GLint format,
971 														   GLuint& texture)
972 {
973 	Texture::Generate(gl, texture);
974 	Texture::Bind(gl, texture, target);
975 
976 	mState.minDepth = SparseTextureUtils::getTargetDepth(target);
977 	SparseTextureUtils::getTexturePageSizes(gl, target, format, mState.pageSizeX, mState.pageSizeY, mState.pageSizeZ);
978 
979 	//The <width> and <height> has to be equal for cube map textures
980 	if (target == GL_TEXTURE_CUBE_MAP || target == GL_TEXTURE_CUBE_MAP_ARRAY)
981 	{
982 		if (mState.pageSizeX > mState.pageSizeY)
983 			mState.pageSizeY = mState.pageSizeX;
984 		else if (mState.pageSizeX < mState.pageSizeY)
985 			mState.pageSizeX = mState.pageSizeY;
986 	}
987 
988 	mState.width  = 4 * mState.pageSizeX;
989 	mState.height = 4 * mState.pageSizeY;
990 	mState.depth  = 4 * mState.pageSizeZ * mState.minDepth;
991 
992 	mState.format = glu::mapGLInternalFormat(format);
993 
994 	return true;
995 }
996 
997 /** Commit texture page using texPageCommitment function. Function overridden to commit whole texture region.
998  *
999  * @param gl           GL API functions
1000  * @param target       Target for which texture is binded
1001  * @param format       Texture internal format
1002  * @param texture      Texture object
1003  * @param level        Texture mipmap level
1004  *
1005  * @return Returns true if commitment is done properly, false if commitment is not allowed or throws exception if error occurred.
1006  */
commitTexturePage(const Functions & gl,GLint target,GLint format,GLuint & texture,GLint level)1007 bool SparseTextureClampLookupColorTestCase::commitTexturePage(const Functions& gl, GLint target, GLint format,
1008 															  GLuint& texture, GLint level)
1009 {
1010 	mLog << "Commit Region [level: " << level << "] - ";
1011 
1012 	if (level > mState.levels - 1)
1013 		TCU_FAIL("Invalid level");
1014 
1015 	// Avoid not allowed commitments
1016 	if (!isInPageSizesRange(target, level) || !isPageSizesMultiplication(target, level))
1017 	{
1018 		mLog << "Skip commitment [level: " << level << "] - ";
1019 		return false;
1020 	}
1021 
1022 	GLint width;
1023 	GLint height;
1024 	GLint depth;
1025 	SparseTextureUtils::getTextureLevelSize(target, mState, level, width, height, depth);
1026 
1027 	if (target == GL_TEXTURE_CUBE_MAP)
1028 		depth = 6 * depth;
1029 
1030 	Texture::Bind(gl, texture, target);
1031 	texPageCommitment(gl, target, format, texture, level, 0, 0, 0, width, height, depth, GL_TRUE);
1032 	GLU_EXPECT_NO_ERROR(gl.getError(), "texPageCommitment");
1033 
1034 	return true;
1035 }
1036 
1037 /** Check if current texture size for level is greater or equal page size in a corresponding direction
1038  *
1039  * @param target  Target for which texture is binded
1040  * @param level   Texture mipmap level
1041  *
1042  * @return Returns true if the texture size condition is fulfilled, false otherwise.
1043  */
isInPageSizesRange(GLint target,GLint level)1044 bool SparseTextureClampLookupColorTestCase::isInPageSizesRange(GLint target, GLint level)
1045 {
1046 	GLint width;
1047 	GLint height;
1048 	GLint depth;
1049 	SparseTextureUtils::getTextureLevelSize(target, mState, level, width, height, depth);
1050 
1051 	if (target == GL_TEXTURE_CUBE_MAP)
1052 		depth = 6 * depth;
1053 
1054 	if (width >= mState.pageSizeX && height >= mState.pageSizeY && (mState.minDepth == 0 || depth >= mState.pageSizeZ))
1055 	{
1056 		return true;
1057 	}
1058 
1059 	return false;
1060 }
1061 
1062 /** Check if current texture size for level is page size multiplication in a corresponding direction
1063  *
1064  * @param target  Target for which texture is binded
1065  * @param level   Texture mipmap level
1066  *
1067  * @return Returns true if the texture size condition is fulfilled, false otherwise.
1068  */
isPageSizesMultiplication(GLint target,GLint level)1069 bool SparseTextureClampLookupColorTestCase::isPageSizesMultiplication(GLint target, GLint level)
1070 {
1071 	GLint width;
1072 	GLint height;
1073 	GLint depth;
1074 	SparseTextureUtils::getTextureLevelSize(target, mState, level, width, height, depth);
1075 
1076 	if (target == GL_TEXTURE_CUBE_MAP)
1077 		depth = 6 * depth;
1078 
1079 	if ((width % mState.pageSizeX) == 0 && (height % mState.pageSizeY) == 0 && (depth % mState.pageSizeZ) == 0)
1080 	{
1081 		return true;
1082 	}
1083 
1084 	return false;
1085 }
1086 
1087 /** Constructor.
1088  *
1089  * @param funcName Tested function name.
1090  *
1091  * @return Returns shader source code part that uses lookup function to fetch texel from texture.
1092  */
generateFunctionDef(std::string funcName)1093 std::string SparseTextureClampLookupColorTestCase::generateFunctionDef(std::string funcName)
1094 {
1095 	if (funcName.find("sparse", 0) != std::string::npos)
1096 	{
1097 		return std::string("    <FUNCTION>(uni_in,\n"
1098 						   "               <POINT_COORD><SAMPLE_DEF><ARGUMENTS>,\n"
1099 						   "               retValue<COMPONENT_DEF>);\n");
1100 	}
1101 	else
1102 	{
1103 		return std::string("    retValue<COMPONENT_DEF> = <FUNCTION>(uni_in,\n"
1104 						   "                                         <POINT_COORD><SAMPLE_DEF><ARGUMENTS>);\n");
1105 	}
1106 }
1107 
1108 /** Constructor.
1109  *
1110  * @param returnType Expected result variable type.
1111  *
1112  * @return Returns shader source token that represent expected lookup result value.
1113  */
generateExpectedResult(std::string returnType,GLint level,GLint format)1114 std::string SparseTextureClampLookupColorTestCase::generateExpectedResult(std::string returnType, GLint level,
1115 																		  GLint format)
1116 {
1117 	if (format == GL_DEPTH_COMPONENT16)
1118 		return std::string("(1, 0, 0, 0)");
1119 	else if (returnType == "vec4")
1120 		return std::string("(") + de::toString(0.5f + (float)level / 10) + std::string(", 0, 0, 1)");
1121 	else
1122 		return std::string("(") + de::toString(level * 10) + std::string(", 0, 0, 1)");
1123 }
1124 
1125 /** Constructor.
1126  *
1127  *  @param context Rendering context.
1128  */
SparseTextureClampTests(deqp::Context & context)1129 SparseTextureClampTests::SparseTextureClampTests(deqp::Context& context)
1130 	: TestCaseGroup(context, "sparse_texture_clamp_tests",
1131 					"Verify conformance of CTS_ARB_sparse_texture_clamp implementation")
1132 {
1133 }
1134 
1135 /** Initializes the test group contents. */
init()1136 void SparseTextureClampTests::init()
1137 {
1138 	addChild(new ShaderExtensionTestCase(m_context, "GL_ARB_sparse_texture_clamp"));
1139 	addChild(new SparseTextureClampLookupResidencyTestCase(m_context));
1140 	addChild(new SparseTextureClampLookupColorTestCase(m_context));
1141 }
1142 
1143 } /* gl4cts namespace */
1144