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