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
45using namespace glw;
46using namespace glu;
47
48namespace gl4cts
49{
50
51const 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
65const 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
77const 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
135const 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 */
175SparseTextureClampLookupResidencyTestCase::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 */
187SparseTextureClampLookupResidencyTestCase::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 */
196void 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 */
238tcu::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 */
257bool 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 */
283bool 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	}
452out:
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
464void 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 */
521SparseTextureClampLookupColorTestCase::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 */
530void 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 */
612tcu::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 */
707bool 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 */
801bool 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 */
985bool 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 */
1022bool 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 */
1059bool 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 */
1084bool 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 */
1108std::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 */
1129std::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 */
1144SparseTextureClampTests::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. */
1151void 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