• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2024 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  glcTextureLodBiasTests.cpp
27  * \brief Conformance tests for the texture lod bias functionality.
28  */ /*-------------------------------------------------------------------*/
29 
30 #include "deMath.h"
31 
32 #include "glcTextureLodBiasTests.hpp"
33 #include "gluContextInfo.hpp"
34 #include "gluDefs.hpp"
35 #include "gluShaderProgram.hpp"
36 #include "glwEnums.hpp"
37 #include "glwFunctions.hpp"
38 #include "tcuRenderTarget.hpp"
39 #include "tcuTestLog.hpp"
40 #include "tcuStringTemplate.hpp"
41 
42 #include <cmath>
43 
44 using namespace glw;
45 using namespace glu;
46 
47 namespace
48 {
49 const GLuint LEVELS = 8;
50 
51 /* full screen quad */
52 const float quad[] = {-1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f,
53                       -1.0f, 1.0f,  0.0f, 1.0f, 1.0f, 1.0f,  0.0f, 1.0f};
54 
55 /* constant array table */
56 const GLubyte COLORS[LEVELS + 1][4] = {
57     {255, 0, 0, 255},     // red
58     {0, 255, 0, 255},     // green
59     {0, 0, 255, 255},     // blue
60     {255, 255, 0, 255},   // yellow
61     {0, 255, 255, 255},   // cyan
62     {255, 0, 255, 255},   // purple
63     {255, 128, 128, 255}, // light red
64     {128, 255, 128, 255}, // light green
65     {128, 128, 255, 255}, // light blue
66 };
67 
68 /* maually calculate the result of texturing */
69 /* returned to parameter r. */
colorTexturing(const glw::Functions & gl,float lodBase,float lodBiasSum,float lodMin,float lodMax,int levelBase,int levelMax,int levelBaseMaxSize,GLenum magFilter,GLenum minFilter,bool mipmap,GLubyte * colors,GLubyte * r)70 void colorTexturing(const glw::Functions &gl, float lodBase, float lodBiasSum, float lodMin, float lodMax,
71                     int levelBase, int levelMax, int levelBaseMaxSize, GLenum magFilter, GLenum minFilter, bool mipmap,
72                     GLubyte *colors, GLubyte *r)
73 {
74     float lodConstant = 0.f, lod = 0.f;
75     int d1 = 0, d2 = 0;
76 
77     auto copy_pixel = [](GLubyte *dst, GLubyte *src)
78     {
79         dst[0] = src[0];
80         dst[1] = src[1];
81         dst[2] = src[2];
82         dst[3] = src[3];
83     };
84 
85     if (!mipmap)
86     {
87         /* When not mipmapped, level base is used */
88         d1 = levelBase;
89         copy_pixel(r, &colors[d1 * 4]);
90         return;
91     }
92 
93     /* Mipmapped */
94     /* Check the constant divide the mag or min filter */
95     if ((magFilter == GL_LINEAR) &&
96         ((minFilter == GL_NEAREST_MIPMAP_NEAREST) || (minFilter == GL_NEAREST_MIPMAP_LINEAR)))
97     {
98         lodConstant = 0.5f;
99     }
100     else
101     {
102         lodConstant = 0.0f;
103     }
104 
105     /* Get final lod which is clamp */
106     lod = lodBase;
107     if (lodBiasSum != 0.0f)
108     {
109         float maxLodBias;
110         gl.getFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxLodBias);
111         GLU_EXPECT_NO_ERROR(gl.getError(), "getFloatv");
112 
113         if (lodBiasSum > maxLodBias)
114         {
115             lodBiasSum = maxLodBias;
116         }
117         else if (lodBiasSum < -maxLodBias)
118         {
119             lodBiasSum = -maxLodBias;
120         }
121         lod += lodBiasSum;
122     }
123     if (lod < lodMin)
124     {
125         lod = lodMin;
126     }
127     else if (lod > lodMax)
128     {
129         lod = lodMax;
130     }
131 
132     /* Check which filter is to use */
133     if (lod > lodConstant)
134     {
135         /* Min filter */
136         int p, q, tempMaxSize = 1;
137         int log2TempMaxSize = 0;
138 
139         /* Calculate the max level */
140 
141         while (tempMaxSize * 2 <= levelBaseMaxSize)
142         {
143             log2TempMaxSize += 1;
144             tempMaxSize <<= 1;
145         }
146 
147         p = log2TempMaxSize + levelBase;
148         q = levelMax;
149         if (p < q)
150         {
151             q = p;
152         }
153 
154         if ((minFilter == GL_NEAREST) || (minFilter == GL_LINEAR))
155         {
156             /* base level is used */
157             d1 = levelBase;
158             copy_pixel(r, &colors[d1 * 4]);
159             return;
160         }
161         else if ((minFilter == GL_NEAREST_MIPMAP_NEAREST) || (minFilter == GL_LINEAR_MIPMAP_NEAREST))
162         {
163             /* only one array is selected */
164             if (lod <= 0.5f)
165             {
166                 d1 = levelBase;
167             }
168             else if (levelBase + lod <= q + 0.5f)
169             {
170                 d1 = (int)ceil(levelBase + lod + 0.5f) - 1;
171             }
172             else
173             {
174                 d1 = q;
175             }
176 
177             copy_pixel(r, &colors[d1 * 4]);
178             return;
179         }
180         else
181         {
182             float fracLod;
183             int i;
184 
185             /* interplate between two arrays */
186             if (levelBase + lod >= q)
187             {
188                 d1 = q;
189                 d2 = q;
190             }
191             else
192             {
193                 d1 = (int)floor(levelBase + lod);
194                 d2 = d1 + 1;
195             }
196 
197             fracLod = (float)fmod(lod, 1.0f);
198 
199             for (i = 0; i < 4; ++i)
200             {
201                 r[i] = (GLubyte)((1.0f - fracLod) * (float)colors[d1 * 4 + i] + fracLod * (float)colors[d2 * 4 + i]);
202             }
203 
204             return;
205         }
206     }
207     else
208     {
209         /* Mag filter, base level is used */
210         d1 = levelBase;
211         copy_pixel(r, &colors[d1 * 4]);
212         return;
213     }
214 }
215 
216 } // namespace
217 
218 namespace glcts
219 {
220 
221 // clang-format off
222 /** @brief Vertex shader source code to test vertex lookup texture lod bias. */
223 const glw::GLchar* glcts::TextureLodBiasAllTestCase::m_vert_shader_sampler_vert =
224     R"(${VERSION}
225     ${EXTENSION}
226 
227     in vec4 vertex;
228     out vec4 tex;
229 
230     uniform float      lodbase;
231     uniform sampler2D texture0;
232 
233     void main(void)
234     {
235         gl_Position = vertex;
236         tex = textureLod(texture0, vertex.xy * 0.5 + 0.5, lodbase);
237     }
238     )";
239 
240 /** @brief Fragment shader source code to test vertex lookup texture lod bias. */
241 const glw::GLchar* glcts::TextureLodBiasAllTestCase::m_frag_shader_sampler_vert =
242     R"(${VERSION}
243     ${PRECISION}
244 
245     in vec4     tex;
246     out vec4 frag;
247 
248     void main(void)
249     {
250         frag = tex;
251     }
252     )";
253 
254 /** @brief Vertex shader source code to test fragment lookup texture lod bias. */
255 const glw::GLchar* glcts::TextureLodBiasAllTestCase::m_vert_shader_sampler_frag =
256     R"(${VERSION}
257     ${EXTENSION}
258 
259     in vec4 vertex;
260     out vec2 tex;
261 
262     void main(void)
263     {
264         gl_Position = vertex;
265         tex.xy = vertex.xy * 0.5 + 0.5;
266     }
267     )";
268 
269 /** @brief Fragment shader source code to test fragment lookup texture lod bias. */
270 const glw::GLchar* glcts::TextureLodBiasAllTestCase::m_frag_shader_sampler_frag =
271     R"(${VERSION}
272     ${PRECISION}
273 
274     in vec2 tex;
275     out vec4 frag;
276 
277     uniform float      biasshader;
278     uniform float      scale;
279     uniform sampler2D texture0;
280 
281     void main(void)
282     {
283         frag = texture(texture0, vec2(scale * tex.x, 0), biasshader);
284     }
285     )";
286 // clang-format on
287 
288 /** Constructor.
289  *
290  *  @param context     Rendering context
291  */
TextureLodBiasAllTestCase(deqp::Context & context)292 TextureLodBiasAllTestCase::TextureLodBiasAllTestCase(deqp::Context &context)
293     : TestCase(context, "texture_lod_bias_all", "Verifies most of biases combinations from the possible ranges")
294     , m_texture(0)
295     , m_target(0)
296     , m_fbo(0)
297     , m_vao(0)
298     , m_vbo(0)
299     , m_isContextES(false)
300     , m_testSupported(false)
301     , m_vertexLookupSupported(true)
302 {
303 }
304 
305 /** Stub deinit method. */
deinit()306 void TextureLodBiasAllTestCase::deinit()
307 {
308     /* Left blank intentionally */
309 }
310 
311 /** Stub init method */
init()312 void TextureLodBiasAllTestCase::init()
313 {
314     const glu::RenderContext &renderContext = m_context.getRenderContext();
315     glu::GLSLVersion glslVersion            = glu::getContextTypeGLSLVersion(renderContext.getType());
316     m_isContextES                           = glu::isContextTypeES(renderContext.getType());
317 
318     specializationMap["VERSION"]   = glu::getGLSLVersionDeclaration(glslVersion);
319     specializationMap["EXTENSION"] = "";
320     specializationMap["PRECISION"] = "";
321 
322     if (m_isContextES)
323     {
324         specializationMap["PRECISION"] = "precision highp float;";
325     }
326 
327     auto contextType = m_context.getRenderContext().getType();
328     if (m_isContextES)
329     {
330         m_maxErrorTolerance = 11;
331         if (glu::contextSupports(contextType, glu::ApiType::es(3, 0)))
332         {
333             m_testSupported = true;
334         }
335         else
336         {
337             m_testSupported = m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_lod_bias");
338             if (m_testSupported)
339                 specializationMap["EXTENSION"] = "#extension GL_EXT_texture_lod_bias : enable";
340             m_vertexLookupSupported = false;
341         }
342     }
343     else
344     {
345         m_maxErrorTolerance = 5;
346         /* This test should only be executed if we're running a GL>=3.0 context */
347         if (glu::contextSupports(contextType, glu::ApiType::core(3, 0)))
348         {
349             m_testSupported = true;
350         }
351     }
352 }
353 
354 /** Executes test iteration.
355  *
356  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
357  */
iterate()358 tcu::TestNode::IterateResult TextureLodBiasAllTestCase::iterate()
359 {
360     if (!m_testSupported)
361     {
362         throw tcu::NotSupportedError("Test texture_lod_bias_all is not supported");
363         return STOP;
364     }
365 
366     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
367 
368     bool returnvalue  = true;
369     const int SAMPLES = 128;
370     int failedbiases  = 0;
371     GLfloat m         = 0.f;
372 
373     gl.getFloatv(GL_MAX_TEXTURE_LOD_BIAS, &m);
374     GLU_EXPECT_NO_ERROR(gl.getError(), "getFloatv");
375 
376     createRenderingResources();
377 
378     failedbiases = 0;
379 
380     auto create_program = [&](const std::string &vert, const std::string &frag)
381     {
382         /* vertex shader test */
383         std::string vshader = tcu::StringTemplate(vert).specialize(specializationMap);
384         std::string fshader = tcu::StringTemplate(frag).specialize(specializationMap);
385 
386         ProgramSources sources = makeVtxFragSources(vshader, fshader);
387         return ShaderProgram(gl, sources);
388     };
389 
390     ShaderProgram program_vert = create_program(m_vert_shader_sampler_vert, m_frag_shader_sampler_vert);
391 
392     if (!program_vert.isOk())
393     {
394         m_testCtx.getLog() << tcu::TestLog::Message << "Shader build failed.\n"
395                            << "Vertex: " << program_vert.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n"
396                            << program_vert.getShader(SHADERTYPE_VERTEX)->getSource() << "\n"
397                            << "Fragment: " << program_vert.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n"
398                            << program_vert.getShader(SHADERTYPE_FRAGMENT)->getSource() << "\n"
399                            << "Program: " << program_vert.getProgramInfo().infoLog << tcu::TestLog::EndMessage;
400         TCU_FAIL("Compile failed");
401     }
402 
403     /* fragment shader test */
404     setBuffers(program_vert);
405 
406     for (int i = 0; i < SAMPLES; ++i)
407     {
408         /* this is the texture object bias */
409         float f = m * (((float)i / (float)(SAMPLES - 1)) * 2.0f - 1.0f);
410 
411         for (int j = 0; j < SAMPLES; ++j)
412         {
413             /* this is the shader bias */
414             float g = m * (((float)j / (float)(SAMPLES - 1)) * 2.0f - 1.0f);
415 
416             if (drawQuad(program_vert.getProgram(), true, 0.0f, f, g, -1000.0f, 1000.0f) == false)
417             {
418                 returnvalue = false;
419                 ++failedbiases;
420                 break;
421             }
422         }
423         if (returnvalue == false)
424             break;
425     }
426 
427     releaseBuffers();
428 
429     ShaderProgram program_frag = create_program(m_vert_shader_sampler_frag, m_frag_shader_sampler_frag);
430 
431     if (!program_frag.isOk())
432     {
433         m_testCtx.getLog() << tcu::TestLog::Message << "Shader build failed.\n"
434                            << "Vertex: " << program_frag.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n"
435                            << program_frag.getShader(SHADERTYPE_VERTEX)->getSource() << "\n"
436                            << "Fragment: " << program_frag.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n"
437                            << program_frag.getShader(SHADERTYPE_FRAGMENT)->getSource() << "\n"
438                            << "Program: " << program_frag.getProgramInfo().infoLog << tcu::TestLog::EndMessage;
439         TCU_FAIL("Compile failed");
440     }
441 
442     /* fragment shader test */
443     setBuffers(program_frag);
444 
445     for (int i = 0; i < SAMPLES; ++i)
446     {
447         /* this is the texture object bias */
448         float f = m * (((float)i / (float)(SAMPLES - 1)) * 2.0f - 1.0f);
449 
450         for (int j = 0; j < SAMPLES; ++j)
451         {
452             /* this is the shader bias */
453             float g = m * (((float)j / (float)(SAMPLES - 1)) * 2.0f - 1.0f);
454 
455             if (drawQuad(program_frag.getProgram(), false, 0.0f, f, g, -1000.0f, 1000.0f) == false)
456             {
457                 returnvalue = false;
458                 ++failedbiases;
459                 break;
460             }
461         }
462         if (returnvalue == false)
463             break;
464     }
465 
466     releaseBuffers();
467 
468     if (failedbiases > 0)
469     {
470         m_testCtx.getLog() << tcu::TestLog::Message
471                            << "Total failed lod bias combinations (vertex shader): " << failedbiases
472                            << tcu::TestLog::EndMessage;
473     }
474 
475     // Release texture
476     releaseRenderingResources();
477 
478     if (returnvalue)
479         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
480     else
481         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
482     return STOP;
483 }
484 
485 /* function activates the program that is given as a argument */
486 /* and sets vertex and texture attributes */
setBuffers(const glu::ShaderProgram & program)487 void TextureLodBiasAllTestCase::setBuffers(const glu::ShaderProgram &program)
488 {
489     if (program.isOk())
490     {
491         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
492 
493         gl.genVertexArrays(1, &m_vao);
494         GLU_EXPECT_NO_ERROR(gl.getError(), "genVertexArrays");
495         gl.bindVertexArray(m_vao);
496         GLU_EXPECT_NO_ERROR(gl.getError(), "bindVertexArray");
497 
498         gl.genBuffers(1, &m_vbo);
499         GLU_EXPECT_NO_ERROR(gl.getError(), "genBuffers");
500         gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo);
501         GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer");
502 
503         gl.bufferData(GL_ARRAY_BUFFER, sizeof(quad), (GLvoid *)quad, GL_DYNAMIC_DRAW);
504         GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData");
505 
506         GLint locVertices = -1;
507         GLint locTexture  = -1;
508 
509         gl.useProgram(program.getProgram());
510         GLU_EXPECT_NO_ERROR(gl.getError(), "useProgram");
511 
512         locVertices = gl.getAttribLocation(program.getProgram(), "vertex");
513         if (locVertices != -1)
514         {
515             gl.enableVertexAttribArray(0);
516             GLU_EXPECT_NO_ERROR(gl.getError(), "enableVertexAttribArray");
517 
518             GLuint strideSize = sizeof(quad) / 4;
519 
520             gl.vertexAttribPointer(locVertices, 4, GL_FLOAT, GL_FALSE, strideSize, nullptr);
521             GLU_EXPECT_NO_ERROR(gl.getError(), "vertexAttribPointer");
522         }
523 
524         locTexture = gl.getUniformLocation(program.getProgram(), "texture0");
525         if (locTexture != -1)
526         {
527             gl.uniform1i(locTexture, 0);
528             GLU_EXPECT_NO_ERROR(gl.getError(), "uniform1i");
529         }
530     }
531 }
532 
533 /* function releases vertex buffers */
releaseBuffers()534 void TextureLodBiasAllTestCase::releaseBuffers()
535 {
536     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
537     gl.disableVertexAttribArray(0);
538     GLU_EXPECT_NO_ERROR(gl.getError(), "disableVertexAttribArray");
539 
540     if (m_vbo)
541     {
542         gl.deleteBuffers(1, &m_vbo);
543         GLU_EXPECT_NO_ERROR(gl.getError(), "deleteBuffers");
544         m_vbo = 0;
545     }
546 
547     if (m_vao)
548     {
549         gl.deleteVertexArrays(1, &m_vao);
550         GLU_EXPECT_NO_ERROR(gl.getError(), "deleteVertexArrays");
551         m_vao = 0;
552     }
553 }
554 
555 /** Texture is generated from constant color array.
556  */
createRenderingResources()557 void TextureLodBiasAllTestCase::createRenderingResources()
558 {
559     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
560 
561     // setup fbo along with attached color texture
562     gl.genTextures(1, &m_target);
563     GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures");
564 
565     gl.bindTexture(GL_TEXTURE_2D, m_target);
566     GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture");
567 
568     gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
569     GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D");
570 
571     gl.genFramebuffers(1, &m_fbo);
572     GLU_EXPECT_NO_ERROR(gl.getError(), "genFramebuffers");
573 
574     gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);
575     GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer");
576 
577     gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
578     GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer");
579 
580     gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_target, 0);
581     GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D");
582 
583     // setup testing texture
584     GLuint texturesize = 1 << LEVELS;
585     std::vector<GLubyte> data(texturesize * texturesize * 3);
586 
587     gl.pixelStorei(GL_UNPACK_ALIGNMENT, 1);
588     GLU_EXPECT_NO_ERROR(gl.getError(), "pixelStorei");
589 
590     gl.genTextures(1, &m_texture);
591     GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures");
592 
593     gl.bindTexture(GL_TEXTURE_2D, m_texture);
594     GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture");
595 
596     gl.viewport(0, 0, texturesize, texturesize);
597     GLU_EXPECT_NO_ERROR(gl.getError(), "viewport");
598 
599     for (GLuint j = 0; j <= LEVELS; ++j)
600     {
601         for (GLuint i = 0; i < texturesize * texturesize; ++i)
602         {
603             data[i * 3 + 0] = COLORS[j][0];
604             data[i * 3 + 1] = COLORS[j][1];
605             data[i * 3 + 2] = COLORS[j][2];
606         }
607 
608         gl.texImage2D(GL_TEXTURE_2D, j, GL_RGB, texturesize, texturesize, 0, GL_RGB, GL_UNSIGNED_BYTE, data.data());
609         GLU_EXPECT_NO_ERROR(gl.getError(), "texImage2D");
610 
611         texturesize = texturesize >> 1;
612     }
613 
614     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
615     GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri");
616 
617     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
618     GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri");
619 }
620 
621 /** Render full screen textured quad.
622  *  @return Returns true if no error occured, false otherwise.
623  */
drawQuad(GLuint program,bool bVertexshader,float lodbase,float statebias,float shaderbias,float lodMin,float lodMax)624 bool TextureLodBiasAllTestCase::drawQuad(GLuint program, bool bVertexshader, float lodbase, float statebias,
625                                          float shaderbias, float lodMin, float lodMax)
626 {
627     const glw::Functions &gl  = m_context.getRenderContext().getFunctions();
628     GLubyte expectedresult[4] = {0, 0, 0, 0};
629     GLubyte readdata[]        = {0, 0, 0, 0};
630     GLfloat biasSum           = statebias + shaderbias;
631     GLint lodbaseLoc = 0, biasLoc = 0, scaleLoc = 0;
632     GLint epsilon   = 0;
633     GLint precision = 0;
634 
635     float savedStatebias  = statebias;
636     float savedShaderbias = shaderbias;
637 
638     if (bVertexshader)
639     {
640         if (!m_vertexLookupSupported)
641         {
642             /* Vertex shader is tested with textureLod and TEXTURE_LOD_BIAS,
643                which should be skipped for GLES ES version prior 3.0.
644              */
645             return true;
646         }
647 
648         lodbaseLoc = gl.getUniformLocation(program, "lodbase");
649         if (lodbaseLoc == -1)
650         {
651             m_testCtx.getLog() << tcu::TestLog::Message << "Couldn't get shader uniform lodbase."
652                                << tcu::TestLog::EndMessage;
653             return false;
654         }
655 
656         /* Shader bias is not used and is accumulated into state bias */
657         statebias = biasSum;
658         if (!m_isContextES)
659         {
660             gl.texParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, statebias);
661             GLU_EXPECT_NO_ERROR(gl.getError(), "texParameterf");
662 
663             /* Explicit lodbase value for textureLod */
664             gl.uniform1f(lodbaseLoc, lodbase);
665         }
666         else
667         {
668             /* ES does not have state bias, so accumulate it into shader bias */
669             gl.uniform1f(lodbaseLoc, biasSum);
670         }
671 
672         GLU_EXPECT_NO_ERROR(gl.getError(), "uniform1f");
673     }
674     else
675     {
676         biasLoc  = gl.getUniformLocation(program, "biasshader");
677         scaleLoc = gl.getUniformLocation(program, "scale");
678         if ((biasLoc) == -1 || (scaleLoc) == -1)
679         {
680             m_testCtx.getLog() << tcu::TestLog::Message << "Couldn't get shader uniform(s) biasshader or/and scale."
681                                << tcu::TestLog::EndMessage;
682             return false;
683         }
684 
685         if (!m_isContextES)
686         {
687             gl.texParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, statebias);
688             GLU_EXPECT_NO_ERROR(gl.getError(), "texParameterf");
689         }
690         else
691         {
692             /* ES does not have state bias, so accumulate it into shader bias */
693             shaderbias = biasSum;
694         }
695 
696         gl.uniform1f(biasLoc, shaderbias);
697         GLU_EXPECT_NO_ERROR(gl.getError(), "uniform1f");
698 
699         /* Setup scale to get proper lodbase */
700         gl.uniform1f(scaleLoc, (float)pow(2.0f, lodbase));
701         GLU_EXPECT_NO_ERROR(gl.getError(), "uniform1f");
702     }
703 
704     gl.texParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, lodMin);
705     GLU_EXPECT_NO_ERROR(gl.getError(), "texParameterf");
706 
707     gl.texParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, lodMax);
708     GLU_EXPECT_NO_ERROR(gl.getError(), "texParameterf");
709 
710     gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
711     GLU_EXPECT_NO_ERROR(gl.getError(), "clearColor");
712     gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
713     GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
714 
715     gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
716     GLU_EXPECT_NO_ERROR(gl.getError(), "drawArrays");
717 
718     /* one pixel is read */
719     gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, readdata);
720     GLU_EXPECT_NO_ERROR(gl.getError(), "readPixels");
721 
722     colorTexturing(gl, lodbase, biasSum, lodMin, lodMax, 0, 8, 1 << LEVELS, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true,
723                    (GLubyte *)COLORS, expectedresult);
724 
725     precision = m_context.getRenderTarget().getPixelFormat().redBits;
726     epsilon   = std::max(256 / (1 << precision), m_maxErrorTolerance);
727 
728     if (std::fabs(readdata[0] - expectedresult[0]) > epsilon || std::fabs(readdata[1] - expectedresult[1]) > epsilon ||
729         std::fabs(readdata[2] - expectedresult[2]) > epsilon || std::fabs(readdata[3] - expectedresult[3]) > epsilon)
730     {
731         char textBuf[512] = {0};
732         std::snprintf(textBuf, 512, "texture bias (%f), shader bias(%f), sum(%f): %d %d %d %d != %d %d %d %d",
733                       savedStatebias, savedShaderbias, savedStatebias + savedShaderbias, readdata[0], readdata[1],
734                       readdata[2], readdata[3], expectedresult[0], expectedresult[1], expectedresult[2],
735                       expectedresult[3]);
736         m_testCtx.getLog() << tcu::TestLog::Message << textBuf << tcu::TestLog::EndMessage;
737         return false;
738     }
739     else
740     {
741         return true;
742     }
743 }
744 
745 /** Release texture.
746  *
747  *  @param gl  OpenGL functions wrapper
748  */
releaseRenderingResources()749 void TextureLodBiasAllTestCase::releaseRenderingResources()
750 {
751     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
752 
753     if (m_texture)
754     {
755         gl.deleteTextures(1, &m_texture);
756         GLU_EXPECT_NO_ERROR(gl.getError(), "deleteTextures");
757     }
758 
759     if (m_target)
760     {
761         gl.deleteTextures(1, &m_target);
762         GLU_EXPECT_NO_ERROR(gl.getError(), "deleteTextures");
763     }
764 
765     if (m_fbo)
766     {
767         gl.deleteFramebuffers(1, &m_fbo);
768         GLU_EXPECT_NO_ERROR(gl.getError(), "deleteTextures");
769     }
770 
771     m_texture = 0;
772     m_target  = 0;
773     m_fbo     = 0;
774 }
775 
776 /** Constructor.
777  *
778  *  @param context Rendering context.
779  */
TextureLodBiasTests(deqp::Context & context)780 TextureLodBiasTests::TextureLodBiasTests(deqp::Context &context)
781     : TestCaseGroup(context, "texture_lod_bias", "Verify conformance of texture lod bias functionality")
782 {
783 }
784 
785 /** Initializes the test group contents. */
init()786 void TextureLodBiasTests::init()
787 {
788     addChild(new TextureLodBiasAllTestCase(m_context));
789 }
790 
791 } // namespace glcts
792