1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
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 Special float stress tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es3sSpecialFloatTests.hpp"
25 #include "gluRenderContext.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "gluPixelTransfer.hpp"
28 #include "gluStrUtil.hpp"
29 #include "gluContextInfo.hpp"
30 #include "glwEnums.hpp"
31 #include "glwFunctions.hpp"
32 #include "tcuRenderTarget.hpp"
33 #include "tcuSurface.hpp"
34 #include "tcuTestLog.hpp"
35 #include "tcuVectorUtil.hpp"
36 #include "deStringUtil.hpp"
37 #include "deMath.h"
38 #include "deRandom.hpp"
39
40 #include <limits>
41 #include <sstream>
42
43 using namespace glw;
44
45 namespace deqp
46 {
47 namespace gles3
48 {
49 namespace Stress
50 {
51 namespace
52 {
53
54 static const int TEST_CANVAS_SIZE = 256;
55 static const int TEST_TEXTURE_SIZE = 128;
56 static const int TEST_TEXTURE_CUBE_SIZE = 32;
57 static const uint32_t s_specialFloats[] = {
58 0x00000000, // zero
59 0x80000000, // negative zero
60 0x3F800000, // one
61 0xBF800000, // negative one
62 0x00800000, // minimum positive normalized value
63 0x80800000, // maximum negative normalized value
64 0x00000001, // minimum positive denorm value
65 0x80000001, // maximum negative denorm value
66 0x7F7FFFFF, // maximum finite value.
67 0xFF7FFFFF, // minimum finite value.
68 0x7F800000, // inf
69 0xFF800000, // -inf
70 0x34000000, // epsilon
71 0xB4000000, // negative epsilon
72 0x7FC00000, // quiet_NaN
73 0xFFC00000, // negative quiet_NaN
74 0x7FC00001, // signaling_NaN
75 0xFFC00001, // negative signaling_NaN
76 0x7FEAAAAA, // quiet payloaded NaN (payload of repeated pattern of 101010...)
77 0xFFEAAAAA, // negative quiet payloaded NaN ( .. )
78 0x7FAAAAAA, // signaling payloaded NaN ( .. )
79 0xFFAAAAAA, // negative signaling payloaded NaN ( .. )
80 };
81
82 static const char *const s_colorPassthroughFragmentShaderSource = "#version 300 es\n"
83 "layout(location = 0) out mediump vec4 fragColor;\n"
84 "in mediump vec4 v_out;\n"
85 "void main ()\n"
86 "{\n"
87 " fragColor = v_out;\n"
88 "}\n";
89 static const char *const s_attrPassthroughVertexShaderSource = "#version 300 es\n"
90 "in highp vec4 a_pos;\n"
91 "in highp vec4 a_attr;\n"
92 "out highp vec4 v_attr;\n"
93 "void main ()\n"
94 "{\n"
95 " v_attr = a_attr;\n"
96 " gl_Position = a_pos;\n"
97 "}\n";
98
99 class RenderCase : public TestCase
100 {
101 public:
102 enum RenderTargetType
103 {
104 RENDERTARGETTYPE_SCREEN,
105 RENDERTARGETTYPE_FBO
106 };
107
108 RenderCase(Context &context, const char *name, const char *desc,
109 RenderTargetType renderTargetType = RENDERTARGETTYPE_SCREEN);
110 virtual ~RenderCase(void);
111
112 virtual void init(void);
113 virtual void deinit(void);
114
115 protected:
116 bool checkResultImage(const tcu::Surface &result);
117 bool drawTestPattern(bool useTexture);
118
119 virtual std::string genVertexSource(void) const = 0;
120 virtual std::string genFragmentSource(void) const = 0;
121
122 const glu::ShaderProgram *m_program;
123 const RenderTargetType m_renderTargetType;
124 };
125
RenderCase(Context & context,const char * name,const char * desc,RenderTargetType renderTargetType)126 RenderCase::RenderCase(Context &context, const char *name, const char *desc, RenderTargetType renderTargetType)
127 : TestCase(context, name, desc)
128 , m_program(DE_NULL)
129 , m_renderTargetType(renderTargetType)
130 {
131 }
132
~RenderCase(void)133 RenderCase::~RenderCase(void)
134 {
135 deinit();
136 }
137
init(void)138 void RenderCase::init(void)
139 {
140 const int width = m_context.getRenderTarget().getWidth();
141 const int height = m_context.getRenderTarget().getHeight();
142
143 // check target size
144 if (m_renderTargetType == RENDERTARGETTYPE_SCREEN)
145 {
146 if (width < TEST_CANVAS_SIZE || height < TEST_CANVAS_SIZE)
147 throw tcu::NotSupportedError(std::string("Render target size must be at least ") +
148 de::toString(TEST_CANVAS_SIZE) + "x" + de::toString(TEST_CANVAS_SIZE));
149 }
150 else if (m_renderTargetType == RENDERTARGETTYPE_FBO)
151 {
152 GLint maxTexSize = 0;
153 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
154
155 if (maxTexSize < TEST_CANVAS_SIZE)
156 throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") +
157 de::toString(TEST_CANVAS_SIZE));
158 }
159 else
160 DE_ASSERT(false);
161
162 // gen shader
163
164 m_testCtx.getLog() << tcu::TestLog::Message << "Creating test shader." << tcu::TestLog::EndMessage;
165
166 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
167 << glu::VertexSource(genVertexSource())
168 << glu::FragmentSource(genFragmentSource()));
169 m_testCtx.getLog() << *m_program;
170
171 if (!m_program->isOk())
172 throw tcu::TestError("shader compile failed");
173 }
174
deinit(void)175 void RenderCase::deinit(void)
176 {
177 if (m_program)
178 {
179 delete m_program;
180 m_program = DE_NULL;
181 }
182 }
183
checkResultImage(const tcu::Surface & result)184 bool RenderCase::checkResultImage(const tcu::Surface &result)
185 {
186 tcu::Surface errorMask(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
187 bool error = false;
188
189 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output image." << tcu::TestLog::EndMessage;
190
191 for (int y = 0; y < TEST_CANVAS_SIZE; ++y)
192 for (int x = 0; x < TEST_CANVAS_SIZE; ++x)
193 {
194 const tcu::RGBA col = result.getPixel(x, y);
195
196 if (col.getGreen() == 255)
197 errorMask.setPixel(x, y, tcu::RGBA::green());
198 else
199 {
200 errorMask.setPixel(x, y, tcu::RGBA::red());
201 error = true;
202 }
203 }
204
205 if (error)
206 {
207 m_testCtx.getLog() << tcu::TestLog::Message << "Result image has missing or invalid pixels"
208 << tcu::TestLog::EndMessage;
209 m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
210 << tcu::TestLog::Image("Result", "Result", result)
211 << tcu::TestLog::Image("Error mask", "Error mask", errorMask) << tcu::TestLog::EndImageSet;
212 }
213 else
214 {
215 m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
216 << tcu::TestLog::Image("Result", "Result", result) << tcu::TestLog::EndImageSet;
217 }
218
219 return !error;
220 }
221
drawTestPattern(bool useTexture)222 bool RenderCase::drawTestPattern(bool useTexture)
223 {
224 static const tcu::Vec4 fullscreenQuad[4] = {
225 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
226 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
227 tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),
228 tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
229 };
230 const char *const vertexSource = "#version 300 es\n"
231 "in highp vec4 a_pos;\n"
232 "out mediump vec4 v_position;\n"
233 "void main ()\n"
234 "{\n"
235 " v_position = a_pos;\n"
236 " gl_Position = a_pos;\n"
237 "}\n";
238 const char *const fragmentSourceNoTex = "#version 300 es\n"
239 "layout(location = 0) out mediump vec4 fragColor;\n"
240 "in mediump vec4 v_position;\n"
241 "void main ()\n"
242 "{\n"
243 " fragColor = vec4((v_position.x + 1.0) * 0.5, 1.0, 1.0, 1.0);\n"
244 "}\n";
245 const char *const fragmentSourceTex = "#version 300 es\n"
246 "layout(location = 0) out mediump vec4 fragColor;\n"
247 "uniform mediump sampler2D u_sampler;\n"
248 "in mediump vec4 v_position;\n"
249 "void main ()\n"
250 "{\n"
251 " fragColor = texture(u_sampler, v_position.xy);\n"
252 "}\n";
253 const char *const fragmentSource = (useTexture) ? (fragmentSourceTex) : (fragmentSourceNoTex);
254 const tcu::RGBA formatThreshold = m_context.getRenderTarget().getPixelFormat().getColorThreshold();
255
256 tcu::Surface resultImage(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
257 tcu::Surface errorMask(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
258 bool error = false;
259
260 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a test pattern to detect "
261 << ((useTexture) ? ("texture sampling") : ("")) << " side-effects." << tcu::TestLog::EndMessage;
262
263 // draw pattern
264 {
265 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
266 const glu::ShaderProgram patternProgram(m_context.getRenderContext(),
267 glu::ProgramSources() << glu::VertexSource(vertexSource)
268 << glu::FragmentSource(fragmentSource));
269 const GLint positionLoc = gl.getAttribLocation(patternProgram.getProgram(), "a_pos");
270 GLuint textureID = 0;
271
272 if (useTexture)
273 {
274 const int textureSize = 32;
275 std::vector<tcu::Vector<uint8_t, 4>> buffer(textureSize * textureSize);
276
277 for (int x = 0; x < textureSize; ++x)
278 for (int y = 0; y < textureSize; ++y)
279 {
280 // sum of two axis aligned gradients. Each gradient is 127 at the edges and 0 at the center.
281 // pattern is symmetric (x and y) => no discontinuity near boundary => no need to worry of results with LINEAR filtering near boundaries
282 const uint8_t redComponent =
283 (uint8_t)de::clamp(de::abs((float)x / (float)textureSize - 0.5f) * 255.0f +
284 de::abs((float)y / (float)textureSize - 0.5f) * 255.0f,
285 0.0f, 255.0f);
286
287 buffer[x * textureSize + y] = tcu::Vector<uint8_t, 4>(redComponent, 255, 255, 255);
288 }
289
290 gl.genTextures(1, &textureID);
291 gl.bindTexture(GL_TEXTURE_2D, textureID);
292 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureSize, textureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
293 buffer[0].getPtr());
294 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
295 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
296 }
297
298 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
299 gl.clear(GL_COLOR_BUFFER_BIT);
300 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
301 gl.useProgram(patternProgram.getProgram());
302
303 if (useTexture)
304 gl.uniform1i(gl.getUniformLocation(patternProgram.getProgram(), "u_sampler"), 0);
305
306 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &fullscreenQuad[0]);
307
308 gl.enableVertexAttribArray(positionLoc);
309 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
310 gl.disableVertexAttribArray(positionLoc);
311
312 gl.useProgram(0);
313 gl.finish();
314 GLU_EXPECT_NO_ERROR(gl.getError(), "RenderCase::drawTestPattern");
315
316 if (textureID)
317 gl.deleteTextures(1, &textureID);
318
319 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
320 }
321
322 // verify pattern
323 for (int y = 0; y < TEST_CANVAS_SIZE; ++y)
324 for (int x = 0; x < TEST_CANVAS_SIZE; ++x)
325 {
326 const float texGradientPosX = deFloatFrac((float)x * 2.0f / (float)TEST_CANVAS_SIZE);
327 const float texGradientPosY = deFloatFrac((float)y * 2.0f / (float)TEST_CANVAS_SIZE);
328 const uint8_t texRedComponent = (uint8_t)de::clamp(
329 de::abs(texGradientPosX - 0.5f) * 255.0f + de::abs(texGradientPosY - 0.5f) * 255.0f, 0.0f, 255.0f);
330
331 const tcu::RGBA refColTexture = tcu::RGBA(texRedComponent, 255, 255, 255);
332 const tcu::RGBA refColGradient =
333 tcu::RGBA((int)((float)x / (float)TEST_CANVAS_SIZE * 255.0f), 255, 255, 255);
334 const tcu::RGBA &refCol = (useTexture) ? (refColTexture) : (refColGradient);
335
336 const int colorThreshold = 10;
337 const tcu::RGBA col = resultImage.getPixel(x, y);
338 const tcu::IVec4 colorDiff = tcu::abs(col.toIVec() - refCol.toIVec());
339
340 if (colorDiff.x() > formatThreshold.getRed() + colorThreshold ||
341 colorDiff.y() > formatThreshold.getGreen() + colorThreshold ||
342 colorDiff.z() > formatThreshold.getBlue() + colorThreshold)
343 {
344 errorMask.setPixel(x, y, tcu::RGBA::red());
345 error = true;
346 }
347 else
348 errorMask.setPixel(x, y, tcu::RGBA::green());
349 }
350
351 // report error
352 if (error)
353 {
354 m_testCtx.getLog() << tcu::TestLog::Message << "Test pattern has missing/invalid pixels"
355 << tcu::TestLog::EndMessage;
356 m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
357 << tcu::TestLog::Image("Result", "Result", resultImage)
358 << tcu::TestLog::Image("Error mask", "Error mask", errorMask) << tcu::TestLog::EndImageSet;
359 }
360 else
361 m_testCtx.getLog() << tcu::TestLog::Message << "No side-effects found." << tcu::TestLog::EndMessage;
362
363 return !error;
364 }
365
366 class FramebufferRenderCase : public RenderCase
367 {
368 public:
369 enum FrameBufferType
370 {
371 FBO_DEFAULT = 0,
372 FBO_RGBA4,
373 FBO_RGB5_A1,
374 FBO_RGB565,
375 FBO_RGBA8,
376 FBO_RGB10_A2,
377 FBO_RGBA_FLOAT16,
378 FBO_RGBA_FLOAT32,
379
380 FBO_LAST
381 };
382
383 FramebufferRenderCase(Context &context, const char *name, const char *desc, FrameBufferType fboType);
384 virtual ~FramebufferRenderCase(void);
385
386 virtual void init(void);
387 virtual void deinit(void);
388 IterateResult iterate(void);
389
390 virtual void testFBO(void) = DE_NULL;
391
392 protected:
393 const FrameBufferType m_fboType;
394
395 private:
396 GLuint m_texID;
397 GLuint m_fboID;
398 };
399
FramebufferRenderCase(Context & context,const char * name,const char * desc,FrameBufferType fboType)400 FramebufferRenderCase::FramebufferRenderCase(Context &context, const char *name, const char *desc,
401 FrameBufferType fboType)
402 : RenderCase(context, name, desc, (fboType == FBO_DEFAULT) ? (RENDERTARGETTYPE_SCREEN) : (RENDERTARGETTYPE_FBO))
403 , m_fboType(fboType)
404 , m_texID(0)
405 , m_fboID(0)
406 {
407 DE_ASSERT(m_fboType < FBO_LAST);
408 }
409
~FramebufferRenderCase(void)410 FramebufferRenderCase::~FramebufferRenderCase(void)
411 {
412 deinit();
413 }
414
init(void)415 void FramebufferRenderCase::init(void)
416 {
417 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
418
419 // check requirements
420 if (m_fboType == FBO_RGBA_FLOAT16)
421 {
422 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_half_float") &&
423 !m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_float"))
424 throw tcu::NotSupportedError("Color renderable half float texture required.");
425 }
426 else if (m_fboType == FBO_RGBA_FLOAT32)
427 {
428 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_float"))
429 throw tcu::NotSupportedError("Color renderable float texture required.");
430 }
431
432 // gen shader
433 RenderCase::init();
434
435 // create render target
436 if (m_fboType == FBO_DEFAULT)
437 {
438 m_testCtx.getLog() << tcu::TestLog::Message << "Using default framebuffer." << tcu::TestLog::EndMessage;
439 }
440 else
441 {
442 GLuint internalFormat = 0;
443 GLuint format = 0;
444 GLuint type = 0;
445
446 switch (m_fboType)
447 {
448 case FBO_RGBA4:
449 internalFormat = GL_RGBA4;
450 format = GL_RGBA;
451 type = GL_UNSIGNED_SHORT_4_4_4_4;
452 break;
453 case FBO_RGB5_A1:
454 internalFormat = GL_RGB5_A1;
455 format = GL_RGBA;
456 type = GL_UNSIGNED_SHORT_5_5_5_1;
457 break;
458 case FBO_RGB565:
459 internalFormat = GL_RGB565;
460 format = GL_RGB;
461 type = GL_UNSIGNED_SHORT_5_6_5;
462 break;
463 case FBO_RGBA8:
464 internalFormat = GL_RGBA8;
465 format = GL_RGBA;
466 type = GL_UNSIGNED_BYTE;
467 break;
468 case FBO_RGB10_A2:
469 internalFormat = GL_RGB10_A2;
470 format = GL_RGBA;
471 type = GL_UNSIGNED_INT_2_10_10_10_REV;
472 break;
473 case FBO_RGBA_FLOAT16:
474 internalFormat = GL_RGBA16F;
475 format = GL_RGBA;
476 type = GL_HALF_FLOAT;
477 break;
478 case FBO_RGBA_FLOAT32:
479 internalFormat = GL_RGBA32F;
480 format = GL_RGBA;
481 type = GL_FLOAT;
482 break;
483
484 default:
485 DE_ASSERT(false);
486 break;
487 }
488
489 m_testCtx.getLog() << tcu::TestLog::Message
490 << "Creating fbo. Texture internalFormat = " << glu::getTextureFormatStr(internalFormat)
491 << ", format = " << glu::getTextureFormatStr(format) << ", type = " << glu::getTypeStr(type)
492 << tcu::TestLog::EndMessage;
493
494 // gen texture
495 gl.genTextures(1, &m_texID);
496 gl.bindTexture(GL_TEXTURE_2D, m_texID);
497 gl.texImage2D(GL_TEXTURE_2D, 0, internalFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE, 0, format, type, DE_NULL);
498 GLU_EXPECT_NO_ERROR(gl.getError(), "texture init");
499
500 // gen fbo
501 gl.genFramebuffers(1, &m_fboID);
502 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
503 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texID, 0);
504 GLU_EXPECT_NO_ERROR(gl.getError(), "fbo init");
505
506 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
507 throw tcu::NotSupportedError("could not create fbo for testing.");
508 }
509 }
510
deinit(void)511 void FramebufferRenderCase::deinit(void)
512 {
513 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
514
515 if (m_texID)
516 {
517 gl.deleteTextures(1, &m_texID);
518 m_texID = 0;
519 }
520
521 if (m_fboID)
522 {
523 gl.deleteFramebuffers(1, &m_fboID);
524 m_fboID = 0;
525 }
526 }
527
iterate(void)528 FramebufferRenderCase::IterateResult FramebufferRenderCase::iterate(void)
529 {
530 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
531
532 // bind fbo (or don't if we are using default)
533 if (m_fboID)
534 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
535
536 // do something with special floats
537 testFBO();
538
539 return STOP;
540 }
541
542 /*--------------------------------------------------------------------*//*!
543 * \brief Tests special floats as vertex attributes
544 *
545 * Tests that special floats transferred to the shader using vertex
546 * attributes do not change the results of normal floating point
547 * calculations. Special floats are put to 4-vector's x and y components and
548 * value 1.0 is put to z and w. The resulting fragment's green channel
549 * should be 1.0 everywhere.
550 *
551 * After the calculation test a test pattern is drawn to detect possible
552 * floating point operation anomalies.
553 *//*--------------------------------------------------------------------*/
554 class VertexAttributeCase : public RenderCase
555 {
556 public:
557 enum Storage
558 {
559 STORAGE_BUFFER = 0,
560 STORAGE_CLIENT,
561
562 STORAGE_LAST
563 };
564 enum ShaderType
565 {
566 TYPE_VERTEX = 0,
567 TYPE_FRAGMENT,
568
569 TYPE_LAST
570 };
571
572 VertexAttributeCase(Context &context, const char *name, const char *desc, Storage storage, ShaderType type);
573 ~VertexAttributeCase(void);
574
575 void init(void);
576 void deinit(void);
577 IterateResult iterate(void);
578
579 private:
580 std::string genVertexSource(void) const;
581 std::string genFragmentSource(void) const;
582
583 const Storage m_storage;
584 const ShaderType m_type;
585 GLuint m_positionVboID;
586 GLuint m_attribVboID;
587 GLuint m_elementVboID;
588 };
589
VertexAttributeCase(Context & context,const char * name,const char * desc,Storage storage,ShaderType type)590 VertexAttributeCase::VertexAttributeCase(Context &context, const char *name, const char *desc, Storage storage,
591 ShaderType type)
592 : RenderCase(context, name, desc)
593 , m_storage(storage)
594 , m_type(type)
595 , m_positionVboID(0)
596 , m_attribVboID(0)
597 , m_elementVboID(0)
598 {
599 DE_ASSERT(storage < STORAGE_LAST);
600 DE_ASSERT(type < TYPE_LAST);
601 }
602
~VertexAttributeCase(void)603 VertexAttributeCase::~VertexAttributeCase(void)
604 {
605 deinit();
606 }
607
init(void)608 void VertexAttributeCase::init(void)
609 {
610 RenderCase::init();
611
612 // init gl resources
613 if (m_storage == STORAGE_BUFFER)
614 {
615 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
616
617 gl.genBuffers(1, &m_positionVboID);
618 gl.genBuffers(1, &m_attribVboID);
619 gl.genBuffers(1, &m_elementVboID);
620 }
621 }
622
deinit(void)623 void VertexAttributeCase::deinit(void)
624 {
625 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
626
627 RenderCase::deinit();
628
629 if (m_attribVboID)
630 {
631 gl.deleteBuffers(1, &m_attribVboID);
632 m_attribVboID = 0;
633 }
634
635 if (m_positionVboID)
636 {
637 gl.deleteBuffers(1, &m_positionVboID);
638 m_positionVboID = 0;
639 }
640
641 if (m_elementVboID)
642 {
643 gl.deleteBuffers(1, &m_elementVboID);
644 m_elementVboID = 0;
645 }
646 }
647
iterate(void)648 VertexAttributeCase::IterateResult VertexAttributeCase::iterate(void)
649 {
650 // Create a [s_specialFloats] X [s_specialFloats] grid of vertices with each vertex having 2 [s_specialFloats] values
651 // and calculate some basic operations with the floating point values. If all goes well, nothing special should happen
652
653 std::vector<tcu::Vec4> gridVertices(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
654 std::vector<tcu::UVec4> gridAttributes(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
655 std::vector<uint16_t> indices((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) *
656 (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6);
657 tcu::Surface resultImage(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
658
659 // vertices
660 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
661 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
662 {
663 const uint32_t one = 0x3F800000;
664 const float posX = (float)x / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f -
665 1.0f; // map from [0, len(s_specialFloats) - 1] to [-1, 1]
666 const float posY = (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f;
667
668 gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
669 gridAttributes[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] =
670 tcu::UVec4(s_specialFloats[x], s_specialFloats[y], one, one);
671 }
672
673 // tiles
674 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x)
675 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y)
676 {
677 const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6;
678
679 indices[baseNdx + 0] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
680 indices[baseNdx + 1] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
681 indices[baseNdx + 2] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
682
683 indices[baseNdx + 3] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
684 indices[baseNdx + 4] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
685 indices[baseNdx + 5] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
686 }
687
688 m_testCtx.getLog() << tcu::TestLog::Message
689 << "Drawing a grid with the shader. Setting a_attr for each vertex to (special, special, 1, 1)."
690 << tcu::TestLog::EndMessage;
691
692 // Draw grid
693 {
694 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
695 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos");
696 const GLint attribLoc = gl.getAttribLocation(m_program->getProgram(), "a_attr");
697
698 if (m_storage == STORAGE_BUFFER)
699 {
700 gl.bindBuffer(GL_ARRAY_BUFFER, m_positionVboID);
701 gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(gridVertices.size() * sizeof(tcu::Vec4)), &gridVertices[0],
702 GL_STATIC_DRAW);
703 GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
704
705 gl.bindBuffer(GL_ARRAY_BUFFER, m_attribVboID);
706 gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(gridAttributes.size() * sizeof(tcu::UVec4)),
707 &gridAttributes[0], GL_STATIC_DRAW);
708 GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
709
710 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementVboID);
711 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indices.size() * sizeof(uint16_t)), &indices[0],
712 GL_STATIC_DRAW);
713 GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
714 }
715
716 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
717 gl.clear(GL_COLOR_BUFFER_BIT);
718 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
719 gl.useProgram(m_program->getProgram());
720
721 if (m_storage == STORAGE_BUFFER)
722 {
723 gl.bindBuffer(GL_ARRAY_BUFFER, m_positionVboID);
724 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
725
726 gl.bindBuffer(GL_ARRAY_BUFFER, m_attribVboID);
727 gl.vertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
728
729 gl.enableVertexAttribArray(positionLoc);
730 gl.enableVertexAttribArray(attribLoc);
731 gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, DE_NULL);
732 gl.disableVertexAttribArray(positionLoc);
733 gl.disableVertexAttribArray(attribLoc);
734
735 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
736 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
737 }
738 else if (m_storage == STORAGE_CLIENT)
739 {
740 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
741 gl.vertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridAttributes[0]);
742
743 gl.enableVertexAttribArray(positionLoc);
744 gl.enableVertexAttribArray(attribLoc);
745 gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
746 gl.disableVertexAttribArray(positionLoc);
747 gl.disableVertexAttribArray(attribLoc);
748 }
749 else
750 DE_ASSERT(false);
751
752 gl.useProgram(0);
753 gl.finish();
754 GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
755
756 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
757 }
758
759 // verify everywhere was drawn (all pixels have Green = 255)
760 if (!checkResultImage(resultImage))
761 {
762 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
763 return STOP;
764 }
765
766 // test drawing still works
767 if (!drawTestPattern(false))
768 {
769 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
770 return STOP;
771 }
772
773 // all ok
774 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
775 return STOP;
776 }
777
genVertexSource(void) const778 std::string VertexAttributeCase::genVertexSource(void) const
779 {
780 if (m_type == TYPE_VERTEX)
781 return "#version 300 es\n"
782 "in highp vec4 a_pos;\n"
783 "in highp vec4 a_attr;\n"
784 "out mediump vec4 v_out;\n"
785 "void main ()\n"
786 "{\n"
787 " highp vec2 a1 = a_attr.xz + a_attr.yw; // add\n"
788 " highp vec2 a2 = a_attr.xz - a_attr.yw; // sub\n"
789 " highp vec2 a3 = a_attr.xz * a_attr.yw; // mul\n"
790 " highp vec2 a4 = a_attr.xz / a_attr.yw; // div\n"
791 " highp vec2 a5 = a_attr.xz + a_attr.yw * a_attr.xz; // fma\n"
792 "\n"
793 " highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
794 " v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
795 " gl_Position = a_pos;\n"
796 "}\n";
797 else
798 return s_attrPassthroughVertexShaderSource;
799 }
800
genFragmentSource(void) const801 std::string VertexAttributeCase::genFragmentSource(void) const
802 {
803 if (m_type == TYPE_VERTEX)
804 return s_colorPassthroughFragmentShaderSource;
805 else
806 return "#version 300 es\n"
807 "layout(location = 0) out mediump vec4 fragColor;\n"
808 "in highp vec4 v_attr;\n"
809 "void main ()\n"
810 "{\n"
811 " highp vec2 a1 = v_attr.xz + v_attr.yw; // add\n"
812 " highp vec2 a2 = v_attr.xz - v_attr.yw; // sub\n"
813 " highp vec2 a3 = v_attr.xz * v_attr.yw; // mul\n"
814 " highp vec2 a4 = v_attr.xz / v_attr.yw; // div\n"
815 " highp vec2 a5 = v_attr.xz + v_attr.yw * v_attr.xz; // fma\n"
816 " highp vec2 a6 = dFdx(v_attr.xz);\n"
817 "\n"
818 " highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y + a6.y) - 6.0);\n"
819 " fragColor = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x+a6.x, 1.0);\n"
820 "}\n";
821 }
822
823 /*--------------------------------------------------------------------*//*!
824 * \brief Tests special floats as uniforms
825 *
826 * Tests that special floats transferred to the shader as uniforms do
827 * not change the results of normal floating point calculations. Special
828 * floats are put to 4-vector's x and y components and value 1.0 is put to
829 * z and w. The resulting fragment's green channel should be 1.0
830 * everywhere.
831 *
832 * After the calculation test a test pattern is drawn to detect possible
833 * floating point operation anomalies.
834 *//*--------------------------------------------------------------------*/
835 class UniformCase : public RenderCase
836 {
837 public:
838 enum ShaderType
839 {
840 TYPE_VERTEX = 0,
841 TYPE_FRAGMENT,
842 };
843
844 UniformCase(Context &context, const char *name, const char *desc, ShaderType type);
845 ~UniformCase(void);
846
847 void init(void);
848 void deinit(void);
849 IterateResult iterate(void);
850
851 private:
852 std::string genVertexSource(void) const;
853 std::string genFragmentSource(void) const;
854
855 const ShaderType m_type;
856 };
857
UniformCase(Context & context,const char * name,const char * desc,ShaderType type)858 UniformCase::UniformCase(Context &context, const char *name, const char *desc, ShaderType type)
859 : RenderCase(context, name, desc)
860 , m_type(type)
861 {
862 }
863
~UniformCase(void)864 UniformCase::~UniformCase(void)
865 {
866 deinit();
867 }
868
init(void)869 void UniformCase::init(void)
870 {
871 RenderCase::init();
872 }
873
deinit(void)874 void UniformCase::deinit(void)
875 {
876 RenderCase::deinit();
877 }
878
iterate(void)879 UniformCase::IterateResult UniformCase::iterate(void)
880 {
881 // Create a [s_specialFloats] X [s_specialFloats] grid of tile with each tile having 2 [s_specialFloats] values
882 // and calculate some basic operations with the floating point values. If all goes well, nothing special should happen
883
884 std::vector<tcu::Vec4> gridVertices((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) *
885 (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1));
886 std::vector<uint16_t> indices(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
887 tcu::Surface resultImage(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
888
889 // vertices
890 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x)
891 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y)
892 {
893 const float posX = (float)x / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f -
894 1.0f; // map from [0, len(s_specialFloats) ] to [-1, 1]
895 const float posY = (float)y / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f;
896
897 gridVertices[x * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
898 }
899
900 // tiles
901 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
902 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
903 {
904 const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats)) + y) * 6;
905
906 indices[baseNdx + 0] = (uint16_t)((x + 0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 0));
907 indices[baseNdx + 1] = (uint16_t)((x + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 1));
908 indices[baseNdx + 2] = (uint16_t)((x + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 0));
909
910 indices[baseNdx + 3] = (uint16_t)((x + 0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 0));
911 indices[baseNdx + 4] = (uint16_t)((x + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 1));
912 indices[baseNdx + 5] = (uint16_t)((x + 0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 1));
913 }
914
915 m_testCtx.getLog()
916 << tcu::TestLog::Message
917 << "Drawing a grid with the shader. Setting u_special for vertex each tile to (special, special, 1, 1)."
918 << tcu::TestLog::EndMessage;
919
920 // Draw grid
921 {
922 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
923 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos");
924 const GLint specialLoc = gl.getUniformLocation(m_program->getProgram(), "u_special");
925
926 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
927 gl.clear(GL_COLOR_BUFFER_BIT);
928 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
929 gl.useProgram(m_program->getProgram());
930
931 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
932 gl.enableVertexAttribArray(positionLoc);
933
934 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
935 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
936 {
937 const uint32_t one = 0x3F800000;
938 const tcu::UVec4 uniformValue = tcu::UVec4(s_specialFloats[x], s_specialFloats[y], one, one);
939 const int indexIndex = (x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y) * 6;
940
941 gl.uniform4fv(specialLoc, 1, (const float *)uniformValue.getPtr());
942 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
943 }
944
945 gl.disableVertexAttribArray(positionLoc);
946
947 gl.useProgram(0);
948 gl.finish();
949 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformCase::iterate");
950
951 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
952 }
953
954 // verify everywhere was drawn (all pixels have Green = 255)
955 if (!checkResultImage(resultImage))
956 {
957 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
958 return STOP;
959 }
960
961 // test drawing still works
962 if (!drawTestPattern(false))
963 {
964 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
965 return STOP;
966 }
967
968 // all ok
969 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
970 return STOP;
971 }
972
genVertexSource(void) const973 std::string UniformCase::genVertexSource(void) const
974 {
975 if (m_type == TYPE_VERTEX)
976 return "#version 300 es\n"
977 "in highp vec4 a_pos;\n"
978 "uniform highp vec4 u_special;\n"
979 "out mediump vec4 v_out;\n"
980 "void main ()\n"
981 "{\n"
982 " highp vec2 a1 = u_special.xz + u_special.yw; // add\n"
983 " highp vec2 a2 = u_special.xz - u_special.yw; // sub\n"
984 " highp vec2 a3 = u_special.xz * u_special.yw; // mul\n"
985 " highp vec2 a4 = u_special.xz / u_special.yw; // div\n"
986 " highp vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n"
987 "\n"
988 " highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
989 " v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
990 " gl_Position = a_pos;\n"
991 "}\n";
992 else
993 return "#version 300 es\n"
994 "in highp vec4 a_pos;\n"
995 "void main ()\n"
996 "{\n"
997 " gl_Position = a_pos;\n"
998 "}\n";
999 }
1000
genFragmentSource(void) const1001 std::string UniformCase::genFragmentSource(void) const
1002 {
1003 if (m_type == TYPE_VERTEX)
1004 return s_colorPassthroughFragmentShaderSource;
1005 else
1006 return "#version 300 es\n"
1007 "layout(location = 0) out mediump vec4 fragColor;\n"
1008 "uniform highp vec4 u_special;\n"
1009 "void main ()\n"
1010 "{\n"
1011 " highp vec2 a1 = u_special.xz + u_special.yw; // add\n"
1012 " highp vec2 a2 = u_special.xz - u_special.yw; // sub\n"
1013 " highp vec2 a3 = u_special.xz * u_special.yw; // mul\n"
1014 " highp vec2 a4 = u_special.xz / u_special.yw; // div\n"
1015 " highp vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n"
1016 " highp vec2 a6 = mod(u_special.xz, u_special.yw);\n"
1017 " highp vec2 a7 = mix(u_special.xz, u_special.yw, a6);\n"
1018 "\n"
1019 " highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y + a6.y + a7.y) - 7.0);\n"
1020 " fragColor = vec4(a1.x*a3.x, green, a5.x*a4.x + a2.x*a7.x, 1.0);\n"
1021 "}\n";
1022 }
1023
1024 /*--------------------------------------------------------------------*//*!
1025 * \brief Tests special floats in floating point textures
1026 *
1027 * Tests that sampling special floats from a floating point texture
1028 * does not affect the values of other color components of the sample. Test
1029 * samples a RG texture with R channel filled with special floats and G
1030 * channel filled with test values.
1031 *
1032 * Tests that linear sampling using compare mode = COMPARE_REF_TO_TEXTURE
1033 * of a floating point depth texture containing special floating point
1034 * values does not produce values outside the [0, 1] range.
1035 *
1036 * After the calculation test a test pattern is drawn to detect possible
1037 * texture sampling anomalies.
1038 *//*--------------------------------------------------------------------*/
1039 class TextureCase : public RenderCase
1040 {
1041 public:
1042 enum ShaderType
1043 {
1044 TYPE_VERTEX = 0,
1045 TYPE_FRAGMENT,
1046
1047 TYPE_LAST
1048 };
1049 enum TextureType
1050 {
1051 TEXTURE_FLOAT = 0,
1052 TEXTURE_DEPTH,
1053
1054 TEXTURE_LAST
1055 };
1056 enum UploadType
1057 {
1058 UPLOAD_CLIENT = 0,
1059 UPLOAD_PBO,
1060
1061 UPLOAD_LAST
1062 };
1063
1064 TextureCase(Context &context, const char *name, const char *desc, ShaderType type, TextureType texType,
1065 UploadType uploadType);
1066 ~TextureCase(void);
1067
1068 void init(void);
1069 void deinit(void);
1070 IterateResult iterate(void);
1071
1072 private:
1073 std::string genVertexSource(void) const;
1074 std::string genFragmentSource(void) const;
1075
1076 const ShaderType m_type;
1077 const TextureType m_textureType;
1078 const UploadType m_uploadType;
1079 GLuint m_textureID;
1080 GLuint m_pboID;
1081 };
1082
TextureCase(Context & context,const char * name,const char * desc,ShaderType type,TextureType texType,UploadType uploadType)1083 TextureCase::TextureCase(Context &context, const char *name, const char *desc, ShaderType type, TextureType texType,
1084 UploadType uploadType)
1085 : RenderCase(context, name, desc)
1086 , m_type(type)
1087 , m_textureType(texType)
1088 , m_uploadType(uploadType)
1089 , m_textureID(0)
1090 , m_pboID(0)
1091 {
1092 DE_ASSERT(type < TYPE_LAST);
1093 DE_ASSERT(texType < TEXTURE_LAST);
1094 DE_ASSERT(uploadType < UPLOAD_LAST);
1095 }
1096
~TextureCase(void)1097 TextureCase::~TextureCase(void)
1098 {
1099 deinit();
1100 }
1101
init(void)1102 void TextureCase::init(void)
1103 {
1104 // requirements
1105 {
1106 GLint maxTextureSize = 0;
1107 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1108 if (maxTextureSize < TEST_TEXTURE_SIZE)
1109 throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") +
1110 de::toString(TEST_TEXTURE_SIZE));
1111 }
1112
1113 RenderCase::init();
1114
1115 // gen texture
1116 {
1117 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1118 de::Random rnd(12345);
1119
1120 gl.genTextures(1, &m_textureID);
1121 gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1122
1123 if (m_uploadType == UPLOAD_PBO)
1124 {
1125 gl.genBuffers(1, &m_pboID);
1126 gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, m_pboID);
1127 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureCase::init");
1128 }
1129
1130 if (m_textureType == TEXTURE_FLOAT)
1131 {
1132 std::vector<uint32_t> texData(TEST_TEXTURE_SIZE * TEST_TEXTURE_SIZE * 2);
1133 const uint32_t *dataPtr = (m_uploadType == UPLOAD_CLIENT) ? (&texData[0]) : (DE_NULL);
1134
1135 m_testCtx.getLog() << tcu::TestLog::Message
1136 << "Creating a 2D 2-component float texture. Pixel contents are of form (special, 1)."
1137 << tcu::TestLog::EndMessage;
1138
1139 // set green channel to 1.0
1140 for (int x = 0; x < TEST_TEXTURE_SIZE; ++x)
1141 for (int y = 0; y < TEST_TEXTURE_SIZE; ++y)
1142 {
1143 texData[(x * TEST_TEXTURE_SIZE + y) * 2 + 0] =
1144 rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
1145 texData[(x * TEST_TEXTURE_SIZE + y) * 2 + 1] = 0x3F800000; // one
1146 }
1147
1148 if (m_uploadType == UPLOAD_PBO)
1149 gl.bufferData(GL_PIXEL_UNPACK_BUFFER, (glw::GLsizeiptr)(texData.size() * sizeof(uint32_t)), &texData[0],
1150 GL_STATIC_DRAW);
1151
1152 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RG32F, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0, GL_RG, GL_FLOAT,
1153 dataPtr);
1154 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1155 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1156 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureCase::init");
1157 }
1158 else if (m_textureType == TEXTURE_DEPTH)
1159 {
1160 std::vector<uint32_t> texData(TEST_TEXTURE_SIZE * TEST_TEXTURE_SIZE);
1161 const uint32_t *dataPtr = (m_uploadType == UPLOAD_CLIENT) ? (&texData[0]) : (DE_NULL);
1162
1163 m_testCtx.getLog() << tcu::TestLog::Message
1164 << "Creating a 2D depth texture and filling it with special floating point values.\n"
1165 << " TEXTURE_COMPARE_MODE = COMPARE_REF_TO_TEXTURE" << tcu::TestLog::EndMessage;
1166
1167 for (int x = 0; x < TEST_TEXTURE_SIZE; ++x)
1168 for (int y = 0; y < TEST_TEXTURE_SIZE; ++y)
1169 texData[x * TEST_TEXTURE_SIZE + y] =
1170 rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
1171
1172 if (m_uploadType == UPLOAD_PBO)
1173 gl.bufferData(GL_PIXEL_UNPACK_BUFFER, (glw::GLsizeiptr)(texData.size() * sizeof(uint32_t)), &texData[0],
1174 GL_STATIC_DRAW);
1175
1176 gl.texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0,
1177 GL_DEPTH_COMPONENT, GL_FLOAT, dataPtr);
1178 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
1179 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
1180 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1181 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1182 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureCase::init");
1183 }
1184 else
1185 DE_ASSERT(false);
1186
1187 if (m_uploadType == UPLOAD_PBO)
1188 {
1189 m_testCtx.getLog() << tcu::TestLog::Message << "PBO used for image upload." << tcu::TestLog::EndMessage;
1190
1191 gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1192 gl.deleteBuffers(1, &m_pboID);
1193 m_pboID = 0;
1194 }
1195 }
1196 }
1197
deinit(void)1198 void TextureCase::deinit(void)
1199 {
1200 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1201
1202 RenderCase::deinit();
1203
1204 if (m_textureID)
1205 {
1206 gl.deleteTextures(1, &m_textureID);
1207 m_textureID = 0;
1208 }
1209 if (m_pboID)
1210 {
1211 gl.deleteBuffers(1, &m_pboID);
1212 m_pboID = 0;
1213 }
1214 }
1215
iterate(void)1216 TextureCase::IterateResult TextureCase::iterate(void)
1217 {
1218 // Draw a grid and texture it with a floating point texture containing special values. If all goes well, nothing special should happen
1219
1220 const int gridSize = 16;
1221 std::vector<tcu::Vec4> gridVertices(gridSize * gridSize);
1222 std::vector<tcu::Vec2> gridTexCoords(gridSize * gridSize);
1223 std::vector<uint16_t> indices((gridSize - 1) * (gridSize - 1) * 6);
1224 tcu::Surface resultImage(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1225
1226 // vertices
1227 for (int x = 0; x < gridSize; ++x)
1228 for (int y = 0; y < gridSize; ++y)
1229 {
1230 const float posX =
1231 (float)x / ((float)gridSize - 1.0f) * 2.0f - 1.0f; // map from [0, gridSize - 1] to [-1, 1]
1232 const float posY = (float)y / ((float)gridSize - 1.0f) * 2.0f - 1.0f;
1233 const float texCoordX = deFloatPow(2.0f, (float)x - (float)gridSize / 2.0f);
1234 const float texCoordY = deFloatPow(2.0f, (float)y - (float)gridSize / 2.0f);
1235
1236 gridVertices[x * gridSize + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1237 gridTexCoords[x * gridSize + y] = tcu::Vec2(texCoordX, texCoordY);
1238 }
1239
1240 // tiles
1241 for (int x = 0; x < gridSize - 1; ++x)
1242 for (int y = 0; y < gridSize - 1; ++y)
1243 {
1244 const int baseNdx = (x * (gridSize - 1) + y) * 6;
1245
1246 indices[baseNdx + 0] = (uint16_t)((x + 0) * gridSize + (y + 0));
1247 indices[baseNdx + 1] = (uint16_t)((x + 1) * gridSize + (y + 1));
1248 indices[baseNdx + 2] = (uint16_t)((x + 1) * gridSize + (y + 0));
1249
1250 indices[baseNdx + 3] = (uint16_t)((x + 0) * gridSize + (y + 0));
1251 indices[baseNdx + 4] = (uint16_t)((x + 1) * gridSize + (y + 1));
1252 indices[baseNdx + 5] = (uint16_t)((x + 0) * gridSize + (y + 1));
1253 }
1254
1255 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a textured grid with the shader."
1256 << tcu::TestLog::EndMessage;
1257
1258 // Draw grid
1259 {
1260 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1261 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos");
1262 const GLint texCoordLoc = gl.getAttribLocation(m_program->getProgram(), "a_attr");
1263 const GLint samplerLoc = gl.getUniformLocation(m_program->getProgram(), "u_sampler");
1264
1265 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1266 gl.clear(GL_COLOR_BUFFER_BIT);
1267 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1268 gl.useProgram(m_program->getProgram());
1269
1270 gl.uniform1i(samplerLoc, 0);
1271 gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1272
1273 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
1274 gl.vertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, &gridTexCoords[0]);
1275
1276 gl.enableVertexAttribArray(positionLoc);
1277 gl.enableVertexAttribArray(texCoordLoc);
1278 gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
1279 gl.disableVertexAttribArray(positionLoc);
1280 gl.disableVertexAttribArray(texCoordLoc);
1281
1282 gl.useProgram(0);
1283 gl.finish();
1284 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureCase::iterate");
1285
1286 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
1287 }
1288
1289 // verify everywhere was drawn (all pixels have Green = 255)
1290 if (!checkResultImage(resultImage))
1291 {
1292 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
1293 return STOP;
1294 }
1295
1296 // test drawing and textures still works
1297 if (!drawTestPattern(true))
1298 {
1299 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
1300 return STOP;
1301 }
1302
1303 // all ok
1304 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1305 return STOP;
1306 }
1307
genVertexSource(void) const1308 std::string TextureCase::genVertexSource(void) const
1309 {
1310 // vertex shader is passthrough, fragment does the calculations
1311 if (m_type == TYPE_FRAGMENT)
1312 return s_attrPassthroughVertexShaderSource;
1313
1314 // vertex shader does the calculations
1315 std::ostringstream buf;
1316 buf << "#version 300 es\n"
1317 "in highp vec4 a_pos;\n"
1318 "in highp vec2 a_attr;\n"
1319 "out mediump vec4 v_out;\n";
1320
1321 if (m_textureType == TEXTURE_FLOAT)
1322 buf << "uniform highp sampler2D u_sampler;\n";
1323 else if (m_textureType == TEXTURE_DEPTH)
1324 buf << "uniform highp sampler2DShadow u_sampler;\n";
1325 else
1326 DE_ASSERT(false);
1327
1328 buf << "void main ()\n"
1329 "{\n";
1330
1331 if (m_textureType == TEXTURE_FLOAT)
1332 buf << " v_out = vec4(textureLod(u_sampler, a_attr, 0.0).rg, 1.0, 1.0);\n";
1333 else if (m_textureType == TEXTURE_DEPTH)
1334 buf << " highp float a1 = textureLod(u_sampler, vec3(a_attr, 0.0), 0.0);\n"
1335 " v_out = vec4(a1, (a1 > 1.0 || a1 < 0.0) ? (0.0) : (1.0), 1.0, 1.0);\n";
1336 else
1337 DE_ASSERT(false);
1338
1339 buf << " gl_Position = a_pos;\n"
1340 "}\n";
1341 return buf.str();
1342 }
1343
genFragmentSource(void) const1344 std::string TextureCase::genFragmentSource(void) const
1345 {
1346 // fragment shader is passthrough
1347 if (m_type == TYPE_VERTEX)
1348 return s_colorPassthroughFragmentShaderSource;
1349
1350 // fragment shader does the calculations
1351 std::ostringstream buf;
1352 buf << "#version 300 es\n"
1353 "layout(location = 0) out mediump vec4 fragColor;\n";
1354
1355 if (m_textureType == TEXTURE_FLOAT)
1356 buf << "uniform highp sampler2D u_sampler;\n";
1357 else if (m_textureType == TEXTURE_DEPTH)
1358 buf << "uniform highp sampler2DShadow u_sampler;\n";
1359 else
1360 DE_ASSERT(false);
1361
1362 buf << "in highp vec4 v_attr;\n"
1363 "void main ()\n"
1364 "{\n";
1365
1366 if (m_textureType == TEXTURE_FLOAT)
1367 buf << " highp vec2 a1 = texture(u_sampler, v_attr.xy).rg;\n"
1368 " fragColor = vec4(a1.x, a1.y, 1.0, 1.0);\n";
1369 else if (m_textureType == TEXTURE_DEPTH)
1370 buf << " highp float a1 = texture(u_sampler, vec3(v_attr.xy, 0.0));\n"
1371 " fragColor = vec4(a1, (a1 > 1.0 || a1 < 0.0) ? (0.0) : (1.0), 1.0, 1.0);\n";
1372 else
1373 DE_ASSERT(false);
1374
1375 buf << "}\n";
1376 return buf.str();
1377 }
1378
1379 /*--------------------------------------------------------------------*//*!
1380 * \brief Tests special floats as texture samping arguments
1381 *
1382 * Tests that special floats given as texture coordinates or LOD levels
1383 * to sampling functions do not return invalid values (values not in the
1384 * texture). Every texel's green component is 1.0.
1385 *
1386 * After the calculation test a test pattern is drawn to detect possible
1387 * texture sampling anomalies.
1388 *//*--------------------------------------------------------------------*/
1389 class TextureSamplerCase : public RenderCase
1390 {
1391 public:
1392 enum ShaderType
1393 {
1394 TYPE_VERTEX = 0,
1395 TYPE_FRAGMENT,
1396
1397 TYPE_LAST
1398 };
1399 enum TestType
1400 {
1401 TEST_TEX_COORD = 0,
1402 TEST_LOD,
1403 TEST_GRAD,
1404 TEST_TEX_COORD_CUBE,
1405
1406 TEST_LAST
1407 };
1408
1409 TextureSamplerCase(Context &context, const char *name, const char *desc, ShaderType type, TestType testType);
1410 ~TextureSamplerCase(void);
1411
1412 void init(void);
1413 void deinit(void);
1414 IterateResult iterate(void);
1415
1416 private:
1417 std::string genVertexSource(void) const;
1418 std::string genFragmentSource(void) const;
1419
1420 const ShaderType m_type;
1421 const TestType m_testType;
1422 GLuint m_textureID;
1423 };
1424
TextureSamplerCase(Context & context,const char * name,const char * desc,ShaderType type,TestType testType)1425 TextureSamplerCase::TextureSamplerCase(Context &context, const char *name, const char *desc, ShaderType type,
1426 TestType testType)
1427 : RenderCase(context, name, desc)
1428 , m_type(type)
1429 , m_testType(testType)
1430 , m_textureID(0)
1431 {
1432 DE_ASSERT(type < TYPE_LAST);
1433 DE_ASSERT(testType < TEST_LAST);
1434 }
1435
~TextureSamplerCase(void)1436 TextureSamplerCase::~TextureSamplerCase(void)
1437 {
1438 deinit();
1439 }
1440
init(void)1441 void TextureSamplerCase::init(void)
1442 {
1443 // requirements
1444 {
1445 GLint maxTextureSize = 0;
1446 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1447 if (maxTextureSize < TEST_TEXTURE_SIZE)
1448 throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") +
1449 de::toString(TEST_TEXTURE_SIZE));
1450 }
1451
1452 RenderCase::init();
1453
1454 // gen texture
1455 {
1456 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1457 std::vector<uint8_t> texData(TEST_TEXTURE_SIZE * TEST_TEXTURE_SIZE * 4);
1458 de::Random rnd(12345);
1459
1460 gl.genTextures(1, &m_textureID);
1461
1462 for (int x = 0; x < TEST_TEXTURE_SIZE; ++x)
1463 for (int y = 0; y < TEST_TEXTURE_SIZE; ++y)
1464 {
1465 // RGBA8, green and alpha channel are always 255 for verification
1466 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 0] = rnd.getUint32() & 0xFF;
1467 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 1] = 0xFF;
1468 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 2] = rnd.getUint32() & 0xFF;
1469 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 3] = 0xFF;
1470 }
1471
1472 if (m_testType == TEST_TEX_COORD)
1473 {
1474 m_testCtx.getLog() << tcu::TestLog::Message << "Creating a 2D texture with a test pattern."
1475 << tcu::TestLog::EndMessage;
1476
1477 gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1478 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0, GL_RGBA,
1479 GL_UNSIGNED_BYTE, &texData[0]);
1480 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1481 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1482 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
1483 }
1484 else if (m_testType == TEST_LOD || m_testType == TEST_GRAD)
1485 {
1486 m_testCtx.getLog() << tcu::TestLog::Message << "Creating a mipmapped 2D texture with a test pattern."
1487 << tcu::TestLog::EndMessage;
1488
1489 gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1490
1491 for (int level = 0; (TEST_TEXTURE_SIZE >> level); ++level)
1492 gl.texImage2D(GL_TEXTURE_2D, level, GL_RGBA8, TEST_TEXTURE_SIZE >> level, TEST_TEXTURE_SIZE >> level, 0,
1493 GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]);
1494
1495 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1496 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
1497 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
1498 }
1499 else if (m_testType == TEST_TEX_COORD_CUBE)
1500 {
1501 DE_STATIC_ASSERT(TEST_TEXTURE_CUBE_SIZE <= TEST_TEXTURE_SIZE);
1502
1503 static const GLenum faces[] = {
1504 GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
1505 GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
1506 };
1507
1508 m_testCtx.getLog() << tcu::TestLog::Message << "Creating a cube map with a test pattern."
1509 << tcu::TestLog::EndMessage;
1510
1511 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textureID);
1512
1513 for (int faceNdx = 0; faceNdx < DE_LENGTH_OF_ARRAY(faces); ++faceNdx)
1514 gl.texImage2D(faces[faceNdx], 0, GL_RGBA8, TEST_TEXTURE_CUBE_SIZE, TEST_TEXTURE_CUBE_SIZE, 0, GL_RGBA,
1515 GL_UNSIGNED_BYTE, &texData[0]);
1516
1517 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1518 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1519 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
1520 }
1521 else
1522 DE_ASSERT(false);
1523 }
1524 }
1525
deinit(void)1526 void TextureSamplerCase::deinit(void)
1527 {
1528 RenderCase::deinit();
1529
1530 if (m_textureID)
1531 {
1532 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1533
1534 gl.deleteTextures(1, &m_textureID);
1535 m_textureID = 0;
1536 }
1537 }
1538
iterate(void)1539 TextureSamplerCase::IterateResult TextureSamplerCase::iterate(void)
1540 {
1541 // Draw a grid and texture it with a texture and sample it using special special values. The result samples should all have the green channel at 255 as per the test image.
1542
1543 std::vector<tcu::Vec4> gridVertices(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
1544 std::vector<tcu::UVec2> gridTexCoords(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
1545 std::vector<uint16_t> indices((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) *
1546 (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6);
1547 tcu::Surface resultImage(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1548
1549 // vertices
1550 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
1551 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
1552 {
1553 const float posX = (float)x / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f -
1554 1.0f; // map from [0, len(s_specialFloats) - 1] to [-1, 1]
1555 const float posY = (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f;
1556
1557 gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1558 gridTexCoords[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] =
1559 tcu::UVec2(s_specialFloats[x], s_specialFloats[y]);
1560 }
1561
1562 // tiles
1563 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x)
1564 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y)
1565 {
1566 const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6;
1567
1568 indices[baseNdx + 0] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
1569 indices[baseNdx + 1] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
1570 indices[baseNdx + 2] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
1571
1572 indices[baseNdx + 3] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
1573 indices[baseNdx + 4] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
1574 indices[baseNdx + 5] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
1575 }
1576
1577 m_testCtx.getLog()
1578 << tcu::TestLog::Message
1579 << "Drawing a textured grid with the shader. Sampling from the texture using special floating point values."
1580 << tcu::TestLog::EndMessage;
1581
1582 // Draw grid
1583 {
1584 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1585 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos");
1586 const GLint texCoordLoc = gl.getAttribLocation(m_program->getProgram(), "a_attr");
1587 const GLint samplerLoc = gl.getUniformLocation(m_program->getProgram(), "u_sampler");
1588
1589 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1590 gl.clear(GL_COLOR_BUFFER_BIT);
1591 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1592 gl.useProgram(m_program->getProgram());
1593
1594 gl.uniform1i(samplerLoc, 0);
1595 if (m_testType != TEST_TEX_COORD_CUBE)
1596 gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1597 else
1598 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textureID);
1599
1600 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
1601 gl.vertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, &gridTexCoords[0]);
1602
1603 gl.enableVertexAttribArray(positionLoc);
1604 gl.enableVertexAttribArray(texCoordLoc);
1605 gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
1606 gl.disableVertexAttribArray(positionLoc);
1607 gl.disableVertexAttribArray(texCoordLoc);
1608
1609 gl.useProgram(0);
1610 gl.finish();
1611 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::iterate");
1612
1613 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
1614 }
1615
1616 // verify everywhere was drawn and samples were from the texture (all pixels have Green = 255)
1617 if (!checkResultImage(resultImage))
1618 {
1619 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
1620 return STOP;
1621 }
1622
1623 // test drawing and textures still works
1624 if (!drawTestPattern(true))
1625 {
1626 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
1627 return STOP;
1628 }
1629
1630 // all ok
1631 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1632 return STOP;
1633 }
1634
genVertexSource(void) const1635 std::string TextureSamplerCase::genVertexSource(void) const
1636 {
1637 // vertex shader is passthrough, fragment does the calculations
1638 if (m_type == TYPE_FRAGMENT)
1639 return s_attrPassthroughVertexShaderSource;
1640
1641 // vertex shader does the calculations
1642 std::ostringstream buf;
1643 buf << "#version 300 es\n"
1644 "in highp vec4 a_pos;\n"
1645 "in highp vec2 a_attr;\n";
1646
1647 if (m_testType != TEST_TEX_COORD_CUBE)
1648 buf << "uniform highp sampler2D u_sampler;\n";
1649 else
1650 buf << "uniform highp samplerCube u_sampler;\n";
1651
1652 buf << "out mediump vec4 v_out;\n"
1653 "void main ()\n"
1654 "{\n";
1655
1656 if (m_testType == TEST_TEX_COORD)
1657 buf << " v_out = textureLod(u_sampler, a_attr, 0.0);\n";
1658 else if (m_testType == TEST_LOD)
1659 buf << " v_out = textureLod(u_sampler, a_attr, a_attr.x);\n";
1660 else if (m_testType == TEST_GRAD)
1661 buf << " v_out = textureGrad(u_sampler, a_attr, a_attr, a_attr.yx);\n";
1662 else if (m_testType == TEST_TEX_COORD_CUBE)
1663 buf << " v_out = textureLod(u_sampler, vec3(a_attr, a_attr.x + a_attr.y), 0.0);\n";
1664 else
1665 DE_ASSERT(false);
1666
1667 buf << "\n"
1668 " gl_Position = a_pos;\n"
1669 "}\n";
1670
1671 return buf.str();
1672 }
1673
genFragmentSource(void) const1674 std::string TextureSamplerCase::genFragmentSource(void) const
1675 {
1676 // fragment shader is passthrough
1677 if (m_type == TYPE_VERTEX)
1678 return s_colorPassthroughFragmentShaderSource;
1679
1680 // fragment shader does the calculations
1681 std::ostringstream buf;
1682 buf << "#version 300 es\n"
1683 "layout(location = 0) out mediump vec4 fragColor;\n";
1684
1685 if (m_testType != TEST_TEX_COORD_CUBE)
1686 buf << "uniform highp sampler2D u_sampler;\n";
1687 else
1688 buf << "uniform highp samplerCube u_sampler;\n";
1689
1690 buf << "in highp vec4 v_attr;\n"
1691 "void main ()\n"
1692 "{\n";
1693
1694 if (m_testType == TEST_TEX_COORD)
1695 buf << " fragColor = texture(u_sampler, v_attr.xy);\n";
1696 else if (m_testType == TEST_LOD)
1697 buf << " fragColor = texture(u_sampler, v_attr.xy, v_attr.x);\n";
1698 else if (m_testType == TEST_GRAD)
1699 buf << " fragColor = textureGrad(u_sampler, v_attr.xy, v_attr.xy, v_attr.yx);\n";
1700 else if (m_testType == TEST_TEX_COORD_CUBE)
1701 buf << " fragColor = texture(u_sampler, vec3(v_attr.xy,v_attr.x + v_attr.y));\n";
1702 else
1703 DE_ASSERT(false);
1704
1705 buf << "}\n";
1706
1707 return buf.str();
1708 }
1709
1710 /*--------------------------------------------------------------------*//*!
1711 * \brief Tests special floats as fragment shader outputs
1712 *
1713 * Tests that outputting special floats from a fragment shader does not change
1714 * the normal floating point values of outputted from a fragment shader. Special
1715 * floats are outputted in the green component, normal floating point values
1716 * in the red and blue component. Potential changes are tested by rendering
1717 * test pattern two times with different floating point values. The resulting
1718 * images' red and blue channels should be equal.
1719 *//*--------------------------------------------------------------------*/
1720 class OutputCase : public FramebufferRenderCase
1721 {
1722 public:
1723 OutputCase(Context &context, const char *name, const char *desc, FramebufferRenderCase::FrameBufferType type);
1724 ~OutputCase(void);
1725
1726 void testFBO(void);
1727
1728 private:
1729 std::string genVertexSource(void) const;
1730 std::string genFragmentSource(void) const;
1731 };
1732
OutputCase(Context & context,const char * name,const char * desc,FramebufferRenderCase::FrameBufferType type)1733 OutputCase::OutputCase(Context &context, const char *name, const char *desc,
1734 FramebufferRenderCase::FrameBufferType type)
1735 : FramebufferRenderCase(context, name, desc, type)
1736 {
1737 }
1738
~OutputCase(void)1739 OutputCase::~OutputCase(void)
1740 {
1741 deinit();
1742 }
1743
testFBO(void)1744 void OutputCase::testFBO(void)
1745 {
1746 // Create a 1 X [s_specialFloats] grid of tiles (stripes).
1747 std::vector<tcu::Vec4> gridVertices((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) * 2);
1748 std::vector<uint16_t> indices(DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
1749 tcu::TextureFormat textureFormat(tcu::TextureFormat::RGBA,
1750 (m_fboType == FBO_RGBA_FLOAT16 || m_fboType == FBO_RGBA_FLOAT32) ?
1751 (tcu::TextureFormat::FLOAT) :
1752 (tcu::TextureFormat::UNORM_INT8));
1753 tcu::TextureLevel specialImage(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1754 tcu::TextureLevel normalImage(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1755
1756 // vertices
1757 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y)
1758 {
1759 const float posY = (float)y / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f -
1760 1.0f; // map from [0, len(s_specialFloats) ] to [-1, 1]
1761
1762 gridVertices[y * 2 + 0] = tcu::Vec4(-1.0, posY, 0.0f, 1.0f);
1763 gridVertices[y * 2 + 1] = tcu::Vec4(1.0, posY, 0.0f, 1.0f);
1764 }
1765
1766 // tiles
1767 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
1768 {
1769 const int baseNdx = y * 6;
1770
1771 indices[baseNdx + 0] = (uint16_t)((y + 0) * 2);
1772 indices[baseNdx + 1] = (uint16_t)((y + 1) * 2);
1773 indices[baseNdx + 2] = (uint16_t)((y + 1) * 2 + 1);
1774
1775 indices[baseNdx + 3] = (uint16_t)((y + 0) * 2);
1776 indices[baseNdx + 4] = (uint16_t)((y + 1) * 2 + 1);
1777 indices[baseNdx + 5] = (uint16_t)((y + 0) * 2 + 1);
1778 }
1779
1780 // Draw grids
1781 {
1782 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1783 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos");
1784 const GLint specialLoc = gl.getUniformLocation(m_program->getProgram(), "u_special");
1785
1786 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1787 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1788 gl.useProgram(m_program->getProgram());
1789 GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw");
1790
1791 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
1792 gl.enableVertexAttribArray(positionLoc);
1793
1794 // draw 2 passes. Special and normal.
1795 for (int passNdx = 0; passNdx < 2; ++passNdx)
1796 {
1797 const bool specialPass = (passNdx == 0);
1798
1799 m_testCtx.getLog() << tcu::TestLog::Message << "Pass " << passNdx
1800 << ": Drawing stripes with the shader. Setting u_special for each stripe to ("
1801 << ((specialPass) ? ("special") : ("1.0")) << ")." << tcu::TestLog::EndMessage;
1802
1803 // draw stripes
1804 gl.clear(GL_COLOR_BUFFER_BIT);
1805 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
1806 {
1807 const uint32_t one = 0x3F800000;
1808 const uint32_t special = s_specialFloats[y];
1809 const uint32_t uniformValue = (specialPass) ? (special) : (one);
1810 const int indexIndex = y * 6;
1811
1812 gl.uniform1fv(specialLoc, 1, (const float *)&uniformValue);
1813 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
1814 }
1815
1816 gl.finish();
1817 glu::readPixels(m_context.getRenderContext(), 0, 0,
1818 ((specialPass) ? (specialImage) : (normalImage)).getAccess());
1819 }
1820
1821 gl.disableVertexAttribArray(positionLoc);
1822 gl.useProgram(0);
1823 GLU_EXPECT_NO_ERROR(gl.getError(), "OutputCase::iterate");
1824 }
1825
1826 // Check results
1827 {
1828 tcu::Surface errorMask(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1829 const tcu::RGBA badPixelColor = tcu::RGBA::red();
1830 const tcu::RGBA okPixelColor = tcu::RGBA::green();
1831 int badPixels = 0;
1832
1833 m_testCtx.getLog() << tcu::TestLog::Message
1834 << "Checking passes have identical red and blue channels and the green channel is correct "
1835 "in the constant pass."
1836 << tcu::TestLog::EndMessage;
1837
1838 for (int y = 0; y < specialImage.getHeight(); ++y)
1839 for (int x = 0; x < specialImage.getWidth(); ++x)
1840 {
1841 const float greenThreshold = 0.1f;
1842 const tcu::Vec4 cNormal = normalImage.getAccess().getPixel(x, y);
1843 const tcu::Vec4 cSpecial = specialImage.getAccess().getPixel(x, y);
1844
1845 if (cNormal.x() != cSpecial.x() || cNormal.z() != cSpecial.z() || cNormal.y() < 1.0f - greenThreshold)
1846 {
1847 ++badPixels;
1848 errorMask.setPixel(x, y, badPixelColor);
1849 }
1850 else
1851 errorMask.setPixel(x, y, okPixelColor);
1852 }
1853
1854 m_testCtx.getLog() << tcu::TestLog::Message << "Found " << badPixels << " invalid pixel(s)."
1855 << tcu::TestLog::EndMessage;
1856
1857 if (badPixels)
1858 {
1859 m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
1860 << tcu::TestLog::Image("Image with special green channel",
1861 "Image with special green channel", specialImage)
1862 << tcu::TestLog::Image("Image with constant green channel",
1863 "Image with constant green channel", normalImage)
1864 << tcu::TestLog::Image("Error Mask", "Error Mask", errorMask)
1865 << tcu::TestLog::EndImageSet;
1866
1867 // all ok?
1868 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1869 }
1870 else
1871 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1872 }
1873 }
1874
genVertexSource(void) const1875 std::string OutputCase::genVertexSource(void) const
1876 {
1877 return "#version 300 es\n"
1878 "in highp vec4 a_pos;\n"
1879 "out highp vec2 v_pos;\n"
1880 "void main ()\n"
1881 "{\n"
1882 " gl_Position = a_pos;\n"
1883 " v_pos = a_pos.xy;\n"
1884 "}\n";
1885 }
1886
genFragmentSource(void) const1887 std::string OutputCase::genFragmentSource(void) const
1888 {
1889 return "#version 300 es\n"
1890 "layout(location = 0) out highp vec4 fragColor;\n"
1891 "uniform highp float u_special;\n"
1892 "in highp vec2 v_pos;\n"
1893 "void main ()\n"
1894 "{\n"
1895 " fragColor = vec4((v_pos.x + 1.0) * 0.5, u_special, (v_pos.y + 1.0) * 0.5, 1.0);\n"
1896 "}\n";
1897 }
1898
1899 /*--------------------------------------------------------------------*//*!
1900 * \brief Tests special floats in blending
1901 *
1902 * Tests special floats as alpha and color components with various blending
1903 * modes. Test draws a test pattern and then does various blend operations
1904 * with special float values. After the blending test another test pattern
1905 * is drawn to detect possible blending anomalies. Test patterns should be
1906 * identical.
1907 *//*--------------------------------------------------------------------*/
1908 class BlendingCase : public FramebufferRenderCase
1909 {
1910 public:
1911 BlendingCase(Context &context, const char *name, const char *desc, FramebufferRenderCase::FrameBufferType type);
1912 ~BlendingCase(void);
1913
1914 void testFBO(void);
1915
1916 private:
1917 void drawTestImage(tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex);
1918
1919 std::string genVertexSource(void) const;
1920 std::string genFragmentSource(void) const;
1921 };
1922
BlendingCase(Context & context,const char * name,const char * desc,FramebufferRenderCase::FrameBufferType type)1923 BlendingCase::BlendingCase(Context &context, const char *name, const char *desc,
1924 FramebufferRenderCase::FrameBufferType type)
1925 : FramebufferRenderCase(context, name, desc, type)
1926 {
1927 }
1928
~BlendingCase(void)1929 BlendingCase::~BlendingCase(void)
1930 {
1931 deinit();
1932 }
1933
testFBO(void)1934 void BlendingCase::testFBO(void)
1935 {
1936 static const GLenum equations[] = {GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, GL_MIN, GL_MAX};
1937 static const GLenum functions[] = {
1938 GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1939 };
1940
1941 // Create a [BlendFuncs] X [s_specialFloats] grid of tiles. ( BlendFuncs = equations x functions )
1942
1943 const int numBlendFuncs = DE_LENGTH_OF_ARRAY(equations) * DE_LENGTH_OF_ARRAY(functions);
1944 std::vector<tcu::Vec4> gridVertices((numBlendFuncs + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1));
1945 std::vector<uint16_t> indices(numBlendFuncs * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
1946 tcu::TextureFormat textureFormat(tcu::TextureFormat::RGBA,
1947 (m_fboType == FBO_RGBA_FLOAT16 || m_fboType == FBO_RGBA_FLOAT32) ?
1948 (tcu::TextureFormat::FLOAT) :
1949 (tcu::TextureFormat::UNORM_INT8));
1950 tcu::TextureLevel beforeImage(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1951 tcu::TextureLevel afterImage(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1952
1953 // vertices
1954 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x)
1955 for (int y = 0; y < numBlendFuncs + 1; ++y)
1956 {
1957 const float posX = (float)x / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f -
1958 1.0f; // map from [0, len(s_specialFloats)] to [-1, 1]
1959 const float posY = (float)y / (float)numBlendFuncs * 2.0f - 1.0f;
1960
1961 gridVertices[x * (numBlendFuncs + 1) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1962 }
1963
1964 // tiles
1965 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
1966 for (int y = 0; y < numBlendFuncs; ++y)
1967 {
1968 const int baseNdx = (x * numBlendFuncs + y) * 6;
1969
1970 indices[baseNdx + 0] = (uint16_t)((x + 0) * (numBlendFuncs + 1) + (y + 0));
1971 indices[baseNdx + 1] = (uint16_t)((x + 1) * (numBlendFuncs + 1) + (y + 1));
1972 indices[baseNdx + 2] = (uint16_t)((x + 1) * (numBlendFuncs + 1) + (y + 0));
1973
1974 indices[baseNdx + 3] = (uint16_t)((x + 0) * (numBlendFuncs + 1) + (y + 0));
1975 indices[baseNdx + 4] = (uint16_t)((x + 1) * (numBlendFuncs + 1) + (y + 1));
1976 indices[baseNdx + 5] = (uint16_t)((x + 0) * (numBlendFuncs + 1) + (y + 1));
1977 }
1978
1979 // Draw tiles
1980 {
1981 const int numPasses = 5;
1982 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1983 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos");
1984 const GLint specialLoc = gl.getUniformLocation(m_program->getProgram(), "u_special");
1985
1986 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1987 gl.clear(GL_COLOR_BUFFER_BIT);
1988 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1989 gl.useProgram(m_program->getProgram());
1990 gl.enable(GL_BLEND);
1991 GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw");
1992
1993 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
1994 gl.enableVertexAttribArray(positionLoc);
1995
1996 // draw "before" image
1997 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing pre-draw pattern." << tcu::TestLog::EndMessage;
1998 drawTestImage(beforeImage.getAccess(), specialLoc, (int)gridVertices.size() - 1);
1999 GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw pattern");
2000
2001 // draw multiple passes with special floats
2002 gl.clear(GL_COLOR_BUFFER_BIT);
2003 for (int passNdx = 0; passNdx < numPasses; ++passNdx)
2004 {
2005 de::Random rnd(123 + 567 * passNdx);
2006
2007 m_testCtx.getLog() << tcu::TestLog::Message << "Pass " << passNdx << ": Drawing tiles with the shader.\n"
2008 << "\tVarying u_special for each tile.\n"
2009 << "\tVarying blend function and blend equation for each tile.\n"
2010 << tcu::TestLog::EndMessage;
2011
2012 // draw tiles
2013 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
2014 for (int y = 0; y < numBlendFuncs; ++y)
2015 {
2016 const GLenum blendEquation = equations[y % DE_LENGTH_OF_ARRAY(equations)];
2017 const GLenum blendFunction = functions[y / DE_LENGTH_OF_ARRAY(equations)];
2018 const GLenum blendFunctionDst =
2019 rnd.choose<GLenum>(DE_ARRAY_BEGIN(functions), DE_ARRAY_END(functions));
2020 const int indexIndex = (x * numBlendFuncs + y) * 6;
2021
2022 // "rnd.get"s are run in a deterministic order
2023 const uint32_t componentR =
2024 rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
2025 const uint32_t componentG =
2026 rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
2027 const uint32_t componentB =
2028 rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
2029 const uint32_t componentA =
2030 rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
2031 const tcu::UVec4 uniformValue = tcu::UVec4(componentR, componentG, componentB, componentA);
2032
2033 gl.uniform4fv(specialLoc, 1, (const float *)uniformValue.getPtr());
2034 gl.blendEquation(blendEquation);
2035 gl.blendFunc(blendFunction, blendFunctionDst);
2036 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
2037 }
2038 }
2039 GLU_EXPECT_NO_ERROR(gl.getError(), "special passes");
2040
2041 // draw "after" image
2042 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing post-draw pattern." << tcu::TestLog::EndMessage;
2043 drawTestImage(afterImage.getAccess(), specialLoc, (int)gridVertices.size() - 1);
2044 GLU_EXPECT_NO_ERROR(gl.getError(), "post-draw pattern");
2045
2046 gl.disableVertexAttribArray(positionLoc);
2047 gl.useProgram(0);
2048 GLU_EXPECT_NO_ERROR(gl.getError(), "OutputCase::iterate");
2049 }
2050
2051 // Check results
2052 {
2053 tcu::Surface errorMask(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
2054 const tcu::RGBA badPixelColor = tcu::RGBA::red();
2055 const tcu::RGBA okPixelColor = tcu::RGBA::green();
2056 int badPixels = 0;
2057
2058 m_testCtx.getLog() << tcu::TestLog::Message << "Checking patterns are identical." << tcu::TestLog::EndMessage;
2059
2060 for (int y = 0; y < beforeImage.getHeight(); ++y)
2061 for (int x = 0; x < beforeImage.getWidth(); ++x)
2062 {
2063 const tcu::Vec4 cBefore = beforeImage.getAccess().getPixel(x, y);
2064 const tcu::Vec4 cAfter = afterImage.getAccess().getPixel(x, y);
2065
2066 if (cBefore != cAfter)
2067 {
2068 ++badPixels;
2069 errorMask.setPixel(x, y, badPixelColor);
2070 }
2071 else
2072 errorMask.setPixel(x, y, okPixelColor);
2073 }
2074
2075 m_testCtx.getLog() << tcu::TestLog::Message << "Found " << badPixels << " invalid pixel(s)."
2076 << tcu::TestLog::EndMessage;
2077
2078 if (badPixels)
2079 {
2080 m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
2081 << tcu::TestLog::Image("Pattern drawn before special float blending",
2082 "Pattern drawn before special float blending", beforeImage)
2083 << tcu::TestLog::Image("Pattern drawn after special float blending",
2084 "Pattern drawn after special float blending", afterImage)
2085 << tcu::TestLog::EndImageSet;
2086
2087 // all ok?
2088 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
2089 }
2090 else
2091 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2092 }
2093 }
2094
drawTestImage(tcu::PixelBufferAccess dst,GLuint uColorLoc,int maxVertexIndex)2095 void BlendingCase::drawTestImage(tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex)
2096 {
2097 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2098 de::Random rnd(123);
2099
2100 gl.clear(GL_COLOR_BUFFER_BIT);
2101 gl.blendEquation(GL_FUNC_ADD);
2102 gl.blendFunc(GL_ONE, GL_ONE);
2103
2104 for (int tri = 0; tri < 20; ++tri)
2105 {
2106 tcu::Vec4 color;
2107 color.x() = rnd.getFloat();
2108 color.y() = rnd.getFloat();
2109 color.z() = rnd.getFloat();
2110 color.w() = rnd.getFloat();
2111 gl.uniform4fv(uColorLoc, 1, color.getPtr());
2112
2113 uint16_t indices[3];
2114 indices[0] = (uint16_t)rnd.getInt(0, maxVertexIndex);
2115 indices[1] = (uint16_t)rnd.getInt(0, maxVertexIndex);
2116 indices[2] = (uint16_t)rnd.getInt(0, maxVertexIndex);
2117
2118 gl.drawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, indices);
2119 }
2120
2121 gl.finish();
2122 glu::readPixels(m_context.getRenderContext(), 0, 0, dst);
2123 }
2124
genVertexSource(void) const2125 std::string BlendingCase::genVertexSource(void) const
2126 {
2127 return "#version 300 es\n"
2128 "in highp vec4 a_pos;\n"
2129 "void main ()\n"
2130 "{\n"
2131 " gl_Position = a_pos;\n"
2132 "}\n";
2133 }
2134
genFragmentSource(void) const2135 std::string BlendingCase::genFragmentSource(void) const
2136 {
2137 return "#version 300 es\n"
2138 "layout(location = 0) out highp vec4 fragColor;\n"
2139 "uniform highp vec4 u_special;\n"
2140 "void main ()\n"
2141 "{\n"
2142 " fragColor = u_special;\n"
2143 "}\n";
2144 }
2145
2146 } // namespace
2147
SpecialFloatTests(Context & context)2148 SpecialFloatTests::SpecialFloatTests(Context &context) : TestCaseGroup(context, "special_float", "Special float tests")
2149 {
2150 }
2151
~SpecialFloatTests(void)2152 SpecialFloatTests::~SpecialFloatTests(void)
2153 {
2154 }
2155
init(void)2156 void SpecialFloatTests::init(void)
2157 {
2158 tcu::TestCaseGroup *const vertexGroup =
2159 new tcu::TestCaseGroup(m_testCtx, "vertex", "Run vertex shader with special float values");
2160 tcu::TestCaseGroup *const fragmentGroup =
2161 new tcu::TestCaseGroup(m_testCtx, "fragment", "Run fragment shader with special float values");
2162 tcu::TestCaseGroup *const framebufferGroup =
2163 new tcu::TestCaseGroup(m_testCtx, "framebuffer", "Test framebuffers containing special float values");
2164
2165 // .vertex
2166 {
2167 vertexGroup->addChild(
2168 new VertexAttributeCase(m_context, "attribute_buffer", "special attribute values in a buffer",
2169 VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_VERTEX));
2170 vertexGroup->addChild(
2171 new VertexAttributeCase(m_context, "attribute_client", "special attribute values in a client storage",
2172 VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_VERTEX));
2173 vertexGroup->addChild(
2174 new UniformCase(m_context, "uniform", "special uniform values", UniformCase::TYPE_VERTEX));
2175 vertexGroup->addChild(new TextureCase(m_context, "texture", "texture with special floating point values",
2176 TextureCase::TYPE_VERTEX, TextureCase::TEXTURE_FLOAT,
2177 TextureCase::UPLOAD_CLIENT));
2178 vertexGroup->addChild(
2179 new TextureCase(m_context, "texture_pbo", "texture (via pbo) with special floating point values",
2180 TextureCase::TYPE_VERTEX, TextureCase::TEXTURE_FLOAT, TextureCase::UPLOAD_PBO));
2181 vertexGroup->addChild(
2182 new TextureCase(m_context, "texture_shadow", "shadow texture with special floating point values",
2183 TextureCase::TYPE_VERTEX, TextureCase::TEXTURE_DEPTH, TextureCase::UPLOAD_CLIENT));
2184 vertexGroup->addChild(new TextureSamplerCase(m_context, "sampler_tex_coord", "special texture coords",
2185 TextureSamplerCase::TYPE_VERTEX,
2186 TextureSamplerCase::TEST_TEX_COORD));
2187 vertexGroup->addChild(
2188 new TextureSamplerCase(m_context, "sampler_tex_coord_cube", "special texture coords to cubemap",
2189 TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_TEX_COORD_CUBE));
2190 vertexGroup->addChild(new TextureSamplerCase(m_context, "sampler_lod", "special texture lod",
2191 TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_LOD));
2192 vertexGroup->addChild(new TextureSamplerCase(m_context, "sampler_grad", "special texture grad",
2193 TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_GRAD));
2194
2195 addChild(vertexGroup);
2196 }
2197
2198 // .fragment
2199 {
2200 fragmentGroup->addChild(
2201 new VertexAttributeCase(m_context, "attribute_buffer", "special attribute values in a buffer",
2202 VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_FRAGMENT));
2203 fragmentGroup->addChild(
2204 new VertexAttributeCase(m_context, "attribute_client", "special attribute values in a client storage",
2205 VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_FRAGMENT));
2206 fragmentGroup->addChild(
2207 new UniformCase(m_context, "uniform", "special uniform values", UniformCase::TYPE_FRAGMENT));
2208 fragmentGroup->addChild(new TextureCase(m_context, "texture", "texture with special floating point values",
2209 TextureCase::TYPE_FRAGMENT, TextureCase::TEXTURE_FLOAT,
2210 TextureCase::UPLOAD_CLIENT));
2211 fragmentGroup->addChild(
2212 new TextureCase(m_context, "texture_pbo", "texture (via pbo) with special floating point values",
2213 TextureCase::TYPE_FRAGMENT, TextureCase::TEXTURE_FLOAT, TextureCase::UPLOAD_PBO));
2214 fragmentGroup->addChild(
2215 new TextureCase(m_context, "texture_shadow", "shadow texture with special floating point values",
2216 TextureCase::TYPE_FRAGMENT, TextureCase::TEXTURE_DEPTH, TextureCase::UPLOAD_CLIENT));
2217 fragmentGroup->addChild(new TextureSamplerCase(m_context, "sampler_tex_coord", "special texture coords",
2218 TextureSamplerCase::TYPE_FRAGMENT,
2219 TextureSamplerCase::TEST_TEX_COORD));
2220 fragmentGroup->addChild(
2221 new TextureSamplerCase(m_context, "sampler_tex_coord_cube", "special texture coords to cubemap",
2222 TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_TEX_COORD_CUBE));
2223 fragmentGroup->addChild(new TextureSamplerCase(m_context, "sampler_lod", "special texture lod",
2224 TextureSamplerCase::TYPE_FRAGMENT,
2225 TextureSamplerCase::TEST_LOD));
2226 fragmentGroup->addChild(new TextureSamplerCase(m_context, "sampler_grad", "special texture grad",
2227 TextureSamplerCase::TYPE_FRAGMENT,
2228 TextureSamplerCase::TEST_GRAD));
2229
2230 addChild(fragmentGroup);
2231 }
2232
2233 // .framebuffer
2234 {
2235 framebufferGroup->addChild(new OutputCase(m_context, "write_default",
2236 "write special floating point values to default framebuffer",
2237 FramebufferRenderCase::FBO_DEFAULT));
2238 framebufferGroup->addChild(new OutputCase(m_context, "write_rgba4",
2239 "write special floating point values to RGBA4 framebuffer",
2240 FramebufferRenderCase::FBO_RGBA4));
2241 framebufferGroup->addChild(new OutputCase(m_context, "write_rgb5_a1",
2242 "write special floating point values to RGB5_A1 framebuffer",
2243 FramebufferRenderCase::FBO_RGB5_A1));
2244 framebufferGroup->addChild(new OutputCase(m_context, "write_rgb565",
2245 "write special floating point values to RGB565 framebuffer",
2246 FramebufferRenderCase::FBO_RGB565));
2247 framebufferGroup->addChild(new OutputCase(m_context, "write_rgba8",
2248 "write special floating point values to RGBA8 framebuffer",
2249 FramebufferRenderCase::FBO_RGBA8));
2250 framebufferGroup->addChild(new OutputCase(m_context, "write_rgb10_a2",
2251 "write special floating point values to RGB10_A2 framebuffer",
2252 FramebufferRenderCase::FBO_RGB10_A2));
2253 framebufferGroup->addChild(new OutputCase(m_context, "write_float16",
2254 "write special floating point values to float16 framebuffer",
2255 FramebufferRenderCase::FBO_RGBA_FLOAT16));
2256 framebufferGroup->addChild(new OutputCase(m_context, "write_float32",
2257 "write special floating point values to float32 framebuffer",
2258 FramebufferRenderCase::FBO_RGBA_FLOAT32));
2259
2260 framebufferGroup->addChild(new BlendingCase(m_context, "blend_default",
2261 "blend special floating point values in a default framebuffer",
2262 FramebufferRenderCase::FBO_DEFAULT));
2263 framebufferGroup->addChild(new BlendingCase(m_context, "blend_rgba8",
2264 "blend special floating point values in a RGBA8 framebuffer",
2265 FramebufferRenderCase::FBO_RGBA8));
2266 framebufferGroup->addChild(new BlendingCase(m_context, "blend_float16",
2267 "blend special floating point values in a float16 framebuffer",
2268 FramebufferRenderCase::FBO_RGBA_FLOAT16));
2269
2270 addChild(framebufferGroup);
2271 }
2272 }
2273
2274 } // namespace Stress
2275 } // namespace gles3
2276 } // namespace deqp
2277