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