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