1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 2.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 "es2sSpecialFloatTests.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 gles2
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 = "varying mediump vec4 v_out;\n"
83 "void main ()\n"
84 "{\n"
85 " gl_FragColor = v_out;\n"
86 "}\n";
87 static const char *const s_attrPassthroughVertexShaderSource = "attribute highp vec4 a_pos;\n"
88 "attribute highp vec4 a_attr;\n"
89 "varying mediump vec4 v_attr;\n"
90 "void main ()\n"
91 "{\n"
92 " v_attr = a_attr;\n"
93 " gl_Position = a_pos;\n"
94 "}\n";
95
96 class RenderCase : public TestCase
97 {
98 public:
99 enum RenderTargetType
100 {
101 RENDERTARGETTYPE_SCREEN,
102 RENDERTARGETTYPE_FBO
103 };
104
105 RenderCase(Context &context, const char *name, const char *desc,
106 RenderTargetType renderTargetType = RENDERTARGETTYPE_SCREEN);
107 virtual ~RenderCase(void);
108
109 virtual void init(void);
110 virtual void deinit(void);
111
112 protected:
113 bool checkResultImage(const tcu::Surface &result);
114 bool drawTestPattern(bool useTexture);
115
116 virtual std::string genVertexSource(void) const = 0;
117 virtual std::string genFragmentSource(void) const = 0;
118
119 const glu::ShaderProgram *m_program;
120 const RenderTargetType m_renderTargetType;
121 };
122
RenderCase(Context & context,const char * name,const char * desc,RenderTargetType renderTargetType)123 RenderCase::RenderCase(Context &context, const char *name, const char *desc, RenderTargetType renderTargetType)
124 : TestCase(context, name, desc)
125 , m_program(DE_NULL)
126 , m_renderTargetType(renderTargetType)
127 {
128 }
129
~RenderCase(void)130 RenderCase::~RenderCase(void)
131 {
132 deinit();
133 }
134
init(void)135 void RenderCase::init(void)
136 {
137 const int width = m_context.getRenderTarget().getWidth();
138 const int height = m_context.getRenderTarget().getHeight();
139
140 // check target size
141 if (m_renderTargetType == RENDERTARGETTYPE_SCREEN)
142 {
143 if (width < TEST_CANVAS_SIZE || height < TEST_CANVAS_SIZE)
144 throw tcu::NotSupportedError(std::string("Render target size must be at least ") +
145 de::toString(TEST_CANVAS_SIZE) + "x" + de::toString(TEST_CANVAS_SIZE));
146 }
147 else if (m_renderTargetType == RENDERTARGETTYPE_FBO)
148 {
149 GLint maxTexSize = 0;
150 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
151
152 if (maxTexSize < TEST_CANVAS_SIZE)
153 throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") +
154 de::toString(TEST_CANVAS_SIZE));
155 }
156 else
157 DE_ASSERT(false);
158
159 // gen shader
160
161 m_testCtx.getLog() << tcu::TestLog::Message << "Creating test shader." << tcu::TestLog::EndMessage;
162
163 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
164 << glu::VertexSource(genVertexSource())
165 << glu::FragmentSource(genFragmentSource()));
166 m_testCtx.getLog() << *m_program;
167
168 if (!m_program->isOk())
169 throw tcu::TestError("shader compile failed");
170 }
171
deinit(void)172 void RenderCase::deinit(void)
173 {
174 if (m_program)
175 {
176 delete m_program;
177 m_program = DE_NULL;
178 }
179 }
180
checkResultImage(const tcu::Surface & result)181 bool RenderCase::checkResultImage(const tcu::Surface &result)
182 {
183 tcu::Surface errorMask(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
184 bool error = false;
185
186 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output image." << tcu::TestLog::EndMessage;
187
188 for (int y = 0; y < TEST_CANVAS_SIZE; ++y)
189 for (int x = 0; x < TEST_CANVAS_SIZE; ++x)
190 {
191 const tcu::RGBA col = result.getPixel(x, y);
192
193 if (col.getGreen() == 255)
194 errorMask.setPixel(x, y, tcu::RGBA::green());
195 else
196 {
197 errorMask.setPixel(x, y, tcu::RGBA::red());
198 error = true;
199 }
200 }
201
202 if (error)
203 {
204 m_testCtx.getLog() << tcu::TestLog::Message << "Result image has missing or invalid pixels"
205 << tcu::TestLog::EndMessage;
206 m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
207 << tcu::TestLog::Image("Result", "Result", result)
208 << tcu::TestLog::Image("Error mask", "Error mask", errorMask) << tcu::TestLog::EndImageSet;
209 }
210 else
211 {
212 m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
213 << tcu::TestLog::Image("Result", "Result", result) << tcu::TestLog::EndImageSet;
214 }
215
216 return !error;
217 }
218
drawTestPattern(bool useTexture)219 bool RenderCase::drawTestPattern(bool useTexture)
220 {
221 static const tcu::Vec4 fullscreenQuad[4] = {
222 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
223 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
224 tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),
225 tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
226 };
227 const char *const vertexSource = "attribute highp vec4 a_pos;\n"
228 "varying mediump vec4 v_position;\n"
229 "void main ()\n"
230 "{\n"
231 " v_position = a_pos;\n"
232 " gl_Position = a_pos;\n"
233 "}\n";
234 const char *const fragmentSourceNoTex = "varying mediump vec4 v_position;\n"
235 "void main ()\n"
236 "{\n"
237 " gl_FragColor = vec4((v_position.x + 1.0) * 0.5, 1.0, 1.0, 1.0);\n"
238 "}\n";
239 const char *const fragmentSourceTex = "uniform mediump sampler2D u_sampler;\n"
240 "varying mediump vec4 v_position;\n"
241 "void main ()\n"
242 "{\n"
243 " gl_FragColor = texture2D(u_sampler, v_position.xy);\n"
244 "}\n";
245 const char *const fragmentSource = (useTexture) ? (fragmentSourceTex) : (fragmentSourceNoTex);
246 const tcu::RGBA formatThreshold = m_context.getRenderTarget().getPixelFormat().getColorThreshold();
247
248 tcu::Surface resultImage(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
249 tcu::Surface errorMask(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
250 bool error = false;
251
252 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a test pattern to detect "
253 << ((useTexture) ? ("texture sampling") : ("")) << " side-effects." << tcu::TestLog::EndMessage;
254
255 // draw pattern
256 {
257 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
258 const glu::ShaderProgram patternProgram(m_context.getRenderContext(),
259 glu::ProgramSources() << glu::VertexSource(vertexSource)
260 << glu::FragmentSource(fragmentSource));
261 const GLint positionLoc = gl.getAttribLocation(patternProgram.getProgram(), "a_pos");
262 GLuint textureID = 0;
263
264 if (useTexture)
265 {
266 const int textureSize = 32;
267 std::vector<tcu::Vector<uint8_t, 4>> buffer(textureSize * textureSize);
268
269 for (int x = 0; x < textureSize; ++x)
270 for (int y = 0; y < textureSize; ++y)
271 {
272 // sum of two axis aligned gradients. Each gradient is 127 at the edges and 0 at the center.
273 // pattern is symmetric (x and y) => no discontinuity near boundary => no need to worry of results with LINEAR filtering near boundaries
274 const uint8_t redComponent =
275 (uint8_t)de::clamp(de::abs((float)x / (float)textureSize - 0.5f) * 255.0f +
276 de::abs((float)y / (float)textureSize - 0.5f) * 255.0f,
277 0.0f, 255.0f);
278
279 buffer[x * textureSize + y] = tcu::Vector<uint8_t, 4>(redComponent, 255, 255, 255);
280 }
281
282 gl.genTextures(1, &textureID);
283 gl.bindTexture(GL_TEXTURE_2D, textureID);
284 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureSize, textureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
285 buffer[0].getPtr());
286 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
287 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
288 }
289
290 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
291 gl.clear(GL_COLOR_BUFFER_BIT);
292 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
293 gl.useProgram(patternProgram.getProgram());
294
295 if (useTexture)
296 gl.uniform1i(gl.getUniformLocation(patternProgram.getProgram(), "u_sampler"), 0);
297
298 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &fullscreenQuad[0]);
299
300 gl.enableVertexAttribArray(positionLoc);
301 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
302 gl.disableVertexAttribArray(positionLoc);
303
304 gl.useProgram(0);
305 gl.finish();
306 GLU_EXPECT_NO_ERROR(gl.getError(), "RenderCase::drawTestPattern");
307
308 if (textureID)
309 gl.deleteTextures(1, &textureID);
310
311 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
312 }
313
314 // verify pattern
315 for (int y = 0; y < TEST_CANVAS_SIZE; ++y)
316 for (int x = 0; x < TEST_CANVAS_SIZE; ++x)
317 {
318 const float texGradientPosX = deFloatFrac((float)x * 2.0f / (float)TEST_CANVAS_SIZE);
319 const float texGradientPosY = deFloatFrac((float)y * 2.0f / (float)TEST_CANVAS_SIZE);
320 const uint8_t texRedComponent = (uint8_t)de::clamp(
321 de::abs(texGradientPosX - 0.5f) * 255.0f + de::abs(texGradientPosY - 0.5f) * 255.0f, 0.0f, 255.0f);
322
323 const tcu::RGBA refColTexture = tcu::RGBA(texRedComponent, 255, 255, 255);
324 const tcu::RGBA refColGradient =
325 tcu::RGBA((int)((float)x / (float)TEST_CANVAS_SIZE * 255.0f), 255, 255, 255);
326 const tcu::RGBA &refCol = (useTexture) ? (refColTexture) : (refColGradient);
327
328 const int colorThreshold = 10;
329 const tcu::RGBA col = resultImage.getPixel(x, y);
330 const tcu::IVec4 colorDiff = tcu::abs(col.toIVec() - refCol.toIVec());
331
332 if (colorDiff.x() > formatThreshold.getRed() + colorThreshold ||
333 colorDiff.y() > formatThreshold.getGreen() + colorThreshold ||
334 colorDiff.z() > formatThreshold.getBlue() + colorThreshold)
335 {
336 errorMask.setPixel(x, y, tcu::RGBA::red());
337 error = true;
338 }
339 else
340 errorMask.setPixel(x, y, tcu::RGBA::green());
341 }
342
343 // report error
344 if (error)
345 {
346 m_testCtx.getLog() << tcu::TestLog::Message << "Test pattern has missing/invalid pixels"
347 << tcu::TestLog::EndMessage;
348 m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
349 << tcu::TestLog::Image("Result", "Result", resultImage)
350 << tcu::TestLog::Image("Error mask", "Error mask", errorMask) << tcu::TestLog::EndImageSet;
351 }
352 else
353 m_testCtx.getLog() << tcu::TestLog::Message << "No side-effects found." << tcu::TestLog::EndMessage;
354
355 return !error;
356 }
357
358 class FramebufferRenderCase : public RenderCase
359 {
360 public:
361 enum FrameBufferType
362 {
363 FBO_DEFAULT = 0,
364 FBO_RGBA,
365 FBO_RGBA4,
366 FBO_RGB5_A1,
367 FBO_RGB565,
368 FBO_RGBA_FLOAT16,
369
370 FBO_LAST
371 };
372
373 FramebufferRenderCase(Context &context, const char *name, const char *desc, FrameBufferType fboType);
374 virtual ~FramebufferRenderCase(void);
375
376 virtual void init(void);
377 virtual void deinit(void);
378 IterateResult iterate(void);
379
380 virtual void testFBO(void) = DE_NULL;
381
382 protected:
383 const FrameBufferType m_fboType;
384
385 private:
386 GLuint m_texID;
387 GLuint m_fboID;
388 };
389
FramebufferRenderCase(Context & context,const char * name,const char * desc,FrameBufferType fboType)390 FramebufferRenderCase::FramebufferRenderCase(Context &context, const char *name, const char *desc,
391 FrameBufferType fboType)
392 : RenderCase(context, name, desc, (fboType == FBO_DEFAULT) ? (RENDERTARGETTYPE_SCREEN) : (RENDERTARGETTYPE_FBO))
393 , m_fboType(fboType)
394 , m_texID(0)
395 , m_fboID(0)
396 {
397 DE_ASSERT(m_fboType < FBO_LAST);
398 }
399
~FramebufferRenderCase(void)400 FramebufferRenderCase::~FramebufferRenderCase(void)
401 {
402 deinit();
403 }
404
init(void)405 void FramebufferRenderCase::init(void)
406 {
407 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
408
409 // check requirements
410 if (m_fboType == FBO_RGBA_FLOAT16)
411 {
412 // half float texture is allowed (OES_texture_half_float) and it is color renderable (EXT_color_buffer_half_float)
413 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_texture_half_float") ||
414 !m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_half_float"))
415 throw tcu::NotSupportedError("Color renderable half float texture required.");
416 }
417
418 // gen shader
419 RenderCase::init();
420
421 // create render target
422 if (m_fboType == FBO_DEFAULT)
423 {
424 m_testCtx.getLog() << tcu::TestLog::Message << "Using default framebuffer." << tcu::TestLog::EndMessage;
425 }
426 else
427 {
428 GLuint internalFormat = 0;
429 GLuint format = 0;
430 GLuint type = 0;
431
432 #if !defined(GL_HALF_FLOAT_OES)
433 #define GL_HALF_FLOAT_OES 0x8D61
434 #endif
435
436 switch (m_fboType)
437 {
438 case FBO_RGBA:
439 internalFormat = GL_RGBA;
440 format = GL_RGBA;
441 type = GL_UNSIGNED_BYTE;
442 break;
443 case FBO_RGBA4:
444 internalFormat = GL_RGBA;
445 format = GL_RGBA;
446 type = GL_UNSIGNED_SHORT_4_4_4_4;
447 break;
448 case FBO_RGB5_A1:
449 internalFormat = GL_RGBA;
450 format = GL_RGBA;
451 type = GL_UNSIGNED_SHORT_5_5_5_1;
452 break;
453 case FBO_RGB565:
454 internalFormat = GL_RGB;
455 format = GL_RGB;
456 type = GL_UNSIGNED_SHORT_5_6_5;
457 break;
458 case FBO_RGBA_FLOAT16:
459 internalFormat = GL_RGBA;
460 format = GL_RGBA;
461 type = GL_HALF_FLOAT_OES;
462 break;
463
464 default:
465 DE_ASSERT(false);
466 break;
467 }
468
469 m_testCtx.getLog() << tcu::TestLog::Message
470 << "Creating fbo. Texture internalFormat = " << glu::getTextureFormatStr(internalFormat)
471 << ", format = " << glu::getTextureFormatStr(format) << ", type = " << glu::getTypeStr(type)
472 << tcu::TestLog::EndMessage;
473
474 // gen texture
475 gl.genTextures(1, &m_texID);
476 gl.bindTexture(GL_TEXTURE_2D, m_texID);
477 gl.texImage2D(GL_TEXTURE_2D, 0, internalFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE, 0, format, type, DE_NULL);
478 GLU_EXPECT_NO_ERROR(gl.getError(), "texture init");
479
480 // gen fbo
481 gl.genFramebuffers(1, &m_fboID);
482 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
483 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texID, 0);
484 GLU_EXPECT_NO_ERROR(gl.getError(), "fbo init");
485
486 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
487 throw tcu::NotSupportedError("could not create fbo for testing.");
488 }
489 }
490
deinit(void)491 void FramebufferRenderCase::deinit(void)
492 {
493 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
494
495 if (m_texID)
496 {
497 gl.deleteTextures(1, &m_texID);
498 m_texID = 0;
499 }
500
501 if (m_fboID)
502 {
503 gl.deleteFramebuffers(1, &m_fboID);
504 m_fboID = 0;
505 }
506 }
507
iterate(void)508 FramebufferRenderCase::IterateResult FramebufferRenderCase::iterate(void)
509 {
510 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
511
512 // bind fbo (or don't if we are using default)
513 if (m_fboID)
514 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
515
516 // do something with special floats
517 testFBO();
518
519 return STOP;
520 }
521
522 /*--------------------------------------------------------------------*//*!
523 * \brief Tests special floats as vertex attributes
524 *
525 * Tests that special floats transferred to the shader using vertex
526 * attributes do not change the results of normal floating point
527 * calculations. Special floats are put to 4-vector's x and y components and
528 * value 1.0 is put to z and w. The resulting fragment's green channel
529 * should be 1.0 everywhere.
530 *
531 * After the calculation test a test pattern is drawn to detect possible
532 * floating point operation anomalies.
533 *//*--------------------------------------------------------------------*/
534 class VertexAttributeCase : public RenderCase
535 {
536 public:
537 enum Storage
538 {
539 STORAGE_BUFFER = 0,
540 STORAGE_CLIENT,
541
542 STORAGE_LAST
543 };
544 enum ShaderType
545 {
546 TYPE_VERTEX = 0,
547 TYPE_FRAGMENT,
548
549 TYPE_LAST
550 };
551
552 VertexAttributeCase(Context &context, const char *name, const char *desc, Storage storage, ShaderType type);
553 ~VertexAttributeCase(void);
554
555 void init(void);
556 void deinit(void);
557 IterateResult iterate(void);
558
559 private:
560 std::string genVertexSource(void) const;
561 std::string genFragmentSource(void) const;
562
563 const Storage m_storage;
564 const ShaderType m_type;
565 GLuint m_positionVboID;
566 GLuint m_attribVboID;
567 GLuint m_elementVboID;
568 };
569
VertexAttributeCase(Context & context,const char * name,const char * desc,Storage storage,ShaderType type)570 VertexAttributeCase::VertexAttributeCase(Context &context, const char *name, const char *desc, Storage storage,
571 ShaderType type)
572 : RenderCase(context, name, desc)
573 , m_storage(storage)
574 , m_type(type)
575 , m_positionVboID(0)
576 , m_attribVboID(0)
577 , m_elementVboID(0)
578 {
579 DE_ASSERT(storage < STORAGE_LAST);
580 DE_ASSERT(type < TYPE_LAST);
581 }
582
~VertexAttributeCase(void)583 VertexAttributeCase::~VertexAttributeCase(void)
584 {
585 deinit();
586 }
587
init(void)588 void VertexAttributeCase::init(void)
589 {
590 RenderCase::init();
591
592 // init gl resources
593 if (m_storage == STORAGE_BUFFER)
594 {
595 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
596
597 gl.genBuffers(1, &m_positionVboID);
598 gl.genBuffers(1, &m_attribVboID);
599 gl.genBuffers(1, &m_elementVboID);
600 }
601 }
602
deinit(void)603 void VertexAttributeCase::deinit(void)
604 {
605 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
606
607 RenderCase::deinit();
608
609 if (m_attribVboID)
610 {
611 gl.deleteBuffers(1, &m_attribVboID);
612 m_attribVboID = 0;
613 }
614
615 if (m_positionVboID)
616 {
617 gl.deleteBuffers(1, &m_positionVboID);
618 m_positionVboID = 0;
619 }
620
621 if (m_elementVboID)
622 {
623 gl.deleteBuffers(1, &m_elementVboID);
624 m_elementVboID = 0;
625 }
626 }
627
iterate(void)628 VertexAttributeCase::IterateResult VertexAttributeCase::iterate(void)
629 {
630 // Create a [s_specialFloats] X [s_specialFloats] grid of vertices with each vertex having 2 [s_specialFloats] values
631 // and calculate some basic operations with the floating point values. If all goes well, nothing special should happen
632
633 std::vector<tcu::Vec4> gridVertices(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
634 std::vector<tcu::UVec4> gridAttributes(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
635 std::vector<uint16_t> indices((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) *
636 (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6);
637 tcu::Surface resultImage(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
638
639 // vertices
640 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
641 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
642 {
643 const uint32_t one = 0x3F800000;
644 const float posX = (float)x / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f -
645 1.0f; // map from [0, len(s_specialFloats) - 1] to [-1, 1]
646 const float posY = (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f;
647
648 gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
649 gridAttributes[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] =
650 tcu::UVec4(s_specialFloats[x], s_specialFloats[y], one, one);
651 }
652
653 // tiles
654 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x)
655 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y)
656 {
657 const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6;
658
659 indices[baseNdx + 0] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
660 indices[baseNdx + 1] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
661 indices[baseNdx + 2] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
662
663 indices[baseNdx + 3] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
664 indices[baseNdx + 4] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
665 indices[baseNdx + 5] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
666 }
667
668 m_testCtx.getLog() << tcu::TestLog::Message
669 << "Drawing a grid with the shader. Setting a_attr for each vertex to (special, special, 1, 1)."
670 << tcu::TestLog::EndMessage;
671
672 // Draw grid
673 {
674 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
675 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos");
676 const GLint attribLoc = gl.getAttribLocation(m_program->getProgram(), "a_attr");
677
678 if (m_storage == STORAGE_BUFFER)
679 {
680 gl.bindBuffer(GL_ARRAY_BUFFER, m_positionVboID);
681 gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(gridVertices.size() * sizeof(tcu::Vec4)), &gridVertices[0],
682 GL_STATIC_DRAW);
683 GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
684
685 gl.bindBuffer(GL_ARRAY_BUFFER, m_attribVboID);
686 gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(gridAttributes.size() * sizeof(tcu::UVec4)),
687 &gridAttributes[0], GL_STATIC_DRAW);
688 GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
689
690 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementVboID);
691 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indices.size() * sizeof(uint16_t)), &indices[0],
692 GL_STATIC_DRAW);
693 GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
694 }
695
696 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
697 gl.clear(GL_COLOR_BUFFER_BIT);
698 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
699 gl.useProgram(m_program->getProgram());
700
701 if (m_storage == STORAGE_BUFFER)
702 {
703 gl.bindBuffer(GL_ARRAY_BUFFER, m_positionVboID);
704 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
705
706 gl.bindBuffer(GL_ARRAY_BUFFER, m_attribVboID);
707 gl.vertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
708
709 gl.enableVertexAttribArray(positionLoc);
710 gl.enableVertexAttribArray(attribLoc);
711 gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, DE_NULL);
712 gl.disableVertexAttribArray(positionLoc);
713 gl.disableVertexAttribArray(attribLoc);
714
715 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
716 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
717 }
718 else if (m_storage == STORAGE_CLIENT)
719 {
720 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
721 gl.vertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridAttributes[0]);
722
723 gl.enableVertexAttribArray(positionLoc);
724 gl.enableVertexAttribArray(attribLoc);
725 gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
726 gl.disableVertexAttribArray(positionLoc);
727 gl.disableVertexAttribArray(attribLoc);
728 }
729 else
730 DE_ASSERT(false);
731
732 gl.useProgram(0);
733 gl.finish();
734 GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
735
736 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
737 }
738
739 // verify everywhere was drawn (all pixels have Green = 255)
740 if (!checkResultImage(resultImage))
741 {
742 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
743 return STOP;
744 }
745
746 // test drawing still works
747 if (!drawTestPattern(false))
748 {
749 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
750 return STOP;
751 }
752
753 // all ok
754 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
755 return STOP;
756 }
757
genVertexSource(void) const758 std::string VertexAttributeCase::genVertexSource(void) const
759 {
760 if (m_type == TYPE_VERTEX)
761 return "attribute highp vec4 a_pos;\n"
762 "attribute highp vec4 a_attr;\n"
763 "varying mediump vec4 v_out;\n"
764 "void main ()\n"
765 "{\n"
766 " highp vec2 a1 = a_attr.xz + a_attr.yw; // add\n"
767 " highp vec2 a2 = a_attr.xz - a_attr.yw; // sub\n"
768 " highp vec2 a3 = a_attr.xz * a_attr.yw; // mul\n"
769 " highp vec2 a4 = a_attr.xz / a_attr.yw; // div\n"
770 " highp vec2 a5 = a_attr.xz + a_attr.yw * a_attr.xz; // fma\n"
771 "\n"
772 " highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
773 " v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
774 " gl_Position = a_pos;\n"
775 "}\n";
776 else
777 return s_attrPassthroughVertexShaderSource;
778 }
779
genFragmentSource(void) const780 std::string VertexAttributeCase::genFragmentSource(void) const
781 {
782 if (m_type == TYPE_VERTEX)
783 return s_colorPassthroughFragmentShaderSource;
784 else
785 return "varying mediump vec4 v_attr;\n"
786 "void main ()\n"
787 "{\n"
788 " mediump vec2 a1 = v_attr.xz + v_attr.yw; // add\n"
789 " mediump vec2 a2 = v_attr.xz - v_attr.yw; // sub\n"
790 " mediump vec2 a3 = v_attr.xz * v_attr.yw; // mul\n"
791 " mediump vec2 a4 = v_attr.xz / v_attr.yw; // div\n"
792 " mediump vec2 a5 = v_attr.xz + v_attr.yw * v_attr.xz; // fma\n"
793 "\n"
794 " const mediump float epsilon = 0.1; // allow small differences. To results to be wrong they must be "
795 "more wrong than that.\n"
796 " mediump float green = 1.0 + epsilon - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
797 " gl_FragColor = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
798 "}\n";
799 }
800
801 /*--------------------------------------------------------------------*//*!
802 * \brief Tests special floats as uniforms
803 *
804 * Tests that special floats transferred to the shader as uniforms do
805 * not change the results of normal floating point calculations. Special
806 * floats are put to 4-vector's x and y components and value 1.0 is put to
807 * z and w. The resulting fragment's green channel should be 1.0
808 * everywhere.
809 *
810 * After the calculation test a test pattern is drawn to detect possible
811 * floating point operation anomalies.
812 *//*--------------------------------------------------------------------*/
813 class UniformCase : public RenderCase
814 {
815 public:
816 enum ShaderType
817 {
818 TYPE_VERTEX = 0,
819 TYPE_FRAGMENT,
820 };
821
822 UniformCase(Context &context, const char *name, const char *desc, ShaderType type);
823 ~UniformCase(void);
824
825 void init(void);
826 void deinit(void);
827 IterateResult iterate(void);
828
829 private:
830 std::string genVertexSource(void) const;
831 std::string genFragmentSource(void) const;
832
833 const ShaderType m_type;
834 };
835
UniformCase(Context & context,const char * name,const char * desc,ShaderType type)836 UniformCase::UniformCase(Context &context, const char *name, const char *desc, ShaderType type)
837 : RenderCase(context, name, desc)
838 , m_type(type)
839 {
840 }
841
~UniformCase(void)842 UniformCase::~UniformCase(void)
843 {
844 deinit();
845 }
846
init(void)847 void UniformCase::init(void)
848 {
849 RenderCase::init();
850 }
851
deinit(void)852 void UniformCase::deinit(void)
853 {
854 RenderCase::deinit();
855 }
856
iterate(void)857 UniformCase::IterateResult UniformCase::iterate(void)
858 {
859 // Create a [s_specialFloats] X [s_specialFloats] grid of tile with each tile having 2 [s_specialFloats] values
860 // and calculate some basic operations with the floating point values. If all goes well, nothing special should happen
861
862 std::vector<tcu::Vec4> gridVertices((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) *
863 (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1));
864 std::vector<uint16_t> indices(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
865 tcu::Surface resultImage(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
866
867 // vertices
868 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x)
869 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y)
870 {
871 const float posX = (float)x / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f -
872 1.0f; // map from [0, len(s_specialFloats) ] to [-1, 1]
873 const float posY = (float)y / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f;
874
875 gridVertices[x * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
876 }
877
878 // tiles
879 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
880 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
881 {
882 const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats)) + y) * 6;
883
884 indices[baseNdx + 0] = (uint16_t)((x + 0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 0));
885 indices[baseNdx + 1] = (uint16_t)((x + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 1));
886 indices[baseNdx + 2] = (uint16_t)((x + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 0));
887
888 indices[baseNdx + 3] = (uint16_t)((x + 0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 0));
889 indices[baseNdx + 4] = (uint16_t)((x + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 1));
890 indices[baseNdx + 5] = (uint16_t)((x + 0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 1));
891 }
892
893 m_testCtx.getLog()
894 << tcu::TestLog::Message
895 << "Drawing a grid with the shader. Setting u_special for vertex each tile to (special, special, 1, 1)."
896 << tcu::TestLog::EndMessage;
897
898 // Draw grid
899 {
900 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
901 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos");
902 const GLint specialLoc = gl.getUniformLocation(m_program->getProgram(), "u_special");
903
904 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
905 gl.clear(GL_COLOR_BUFFER_BIT);
906 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
907 gl.useProgram(m_program->getProgram());
908
909 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
910 gl.enableVertexAttribArray(positionLoc);
911
912 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
913 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
914 {
915 const uint32_t one = 0x3F800000;
916 const tcu::UVec4 uniformValue = tcu::UVec4(s_specialFloats[x], s_specialFloats[y], one, one);
917 const int indexIndex = (x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y) * 6;
918
919 gl.uniform4fv(specialLoc, 1, (const float *)uniformValue.getPtr());
920 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
921 }
922
923 gl.disableVertexAttribArray(positionLoc);
924
925 gl.useProgram(0);
926 gl.finish();
927 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformCase::iterate");
928
929 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
930 }
931
932 // verify everywhere was drawn (all pixels have Green = 255)
933 if (!checkResultImage(resultImage))
934 {
935 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
936 return STOP;
937 }
938
939 // test drawing still works
940 if (!drawTestPattern(false))
941 {
942 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
943 return STOP;
944 }
945
946 // all ok
947 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
948 return STOP;
949 }
950
genVertexSource(void) const951 std::string UniformCase::genVertexSource(void) const
952 {
953 if (m_type == TYPE_VERTEX)
954 return "attribute highp vec4 a_pos;\n"
955 "uniform highp vec4 u_special;\n"
956 "varying mediump vec4 v_out;\n"
957 "void main ()\n"
958 "{\n"
959 " highp vec2 a1 = u_special.xz + u_special.yw; // add\n"
960 " highp vec2 a2 = u_special.xz - u_special.yw; // sub\n"
961 " highp vec2 a3 = u_special.xz * u_special.yw; // mul\n"
962 " highp vec2 a4 = u_special.xz / u_special.yw; // div\n"
963 " highp vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n"
964 "\n"
965 " highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
966 " v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
967 " gl_Position = a_pos;\n"
968 "}\n";
969 else
970 return "attribute highp vec4 a_pos;\n"
971 "void main ()\n"
972 "{\n"
973 " gl_Position = a_pos;\n"
974 "}\n";
975 }
976
genFragmentSource(void) const977 std::string UniformCase::genFragmentSource(void) const
978 {
979 if (m_type == TYPE_VERTEX)
980 return s_colorPassthroughFragmentShaderSource;
981 else
982 return "uniform mediump vec4 u_special;\n"
983 "void main ()\n"
984 "{\n"
985 " mediump vec2 a1 = u_special.xz + u_special.yw; // add\n"
986 " mediump vec2 a2 = u_special.xz - u_special.yw; // sub\n"
987 " mediump vec2 a3 = u_special.xz * u_special.yw; // mul\n"
988 " mediump vec2 a4 = u_special.xz / u_special.yw; // div\n"
989 " mediump vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n"
990 " mediump vec2 a6 = mod(u_special.xz, u_special.yw);\n"
991 " mediump vec2 a7 = mix(u_special.xz, u_special.yw, a6);\n"
992 "\n"
993 " mediump float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y + a6.y + a7.y) - 7.0);\n"
994 " gl_FragColor = vec4(a1.x*a3.x, green, a5.x*a4.x + a2.x*a7.x, 1.0);\n"
995 "}\n";
996 }
997
998 /*--------------------------------------------------------------------*//*!
999 * \brief Tests special floats as texture samping arguments
1000 *
1001 * Tests that special floats given as texture coordinates or LOD levels
1002 * to sampling functions do not return invalid values (values not in the
1003 * texture). Every texel's green component is 1.0.
1004 *
1005 * After the calculation test a test pattern is drawn to detect possible
1006 * texture sampling anomalies.
1007 *//*--------------------------------------------------------------------*/
1008 class TextureSamplerCase : public RenderCase
1009 {
1010 public:
1011 enum ShaderType
1012 {
1013 TYPE_VERTEX = 0,
1014 TYPE_FRAGMENT,
1015
1016 TYPE_LAST
1017 };
1018 enum TestType
1019 {
1020 TEST_TEX_COORD = 0,
1021 TEST_LOD,
1022 TEST_TEX_COORD_CUBE,
1023
1024 TEST_LAST
1025 };
1026
1027 TextureSamplerCase(Context &context, const char *name, const char *desc, ShaderType type, TestType testType);
1028 ~TextureSamplerCase(void);
1029
1030 void init(void);
1031 void deinit(void);
1032 IterateResult iterate(void);
1033
1034 private:
1035 std::string genVertexSource(void) const;
1036 std::string genFragmentSource(void) const;
1037
1038 const ShaderType m_type;
1039 const TestType m_testType;
1040 GLuint m_textureID;
1041 };
1042
TextureSamplerCase(Context & context,const char * name,const char * desc,ShaderType type,TestType testType)1043 TextureSamplerCase::TextureSamplerCase(Context &context, const char *name, const char *desc, ShaderType type,
1044 TestType testType)
1045 : RenderCase(context, name, desc)
1046 , m_type(type)
1047 , m_testType(testType)
1048 , m_textureID(0)
1049 {
1050 DE_ASSERT(type < TYPE_LAST);
1051 DE_ASSERT(testType < TEST_LAST);
1052 }
1053
~TextureSamplerCase(void)1054 TextureSamplerCase::~TextureSamplerCase(void)
1055 {
1056 deinit();
1057 }
1058
init(void)1059 void TextureSamplerCase::init(void)
1060 {
1061 // requirements
1062 {
1063 GLint maxTextureSize = 0;
1064 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1065 if (maxTextureSize < TEST_TEXTURE_SIZE)
1066 throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") +
1067 de::toString(TEST_TEXTURE_SIZE));
1068 }
1069
1070 // vertex shader supports textures?
1071 if (m_type == TYPE_VERTEX)
1072 {
1073 GLint maxVertexTexUnits = 0;
1074 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTexUnits);
1075 if (maxVertexTexUnits < 1)
1076 throw tcu::NotSupportedError("GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS must be at least 1");
1077 }
1078
1079 RenderCase::init();
1080
1081 // gen texture
1082 {
1083 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1084 std::vector<uint8_t> texData(TEST_TEXTURE_SIZE * TEST_TEXTURE_SIZE * 4);
1085 de::Random rnd(12345);
1086
1087 gl.genTextures(1, &m_textureID);
1088
1089 for (int x = 0; x < TEST_TEXTURE_SIZE; ++x)
1090 for (int y = 0; y < TEST_TEXTURE_SIZE; ++y)
1091 {
1092 // RGBA8, green and alpha channel are always 255 for verification
1093 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 0] = rnd.getUint32() & 0xFF;
1094 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 1] = 0xFF;
1095 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 2] = rnd.getUint32() & 0xFF;
1096 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 3] = 0xFF;
1097 }
1098
1099 if (m_testType == TEST_TEX_COORD)
1100 {
1101 m_testCtx.getLog() << tcu::TestLog::Message << "Creating a 2D texture with a test pattern."
1102 << tcu::TestLog::EndMessage;
1103
1104 gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1105 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1106 &texData[0]);
1107 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1108 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1109 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
1110 }
1111 else if (m_testType == TEST_LOD)
1112 {
1113 m_testCtx.getLog() << tcu::TestLog::Message << "Creating a mipmapped 2D texture with a test pattern."
1114 << tcu::TestLog::EndMessage;
1115
1116 gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1117
1118 for (int level = 0; (TEST_TEXTURE_SIZE >> level); ++level)
1119 gl.texImage2D(GL_TEXTURE_2D, level, GL_RGBA, TEST_TEXTURE_SIZE >> level, TEST_TEXTURE_SIZE >> level, 0,
1120 GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]);
1121
1122 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1123 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
1124 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
1125 }
1126 else if (m_testType == TEST_TEX_COORD_CUBE)
1127 {
1128 DE_STATIC_ASSERT(TEST_TEXTURE_CUBE_SIZE <= TEST_TEXTURE_SIZE);
1129
1130 static const GLenum faces[] = {
1131 GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
1132 GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
1133 };
1134
1135 m_testCtx.getLog() << tcu::TestLog::Message << "Creating a cube map with a test pattern."
1136 << tcu::TestLog::EndMessage;
1137
1138 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textureID);
1139
1140 for (int faceNdx = 0; faceNdx < DE_LENGTH_OF_ARRAY(faces); ++faceNdx)
1141 gl.texImage2D(faces[faceNdx], 0, GL_RGBA, TEST_TEXTURE_CUBE_SIZE, TEST_TEXTURE_CUBE_SIZE, 0, GL_RGBA,
1142 GL_UNSIGNED_BYTE, &texData[0]);
1143
1144 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1145 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1146 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
1147 }
1148 else
1149 DE_ASSERT(false);
1150 }
1151 }
1152
deinit(void)1153 void TextureSamplerCase::deinit(void)
1154 {
1155 RenderCase::deinit();
1156
1157 if (m_textureID)
1158 {
1159 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1160
1161 gl.deleteTextures(1, &m_textureID);
1162 m_textureID = 0;
1163 }
1164 }
1165
iterate(void)1166 TextureSamplerCase::IterateResult TextureSamplerCase::iterate(void)
1167 {
1168 // 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.
1169
1170 std::vector<tcu::Vec4> gridVertices(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
1171 std::vector<tcu::UVec2> gridTexCoords(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
1172 std::vector<uint16_t> indices((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) *
1173 (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6);
1174 tcu::Surface resultImage(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1175
1176 // vertices
1177 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
1178 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
1179 {
1180 const float posX = (float)x / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f -
1181 1.0f; // map from [0, len(s_specialFloats) - 1] to [-1, 1]
1182 const float posY = (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f;
1183
1184 gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1185 gridTexCoords[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] =
1186 tcu::UVec2(s_specialFloats[x], s_specialFloats[y]);
1187 }
1188
1189 // tiles
1190 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x)
1191 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y)
1192 {
1193 const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6;
1194
1195 indices[baseNdx + 0] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
1196 indices[baseNdx + 1] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
1197 indices[baseNdx + 2] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
1198
1199 indices[baseNdx + 3] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
1200 indices[baseNdx + 4] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
1201 indices[baseNdx + 5] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
1202 }
1203
1204 m_testCtx.getLog()
1205 << tcu::TestLog::Message
1206 << "Drawing a textured grid with the shader. Sampling from the texture using special floating point values."
1207 << tcu::TestLog::EndMessage;
1208
1209 // Draw grid
1210 {
1211 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1212 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos");
1213 const GLint texCoordLoc = gl.getAttribLocation(m_program->getProgram(), "a_attr");
1214 const GLint samplerLoc = gl.getUniformLocation(m_program->getProgram(), "u_sampler");
1215
1216 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1217 gl.clear(GL_COLOR_BUFFER_BIT);
1218 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1219 gl.useProgram(m_program->getProgram());
1220
1221 gl.uniform1i(samplerLoc, 0);
1222 if (m_testType != TEST_TEX_COORD_CUBE)
1223 gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1224 else
1225 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textureID);
1226
1227 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
1228 gl.vertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, &gridTexCoords[0]);
1229
1230 gl.enableVertexAttribArray(positionLoc);
1231 gl.enableVertexAttribArray(texCoordLoc);
1232 gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
1233 gl.disableVertexAttribArray(positionLoc);
1234 gl.disableVertexAttribArray(texCoordLoc);
1235
1236 gl.useProgram(0);
1237 gl.finish();
1238 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::iterate");
1239
1240 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
1241 }
1242
1243 // verify everywhere was drawn and samples were from the texture (all pixels have Green = 255)
1244 if (!checkResultImage(resultImage))
1245 {
1246 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
1247 return STOP;
1248 }
1249
1250 // test drawing and textures still works
1251 if (!drawTestPattern(true))
1252 {
1253 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
1254 return STOP;
1255 }
1256
1257 // all ok
1258 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1259 return STOP;
1260 }
1261
genVertexSource(void) const1262 std::string TextureSamplerCase::genVertexSource(void) const
1263 {
1264 // vertex shader is passthrough, fragment does the calculations
1265 if (m_type == TYPE_FRAGMENT)
1266 return s_attrPassthroughVertexShaderSource;
1267
1268 // vertex shader does the calculations
1269 std::ostringstream buf;
1270 buf << "attribute highp vec4 a_pos;\n"
1271 "attribute highp vec2 a_attr;\n";
1272
1273 if (m_testType != TEST_TEX_COORD_CUBE)
1274 buf << "uniform highp sampler2D u_sampler;\n";
1275 else
1276 buf << "uniform highp samplerCube u_sampler;\n";
1277
1278 buf << "varying mediump vec4 v_out;\n"
1279 "void main ()\n"
1280 "{\n";
1281
1282 if (m_testType == TEST_TEX_COORD)
1283 buf << " v_out = texture2DLod(u_sampler, a_attr, 0.0);\n";
1284 else if (m_testType == TEST_LOD)
1285 buf << " v_out = texture2DLod(u_sampler, a_attr, a_attr.x);\n";
1286 else if (m_testType == TEST_TEX_COORD_CUBE)
1287 buf << " v_out = textureCubeLod(u_sampler, vec3(a_attr, a_attr.x+a_attr.y), 0.0);\n";
1288 else
1289 DE_ASSERT(false);
1290
1291 buf << "\n"
1292 " gl_Position = a_pos;\n"
1293 "}\n";
1294
1295 return buf.str();
1296 }
1297
genFragmentSource(void) const1298 std::string TextureSamplerCase::genFragmentSource(void) const
1299 {
1300 // fragment shader is passthrough
1301 if (m_type == TYPE_VERTEX)
1302 return s_colorPassthroughFragmentShaderSource;
1303
1304 // fragment shader does the calculations
1305 std::ostringstream buf;
1306 if (m_testType != TEST_TEX_COORD_CUBE)
1307 buf << "uniform mediump sampler2D u_sampler;\n";
1308 else
1309 buf << "uniform mediump samplerCube u_sampler;\n";
1310
1311 buf << "varying mediump vec4 v_attr;\n"
1312 "void main ()\n"
1313 "{\n";
1314
1315 if (m_testType == TEST_TEX_COORD)
1316 buf << " gl_FragColor = texture2D(u_sampler, v_attr.xy);\n";
1317 else if (m_testType == TEST_LOD)
1318 buf << " gl_FragColor = texture2D(u_sampler, v_attr.xy, v_attr.x);\n";
1319 else if (m_testType == TEST_TEX_COORD_CUBE)
1320 buf << " gl_FragColor = textureCube(u_sampler, vec3(v_attr.xy, v_attr.x + v_attr.y));\n";
1321 else
1322 DE_ASSERT(false);
1323
1324 buf << "}\n";
1325
1326 return buf.str();
1327 }
1328
1329 /*--------------------------------------------------------------------*//*!
1330 * \brief Tests special floats as fragment shader outputs
1331 *
1332 * Tests that outputting special floats from a fragment shader does not change
1333 * the normal floating point values of outputted from a fragment shader. Special
1334 * floats are outputted in the green component, normal floating point values
1335 * in the red and blue component. Potential changes are tested by rendering
1336 * test pattern two times with different floating point values. The resulting
1337 * images' red and blue channels should be equal.
1338 *//*--------------------------------------------------------------------*/
1339 class OutputCase : public FramebufferRenderCase
1340 {
1341 public:
1342 OutputCase(Context &context, const char *name, const char *desc, FramebufferRenderCase::FrameBufferType type);
1343 ~OutputCase(void);
1344
1345 void testFBO(void);
1346
1347 private:
1348 std::string genVertexSource(void) const;
1349 std::string genFragmentSource(void) const;
1350 };
1351
OutputCase(Context & context,const char * name,const char * desc,FramebufferRenderCase::FrameBufferType type)1352 OutputCase::OutputCase(Context &context, const char *name, const char *desc,
1353 FramebufferRenderCase::FrameBufferType type)
1354 : FramebufferRenderCase(context, name, desc, type)
1355 {
1356 }
1357
~OutputCase(void)1358 OutputCase::~OutputCase(void)
1359 {
1360 deinit();
1361 }
1362
testFBO(void)1363 void OutputCase::testFBO(void)
1364 {
1365 // Create a 1 X [s_specialFloats] grid of tiles (stripes).
1366 std::vector<tcu::Vec4> gridVertices((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) * 2);
1367 std::vector<uint16_t> indices(DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
1368 tcu::TextureFormat textureFormat(tcu::TextureFormat::RGBA, (m_fboType == FBO_RGBA_FLOAT16) ?
1369 (tcu::TextureFormat::FLOAT) :
1370 (tcu::TextureFormat::UNORM_INT8));
1371 tcu::TextureLevel specialImage(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1372 tcu::TextureLevel normalImage(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1373
1374 // vertices
1375 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y)
1376 {
1377 const float posY = (float)y / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f -
1378 1.0f; // map from [0, len(s_specialFloats) ] to [-1, 1]
1379
1380 gridVertices[y * 2 + 0] = tcu::Vec4(-1.0, posY, 0.0f, 1.0f);
1381 gridVertices[y * 2 + 1] = tcu::Vec4(1.0, posY, 0.0f, 1.0f);
1382 }
1383
1384 // tiles
1385 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
1386 {
1387 const int baseNdx = y * 6;
1388
1389 indices[baseNdx + 0] = (uint16_t)((y + 0) * 2);
1390 indices[baseNdx + 1] = (uint16_t)((y + 1) * 2);
1391 indices[baseNdx + 2] = (uint16_t)((y + 1) * 2 + 1);
1392
1393 indices[baseNdx + 3] = (uint16_t)((y + 0) * 2);
1394 indices[baseNdx + 4] = (uint16_t)((y + 1) * 2 + 1);
1395 indices[baseNdx + 5] = (uint16_t)((y + 0) * 2 + 1);
1396 }
1397
1398 // Draw grids
1399 {
1400 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1401 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos");
1402 const GLint specialLoc = gl.getUniformLocation(m_program->getProgram(), "u_special");
1403
1404 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1405 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1406 gl.useProgram(m_program->getProgram());
1407 GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw");
1408
1409 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
1410 gl.enableVertexAttribArray(positionLoc);
1411
1412 // draw 2 passes. Special and normal.
1413 for (int passNdx = 0; passNdx < 2; ++passNdx)
1414 {
1415 const bool specialPass = (passNdx == 0);
1416
1417 m_testCtx.getLog() << tcu::TestLog::Message << "Pass " << passNdx
1418 << ": Drawing stripes with the shader. Setting u_special for each stripe to ("
1419 << ((specialPass) ? ("special") : ("1.0")) << ")." << tcu::TestLog::EndMessage;
1420
1421 // draw stripes
1422 gl.clear(GL_COLOR_BUFFER_BIT);
1423 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
1424 {
1425 const uint32_t one = 0x3F800000;
1426 const uint32_t special = s_specialFloats[y];
1427 const uint32_t uniformValue = (specialPass) ? (special) : (one);
1428 const int indexIndex = y * 6;
1429
1430 gl.uniform1fv(specialLoc, 1, (const float *)&uniformValue);
1431 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
1432 }
1433
1434 gl.finish();
1435 glu::readPixels(m_context.getRenderContext(), 0, 0,
1436 ((specialPass) ? (specialImage) : (normalImage)).getAccess());
1437 }
1438
1439 gl.disableVertexAttribArray(positionLoc);
1440 gl.useProgram(0);
1441 GLU_EXPECT_NO_ERROR(gl.getError(), "OutputCase::iterate");
1442 }
1443
1444 // Check results
1445 {
1446 tcu::Surface errorMask(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1447 const tcu::RGBA badPixelColor = tcu::RGBA::red();
1448 const tcu::RGBA okPixelColor = tcu::RGBA::green();
1449 int badPixels = 0;
1450
1451 m_testCtx.getLog() << tcu::TestLog::Message
1452 << "Checking passes have identical red and blue channels and the green channel is correct "
1453 "in the constant pass."
1454 << tcu::TestLog::EndMessage;
1455
1456 for (int y = 0; y < specialImage.getHeight(); ++y)
1457 for (int x = 0; x < specialImage.getWidth(); ++x)
1458 {
1459 const float greenThreshold = 0.1f;
1460 const tcu::Vec4 cNormal = normalImage.getAccess().getPixel(x, y);
1461 const tcu::Vec4 cSpecial = specialImage.getAccess().getPixel(x, y);
1462
1463 if (cNormal.x() != cSpecial.x() || cNormal.z() != cSpecial.z() || cNormal.y() < 1.0f - greenThreshold)
1464 {
1465 ++badPixels;
1466 errorMask.setPixel(x, y, badPixelColor);
1467 }
1468 else
1469 errorMask.setPixel(x, y, okPixelColor);
1470 }
1471
1472 m_testCtx.getLog() << tcu::TestLog::Message << "Found " << badPixels << " invalid pixel(s)."
1473 << tcu::TestLog::EndMessage;
1474
1475 if (badPixels)
1476 {
1477 m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
1478 << tcu::TestLog::Image("Image with special green channel",
1479 "Image with special green channel", specialImage)
1480 << tcu::TestLog::Image("Image with constant green channel",
1481 "Image with constant green channel", normalImage)
1482 << tcu::TestLog::Image("Error Mask", "Error Mask", errorMask)
1483 << tcu::TestLog::EndImageSet;
1484
1485 // all ok?
1486 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1487 }
1488 else
1489 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1490 }
1491 }
1492
genVertexSource(void) const1493 std::string OutputCase::genVertexSource(void) const
1494 {
1495 return "attribute highp vec4 a_pos;\n"
1496 "varying mediump vec2 v_pos;\n"
1497 "void main ()\n"
1498 "{\n"
1499 " gl_Position = a_pos;\n"
1500 " v_pos = a_pos.xy;\n"
1501 "}\n";
1502 }
1503
genFragmentSource(void) const1504 std::string OutputCase::genFragmentSource(void) const
1505 {
1506 return "uniform mediump float u_special;\n"
1507 "varying mediump vec2 v_pos;\n"
1508 "void main ()\n"
1509 "{\n"
1510 " gl_FragColor = vec4((v_pos.x + 1.0) * 0.5, u_special, (v_pos.y + 1.0) * 0.5, 1.0);\n"
1511 "}\n";
1512 }
1513
1514 /*--------------------------------------------------------------------*//*!
1515 * \brief Tests special floats in blending
1516 *
1517 * Tests special floats as alpha and color components with various blending
1518 * modes. Test draws a test pattern and then does various blend operations
1519 * with special float values. After the blending test another test pattern
1520 * is drawn to detect possible blending anomalies. Test patterns should be
1521 * identical.
1522 *//*--------------------------------------------------------------------*/
1523 class BlendingCase : public FramebufferRenderCase
1524 {
1525 public:
1526 BlendingCase(Context &context, const char *name, const char *desc, FramebufferRenderCase::FrameBufferType type);
1527 ~BlendingCase(void);
1528
1529 void testFBO(void);
1530
1531 private:
1532 void drawTestImage(tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex);
1533
1534 std::string genVertexSource(void) const;
1535 std::string genFragmentSource(void) const;
1536 };
1537
BlendingCase(Context & context,const char * name,const char * desc,FramebufferRenderCase::FrameBufferType type)1538 BlendingCase::BlendingCase(Context &context, const char *name, const char *desc,
1539 FramebufferRenderCase::FrameBufferType type)
1540 : FramebufferRenderCase(context, name, desc, type)
1541 {
1542 }
1543
~BlendingCase(void)1544 BlendingCase::~BlendingCase(void)
1545 {
1546 deinit();
1547 }
1548
testFBO(void)1549 void BlendingCase::testFBO(void)
1550 {
1551 static const GLenum equations[] = {
1552 GL_FUNC_ADD,
1553 GL_FUNC_SUBTRACT,
1554 GL_FUNC_REVERSE_SUBTRACT,
1555 };
1556 static const GLenum functions[] = {
1557 GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1558 };
1559
1560 // Create a [BlendFuncs] X [s_specialFloats] grid of tiles. ( BlendFuncs = equations x functions )
1561
1562 const int numBlendFuncs = DE_LENGTH_OF_ARRAY(equations) * DE_LENGTH_OF_ARRAY(functions);
1563 std::vector<tcu::Vec4> gridVertices((numBlendFuncs + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1));
1564 std::vector<uint16_t> indices(numBlendFuncs * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
1565 tcu::TextureFormat textureFormat(tcu::TextureFormat::RGBA, (m_fboType == FBO_RGBA_FLOAT16) ?
1566 (tcu::TextureFormat::FLOAT) :
1567 (tcu::TextureFormat::UNORM_INT8));
1568 tcu::TextureLevel beforeImage(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1569 tcu::TextureLevel afterImage(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1570
1571 // vertices
1572 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x)
1573 for (int y = 0; y < numBlendFuncs + 1; ++y)
1574 {
1575 const float posX = (float)x / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f -
1576 1.0f; // map from [0, len(s_specialFloats)] to [-1, 1]
1577 const float posY = (float)y / (float)numBlendFuncs * 2.0f - 1.0f;
1578
1579 gridVertices[x * (numBlendFuncs + 1) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1580 }
1581
1582 // tiles
1583 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
1584 for (int y = 0; y < numBlendFuncs; ++y)
1585 {
1586 const int baseNdx = (x * numBlendFuncs + y) * 6;
1587
1588 indices[baseNdx + 0] = (uint16_t)((x + 0) * (numBlendFuncs + 1) + (y + 0));
1589 indices[baseNdx + 1] = (uint16_t)((x + 1) * (numBlendFuncs + 1) + (y + 1));
1590 indices[baseNdx + 2] = (uint16_t)((x + 1) * (numBlendFuncs + 1) + (y + 0));
1591
1592 indices[baseNdx + 3] = (uint16_t)((x + 0) * (numBlendFuncs + 1) + (y + 0));
1593 indices[baseNdx + 4] = (uint16_t)((x + 1) * (numBlendFuncs + 1) + (y + 1));
1594 indices[baseNdx + 5] = (uint16_t)((x + 0) * (numBlendFuncs + 1) + (y + 1));
1595 }
1596
1597 // Draw tiles
1598 {
1599 const int numPasses = 5;
1600 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1601 const GLint positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_pos");
1602 const GLint specialLoc = gl.getUniformLocation(m_program->getProgram(), "u_special");
1603
1604 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1605 gl.clear(GL_COLOR_BUFFER_BIT);
1606 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1607 gl.useProgram(m_program->getProgram());
1608 gl.enable(GL_BLEND);
1609 GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw");
1610
1611 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
1612 gl.enableVertexAttribArray(positionLoc);
1613
1614 // draw "before" image
1615 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing pre-draw pattern." << tcu::TestLog::EndMessage;
1616 drawTestImage(beforeImage.getAccess(), specialLoc, (int)gridVertices.size() - 1);
1617 GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw pattern");
1618
1619 // draw multiple passes with special floats
1620 gl.clear(GL_COLOR_BUFFER_BIT);
1621 for (int passNdx = 0; passNdx < numPasses; ++passNdx)
1622 {
1623 de::Random rnd(123 + 567 * passNdx);
1624
1625 m_testCtx.getLog() << tcu::TestLog::Message << "Pass " << passNdx << ": Drawing tiles with the shader.\n"
1626 << "\tVarying u_special for each tile.\n"
1627 << "\tVarying blend function and blend equation for each tile.\n"
1628 << tcu::TestLog::EndMessage;
1629
1630 // draw tiles
1631 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
1632 for (int y = 0; y < numBlendFuncs; ++y)
1633 {
1634 const GLenum blendEquation = equations[y % DE_LENGTH_OF_ARRAY(equations)];
1635 const GLenum blendFunction = functions[y / DE_LENGTH_OF_ARRAY(equations)];
1636 const GLenum blendFunctionDst =
1637 rnd.choose<GLenum>(DE_ARRAY_BEGIN(functions), DE_ARRAY_END(functions));
1638 const int indexIndex = (x * numBlendFuncs + y) * 6;
1639
1640 // "rnd.get"s are run in a deterministic order
1641 const uint32_t componentR =
1642 rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
1643 const uint32_t componentG =
1644 rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
1645 const uint32_t componentB =
1646 rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
1647 const uint32_t componentA =
1648 rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
1649 const tcu::UVec4 uniformValue = tcu::UVec4(componentR, componentG, componentB, componentA);
1650
1651 gl.uniform4fv(specialLoc, 1, (const float *)uniformValue.getPtr());
1652 gl.blendEquation(blendEquation);
1653 gl.blendFunc(blendFunction, blendFunctionDst);
1654 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
1655 }
1656 }
1657 GLU_EXPECT_NO_ERROR(gl.getError(), "special passes");
1658
1659 // draw "after" image
1660 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing post-draw pattern." << tcu::TestLog::EndMessage;
1661 drawTestImage(afterImage.getAccess(), specialLoc, (int)gridVertices.size() - 1);
1662 GLU_EXPECT_NO_ERROR(gl.getError(), "post-draw pattern");
1663
1664 gl.disableVertexAttribArray(positionLoc);
1665 gl.useProgram(0);
1666 GLU_EXPECT_NO_ERROR(gl.getError(), "OutputCase::iterate");
1667 }
1668
1669 // Check results
1670 {
1671 tcu::Surface errorMask(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1672 const tcu::RGBA badPixelColor = tcu::RGBA::red();
1673 const tcu::RGBA okPixelColor = tcu::RGBA::green();
1674 int badPixels = 0;
1675
1676 m_testCtx.getLog() << tcu::TestLog::Message << "Checking patterns are identical." << tcu::TestLog::EndMessage;
1677
1678 for (int y = 0; y < beforeImage.getHeight(); ++y)
1679 for (int x = 0; x < beforeImage.getWidth(); ++x)
1680 {
1681 const tcu::Vec4 cBefore = beforeImage.getAccess().getPixel(x, y);
1682 const tcu::Vec4 cAfter = afterImage.getAccess().getPixel(x, y);
1683
1684 if (cBefore != cAfter)
1685 {
1686 ++badPixels;
1687 errorMask.setPixel(x, y, badPixelColor);
1688 }
1689 else
1690 errorMask.setPixel(x, y, okPixelColor);
1691 }
1692
1693 m_testCtx.getLog() << tcu::TestLog::Message << "Found " << badPixels << " invalid pixel(s)."
1694 << tcu::TestLog::EndMessage;
1695
1696 if (badPixels)
1697 {
1698 m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
1699 << tcu::TestLog::Image("Pattern drawn before special float blending",
1700 "Pattern drawn before special float blending", beforeImage)
1701 << tcu::TestLog::Image("Pattern drawn after special float blending",
1702 "Pattern drawn after special float blending", afterImage)
1703 << tcu::TestLog::EndImageSet;
1704
1705 // all ok?
1706 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1707 }
1708 else
1709 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1710 }
1711 }
1712
drawTestImage(tcu::PixelBufferAccess dst,GLuint uColorLoc,int maxVertexIndex)1713 void BlendingCase::drawTestImage(tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex)
1714 {
1715 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1716 de::Random rnd(123);
1717
1718 gl.clear(GL_COLOR_BUFFER_BIT);
1719 gl.blendEquation(GL_FUNC_ADD);
1720 gl.blendFunc(GL_ONE, GL_ONE);
1721
1722 for (int tri = 0; tri < 20; ++tri)
1723 {
1724 tcu::Vec4 color;
1725 color.x() = rnd.getFloat();
1726 color.y() = rnd.getFloat();
1727 color.z() = rnd.getFloat();
1728 color.w() = rnd.getFloat();
1729 gl.uniform4fv(uColorLoc, 1, color.getPtr());
1730
1731 uint16_t indices[3];
1732 indices[0] = (uint16_t)rnd.getInt(0, maxVertexIndex);
1733 indices[1] = (uint16_t)rnd.getInt(0, maxVertexIndex);
1734 indices[2] = (uint16_t)rnd.getInt(0, maxVertexIndex);
1735
1736 gl.drawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, indices);
1737 }
1738
1739 gl.finish();
1740 glu::readPixels(m_context.getRenderContext(), 0, 0, dst);
1741 }
1742
genVertexSource(void) const1743 std::string BlendingCase::genVertexSource(void) const
1744 {
1745 return "attribute highp vec4 a_pos;\n"
1746 "void main ()\n"
1747 "{\n"
1748 " gl_Position = a_pos;\n"
1749 "}\n";
1750 }
1751
genFragmentSource(void) const1752 std::string BlendingCase::genFragmentSource(void) const
1753 {
1754 return "uniform mediump vec4 u_special;\n"
1755 "void main ()\n"
1756 "{\n"
1757 " gl_FragColor = u_special;\n"
1758 "}\n";
1759 }
1760
1761 } // namespace
1762
SpecialFloatTests(Context & context)1763 SpecialFloatTests::SpecialFloatTests(Context &context) : TestCaseGroup(context, "special_float", "Special float tests")
1764 {
1765 }
1766
~SpecialFloatTests(void)1767 SpecialFloatTests::~SpecialFloatTests(void)
1768 {
1769 }
1770
init(void)1771 void SpecialFloatTests::init(void)
1772 {
1773 tcu::TestCaseGroup *const vertexGroup =
1774 new tcu::TestCaseGroup(m_testCtx, "vertex", "Run vertex shader with special float values");
1775 tcu::TestCaseGroup *const fragmentGroup =
1776 new tcu::TestCaseGroup(m_testCtx, "fragment", "Run fragment shader with special float values");
1777 tcu::TestCaseGroup *const framebufferGroup =
1778 new tcu::TestCaseGroup(m_testCtx, "framebuffer", "Test framebuffers containing special float values");
1779
1780 // .vertex
1781 {
1782 vertexGroup->addChild(
1783 new VertexAttributeCase(m_context, "attribute_buffer", "special attribute values in a buffer",
1784 VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_VERTEX));
1785 vertexGroup->addChild(
1786 new VertexAttributeCase(m_context, "attribute_client", "special attribute values in a client storage",
1787 VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_VERTEX));
1788 vertexGroup->addChild(
1789 new UniformCase(m_context, "uniform", "special uniform values", UniformCase::TYPE_VERTEX));
1790 vertexGroup->addChild(new TextureSamplerCase(m_context, "sampler_tex_coord", "special texture coords",
1791 TextureSamplerCase::TYPE_VERTEX,
1792 TextureSamplerCase::TEST_TEX_COORD));
1793 vertexGroup->addChild(
1794 new TextureSamplerCase(m_context, "sampler_tex_coord_cube", "special texture coords to cubemap",
1795 TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_TEX_COORD_CUBE));
1796 vertexGroup->addChild(new TextureSamplerCase(m_context, "sampler_lod", "special texture lod",
1797 TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_LOD));
1798
1799 addChild(vertexGroup);
1800 }
1801
1802 // .fragment
1803 {
1804 fragmentGroup->addChild(
1805 new VertexAttributeCase(m_context, "attribute_buffer", "special attribute values in a buffer",
1806 VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_FRAGMENT));
1807 fragmentGroup->addChild(
1808 new VertexAttributeCase(m_context, "attribute_client", "special attribute values in a client storage",
1809 VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_FRAGMENT));
1810 fragmentGroup->addChild(
1811 new UniformCase(m_context, "uniform", "special uniform values", UniformCase::TYPE_FRAGMENT));
1812 fragmentGroup->addChild(new TextureSamplerCase(m_context, "sampler_tex_coord", "special texture coords",
1813 TextureSamplerCase::TYPE_FRAGMENT,
1814 TextureSamplerCase::TEST_TEX_COORD));
1815 fragmentGroup->addChild(
1816 new TextureSamplerCase(m_context, "sampler_tex_coord_cube", "special texture coords to cubemap",
1817 TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_TEX_COORD_CUBE));
1818 fragmentGroup->addChild(new TextureSamplerCase(m_context, "sampler_lod", "special texture lod",
1819 TextureSamplerCase::TYPE_FRAGMENT,
1820 TextureSamplerCase::TEST_LOD));
1821
1822 addChild(fragmentGroup);
1823 }
1824
1825 // .framebuffer
1826 {
1827 framebufferGroup->addChild(new OutputCase(m_context, "write_default",
1828 "write special floating point values to default framebuffer",
1829 FramebufferRenderCase::FBO_DEFAULT));
1830 framebufferGroup->addChild(new OutputCase(m_context, "write_rgba",
1831 "write special floating point values to RGBA framebuffer",
1832 FramebufferRenderCase::FBO_RGBA));
1833 framebufferGroup->addChild(new OutputCase(m_context, "write_rgba4",
1834 "write special floating point values to RGBA4 framebuffer",
1835 FramebufferRenderCase::FBO_RGBA4));
1836 framebufferGroup->addChild(new OutputCase(m_context, "write_rgb5_a1",
1837 "write special floating point values to RGB5_A1 framebuffer",
1838 FramebufferRenderCase::FBO_RGB5_A1));
1839 framebufferGroup->addChild(new OutputCase(m_context, "write_rgb565",
1840 "write special floating point values to RGB565 framebuffer",
1841 FramebufferRenderCase::FBO_RGB565));
1842 framebufferGroup->addChild(new OutputCase(m_context, "write_float16",
1843 "write special floating point values to float16 framebuffer",
1844 FramebufferRenderCase::FBO_RGBA_FLOAT16));
1845
1846 framebufferGroup->addChild(new BlendingCase(m_context, "blend_default",
1847 "blend special floating point values in a default framebuffer",
1848 FramebufferRenderCase::FBO_DEFAULT));
1849 framebufferGroup->addChild(new BlendingCase(m_context, "blend_rgba",
1850 "blend special floating point values in a RGBA framebuffer",
1851 FramebufferRenderCase::FBO_RGBA));
1852 framebufferGroup->addChild(new BlendingCase(m_context, "blend_float16",
1853 "blend special floating point values in a float16 framebuffer",
1854 FramebufferRenderCase::FBO_RGBA_FLOAT16));
1855
1856 addChild(framebufferGroup);
1857 }
1858 }
1859
1860 } // namespace Stress
1861 } // namespace gles2
1862 } // namespace deqp
1863