xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fDefaultVertexAttributeTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Default vertex attribute test
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3fDefaultVertexAttributeTests.hpp"
25 #include "tcuVector.hpp"
26 #include "tcuRenderTarget.hpp"
27 #include "tcuSurface.hpp"
28 #include "tcuTextureUtil.hpp"
29 #include "gluRenderContext.hpp"
30 #include "gluCallLogWrapper.hpp"
31 #include "gluShaderProgram.hpp"
32 #include "gluObjectWrapper.hpp"
33 #include "gluPixelTransfer.hpp"
34 #include "glwEnums.hpp"
35 #include "glwFunctions.hpp"
36 #include "deMath.h"
37 #include "deStringUtil.hpp"
38 #include "deString.h"
39 
40 #include <limits>
41 
42 namespace deqp
43 {
44 namespace gles3
45 {
46 namespace Functional
47 {
48 namespace
49 {
50 
51 static const int s_valueRange = 10;
52 
53 static const char *const s_passThroughFragmentShaderSource = "#version 300 es\n"
54                                                              "layout(location = 0) out mediump vec4 fragColor;\n"
55                                                              "in mediump vec4 v_color;\n"
56                                                              "void main (void)\n"
57                                                              "{\n"
58                                                              "    fragColor = v_color;\n"
59                                                              "}\n";
60 
61 template <typename T1, int S1, typename T2, int S2>
convertToTypeVec(const tcu::Vector<T2,S2> & v)62 tcu::Vector<T1, S1> convertToTypeVec(const tcu::Vector<T2, S2> &v)
63 {
64     tcu::Vector<T1, S1> retVal;
65 
66     for (int ndx = 0; ndx < S1; ++ndx)
67         retVal[ndx] = T1(0);
68 
69     if (S1 == 4)
70         retVal[3] = T1(1);
71 
72     for (int ndx = 0; ndx < de::min(S1, S2); ++ndx)
73         retVal[ndx] = T1(v[ndx]);
74 
75     return retVal;
76 }
77 
78 class FloatLoader
79 {
80 public:
~FloatLoader(void)81     virtual ~FloatLoader(void)
82     {
83     }
84 
85     // returns the value loaded
86     virtual tcu::Vec4 load(glu::CallLogWrapper &gl, int index, const tcu::Vec4 &v) const = 0;
87 };
88 
89 #define GEN_DIRECT_FLOAT_LOADER(TYPE, COMPS, TYPECODE, CASENAME, VALUES)             \
90     class LoaderVertexAttrib##COMPS##TYPECODE : public FloatLoader                   \
91     {                                                                                \
92     public:                                                                          \
93         enum                                                                         \
94         {                                                                            \
95             NORMALIZING = 0,                                                         \
96         };                                                                           \
97         enum                                                                         \
98         {                                                                            \
99             COMPONENTS = (COMPS)                                                     \
100         };                                                                           \
101         typedef TYPE Type;                                                           \
102                                                                                      \
103         tcu::Vec4 load(glu::CallLogWrapper &gl, int index, const tcu::Vec4 &v) const \
104         {                                                                            \
105             tcu::Vector<TYPE, COMPONENTS> value;                                     \
106             value = convertToTypeVec<Type, COMPONENTS>(v);                           \
107                                                                                      \
108             gl.glVertexAttrib##COMPS##TYPECODE VALUES;                               \
109             return convertToTypeVec<float, 4>(value);                                \
110         }                                                                            \
111                                                                                      \
112         static const char *getCaseName(void)                                         \
113         {                                                                            \
114             return CASENAME;                                                         \
115         }                                                                            \
116                                                                                      \
117         static const char *getName(void)                                             \
118         {                                                                            \
119             return "VertexAttrib" #COMPS #TYPECODE;                                  \
120         }                                                                            \
121     }
122 
123 #define GEN_INDIRECT_FLOAT_LOADER(TYPE, COMPS, TYPECODE, CASENAME)                   \
124     class LoaderVertexAttrib##COMPS##TYPECODE : public FloatLoader                   \
125     {                                                                                \
126     public:                                                                          \
127         enum                                                                         \
128         {                                                                            \
129             NORMALIZING = 0,                                                         \
130         };                                                                           \
131         enum                                                                         \
132         {                                                                            \
133             COMPONENTS = (COMPS)                                                     \
134         };                                                                           \
135         typedef TYPE Type;                                                           \
136                                                                                      \
137         tcu::Vec4 load(glu::CallLogWrapper &gl, int index, const tcu::Vec4 &v) const \
138         {                                                                            \
139             tcu::Vector<TYPE, COMPONENTS> value;                                     \
140             value = convertToTypeVec<Type, COMPONENTS>(v);                           \
141                                                                                      \
142             gl.glVertexAttrib##COMPS##TYPECODE(index, value.getPtr());               \
143             return convertToTypeVec<float, 4>(value);                                \
144         }                                                                            \
145                                                                                      \
146         static const char *getCaseName(void)                                         \
147         {                                                                            \
148             return CASENAME;                                                         \
149         }                                                                            \
150                                                                                      \
151         static const char *getName(void)                                             \
152         {                                                                            \
153             return "VertexAttrib" #COMPS #TYPECODE;                                  \
154         }                                                                            \
155     }
156 
157 #define GEN_DIRECT_INTEGER_LOADER(TYPE, COMPS, TYPECODE, CASENAME, VALUES)           \
158     class LoaderVertexAttribI##COMPS##TYPECODE : public FloatLoader                  \
159     {                                                                                \
160     public:                                                                          \
161         enum                                                                         \
162         {                                                                            \
163             NORMALIZING = 0,                                                         \
164         };                                                                           \
165         enum                                                                         \
166         {                                                                            \
167             COMPONENTS = (COMPS)                                                     \
168         };                                                                           \
169         typedef TYPE Type;                                                           \
170                                                                                      \
171         tcu::Vec4 load(glu::CallLogWrapper &gl, int index, const tcu::Vec4 &v) const \
172         {                                                                            \
173             tcu::Vector<TYPE, COMPONENTS> value;                                     \
174             value = convertToTypeVec<Type, COMPONENTS>(v);                           \
175                                                                                      \
176             gl.glVertexAttribI##COMPS##TYPECODE VALUES;                              \
177             return convertToTypeVec<float, 4>(value);                                \
178         }                                                                            \
179                                                                                      \
180         static const char *getCaseName(void)                                         \
181         {                                                                            \
182             return CASENAME;                                                         \
183         }                                                                            \
184                                                                                      \
185         static const char *getName(void)                                             \
186         {                                                                            \
187             return "VertexAttrib" #COMPS #TYPECODE;                                  \
188         }                                                                            \
189     }
190 
191 #define GEN_INDIRECT_INTEGER_LOADER(TYPE, COMPS, TYPECODE, CASENAME)                 \
192     class LoaderVertexAttribI##COMPS##TYPECODE : public FloatLoader                  \
193     {                                                                                \
194     public:                                                                          \
195         enum                                                                         \
196         {                                                                            \
197             NORMALIZING = 0,                                                         \
198         };                                                                           \
199         enum                                                                         \
200         {                                                                            \
201             COMPONENTS = (COMPS)                                                     \
202         };                                                                           \
203         typedef TYPE Type;                                                           \
204                                                                                      \
205         tcu::Vec4 load(glu::CallLogWrapper &gl, int index, const tcu::Vec4 &v) const \
206         {                                                                            \
207             tcu::Vector<TYPE, COMPONENTS> value;                                     \
208             value = convertToTypeVec<Type, COMPONENTS>(v);                           \
209                                                                                      \
210             gl.glVertexAttribI##COMPS##TYPECODE(index, value.getPtr());              \
211             return convertToTypeVec<float, 4>(value);                                \
212         }                                                                            \
213                                                                                      \
214         static const char *getCaseName(void)                                         \
215         {                                                                            \
216             return CASENAME;                                                         \
217         }                                                                            \
218                                                                                      \
219         static const char *getName(void)                                             \
220         {                                                                            \
221             return "VertexAttrib" #COMPS #TYPECODE;                                  \
222         }                                                                            \
223     }
224 
225 GEN_DIRECT_FLOAT_LOADER(float, 1, f, "vertex_attrib_1f", (index, value.x()));
226 GEN_DIRECT_FLOAT_LOADER(float, 2, f, "vertex_attrib_2f", (index, value.x(), value.y()));
227 GEN_DIRECT_FLOAT_LOADER(float, 3, f, "vertex_attrib_3f", (index, value.x(), value.y(), value.z()));
228 GEN_DIRECT_FLOAT_LOADER(float, 4, f, "vertex_attrib_4f", (index, value.x(), value.y(), value.z(), value.w()));
229 
230 GEN_INDIRECT_FLOAT_LOADER(float, 1, fv, "vertex_attrib_1fv");
231 GEN_INDIRECT_FLOAT_LOADER(float, 2, fv, "vertex_attrib_2fv");
232 GEN_INDIRECT_FLOAT_LOADER(float, 3, fv, "vertex_attrib_3fv");
233 GEN_INDIRECT_FLOAT_LOADER(float, 4, fv, "vertex_attrib_4fv");
234 
235 GEN_DIRECT_INTEGER_LOADER(int32_t, 4, i, "vertex_attribi_4i", (index, value.x(), value.y(), value.z(), value.w()));
236 GEN_INDIRECT_INTEGER_LOADER(int32_t, 4, iv, "vertex_attribi_4iv");
237 
238 GEN_DIRECT_INTEGER_LOADER(uint32_t, 4, ui, "vertex_attribi_4ui", (index, value.x(), value.y(), value.z(), value.w()));
239 GEN_INDIRECT_INTEGER_LOADER(uint32_t, 4, uiv, "vertex_attribi_4uiv");
240 
241 class AttributeCase : public TestCase
242 {
243     AttributeCase(Context &ctx, const char *name, const char *desc, const char *funcName, bool normalizing,
244                   bool useNegative, glu::DataType dataType);
245 
246 public:
247     template <typename LoaderType>
248     static AttributeCase *create(Context &ctx, glu::DataType dataType);
249     ~AttributeCase(void);
250 
251 private:
252     void init(void);
253     void deinit(void);
254     IterateResult iterate(void);
255 
256     glu::DataType getTargetType(void) const;
257     std::string genVertexSource(void) const;
258     bool renderWithValue(const tcu::Vec4 &v);
259     tcu::Vec4 computeColor(const tcu::Vec4 &value);
260     bool verifyUnicoloredBuffer(const tcu::Surface &scene, const tcu::Vec4 &refValue);
261 
262     const bool m_normalizing;
263     const bool m_useNegativeValues;
264     const char *const m_funcName;
265     const glu::DataType m_dataType;
266     const FloatLoader *m_loader;
267     glu::ShaderProgram *m_program;
268     uint32_t m_bufID;
269     bool m_allIterationsPassed;
270     int m_iteration;
271 
272     enum
273     {
274         RENDER_SIZE = 32
275     };
276 };
277 
AttributeCase(Context & ctx,const char * name,const char * desc,const char * funcName,bool normalizing,bool useNegative,glu::DataType dataType)278 AttributeCase::AttributeCase(Context &ctx, const char *name, const char *desc, const char *funcName, bool normalizing,
279                              bool useNegative, glu::DataType dataType)
280     : TestCase(ctx, name, desc)
281     , m_normalizing(normalizing)
282     , m_useNegativeValues(useNegative)
283     , m_funcName(funcName)
284     , m_dataType(dataType)
285     , m_loader(DE_NULL)
286     , m_program(DE_NULL)
287     , m_bufID(0)
288     , m_allIterationsPassed(true)
289     , m_iteration(0)
290 {
291 }
292 
293 template <typename LoaderType>
create(Context & ctx,glu::DataType dataType)294 AttributeCase *AttributeCase::create(Context &ctx, glu::DataType dataType)
295 {
296     AttributeCase *retVal = new AttributeCase(
297         ctx, LoaderType::getCaseName(), (std::string("Test ") + LoaderType::getName()).c_str(), LoaderType::getName(),
298         LoaderType::NORMALIZING != 0, std::numeric_limits<typename LoaderType::Type>::is_signed, dataType);
299     retVal->m_loader = new LoaderType();
300     return retVal;
301 }
302 
~AttributeCase(void)303 AttributeCase::~AttributeCase(void)
304 {
305     deinit();
306 }
307 
init(void)308 void AttributeCase::init(void)
309 {
310     if (m_context.getRenderTarget().getWidth() < RENDER_SIZE || m_context.getRenderTarget().getHeight() < RENDER_SIZE)
311         throw tcu::NotSupportedError("Render target must be at least " + de::toString<int>(RENDER_SIZE) + "x" +
312                                      de::toString<int>(RENDER_SIZE));
313 
314     // log test info
315 
316     {
317         const float maxRange = (m_normalizing) ? (1.0f) : (s_valueRange);
318         const float minRange = (m_useNegativeValues) ? (-maxRange) : (0.0f);
319 
320         m_testCtx.getLog() << tcu::TestLog::Message << "Loading attribute values using " << m_funcName << "\n"
321                            << "Attribute type: " << glu::getDataTypeName(m_dataType) << "\n"
322                            << "Attribute value range: [" << minRange << ", " << maxRange << "]"
323                            << tcu::TestLog::EndMessage;
324     }
325 
326     // gen shader and base quad
327 
328     m_program = new glu::ShaderProgram(m_context.getRenderContext(),
329                                        glu::ProgramSources() << glu::VertexSource(genVertexSource())
330                                                              << glu::FragmentSource(s_passThroughFragmentShaderSource));
331     m_testCtx.getLog() << *m_program;
332     if (!m_program->isOk())
333         throw tcu::TestError("could not build program");
334 
335     {
336         const tcu::Vec4 fullscreenQuad[] = {
337             tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
338             tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),
339             tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
340             tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
341         };
342 
343         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
344 
345         gl.genBuffers(1, &m_bufID);
346         gl.bindBuffer(GL_ARRAY_BUFFER, m_bufID);
347         gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad, GL_STATIC_DRAW);
348         GLU_EXPECT_NO_ERROR(gl.getError(), "fill buffer");
349     }
350 }
351 
deinit(void)352 void AttributeCase::deinit(void)
353 {
354     delete m_loader;
355     m_loader = DE_NULL;
356 
357     delete m_program;
358     m_program = DE_NULL;
359 
360     if (m_bufID)
361     {
362         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_bufID);
363         m_bufID = 0;
364     }
365 }
366 
iterate(void)367 AttributeCase::IterateResult AttributeCase::iterate(void)
368 {
369     static const tcu::Vec4 testValues[] = {
370         tcu::Vec4(0.0f, 0.5f, 0.2f, 1.0f), tcu::Vec4(0.1f, 0.7f, 1.0f, 0.6f), tcu::Vec4(0.4f, 0.2f, 0.0f, 0.5f),
371         tcu::Vec4(0.5f, 0.0f, 0.9f, 0.1f), tcu::Vec4(0.6f, 0.2f, 0.2f, 0.9f), tcu::Vec4(0.9f, 1.0f, 0.0f, 0.0f),
372         tcu::Vec4(1.0f, 0.5f, 0.3f, 0.8f),
373     };
374 
375     const tcu::ScopedLogSection section(m_testCtx.getLog(), "Iteration",
376                                         "Iteration " + de::toString(m_iteration + 1) + "/" +
377                                             de::toString(DE_LENGTH_OF_ARRAY(testValues)));
378 
379     // Test normalizing transfers with whole range, non-normalizing with up to s_valueRange
380     const tcu::Vec4 testValue =
381         ((m_useNegativeValues) ? (testValues[m_iteration] * 2.0f - tcu::Vec4(1.0f)) : (testValues[m_iteration])) *
382         ((m_normalizing) ? (1.0f) : ((float)s_valueRange));
383 
384     if (!renderWithValue(testValue))
385         m_allIterationsPassed = false;
386 
387     // continue
388 
389     if (++m_iteration < DE_LENGTH_OF_ARRAY(testValues))
390         return CONTINUE;
391 
392     if (m_allIterationsPassed)
393         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
394     else
395         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected values");
396 
397     return STOP;
398 }
399 
genVertexSource(void) const400 std::string AttributeCase::genVertexSource(void) const
401 {
402     const int vectorSize         = (glu::isDataTypeMatrix(m_dataType)) ? (glu::getDataTypeMatrixNumRows(m_dataType)) :
403                                    (glu::isDataTypeVector(m_dataType)) ? (glu::getDataTypeScalarSize(m_dataType)) :
404                                                                          (-1);
405     const char *const vectorType = glu::getDataTypeName(
406         (glu::isDataTypeMatrix(m_dataType)) ? (glu::getDataTypeVector(glu::TYPE_FLOAT, vectorSize)) :
407         (glu::isDataTypeVector(m_dataType)) ? (glu::getDataTypeVector(glu::TYPE_FLOAT, vectorSize)) :
408                                               (glu::TYPE_FLOAT));
409     const int components = (glu::isDataTypeMatrix(m_dataType)) ? (glu::getDataTypeMatrixNumRows(m_dataType)) :
410                                                                  (glu::getDataTypeScalarSize(m_dataType));
411     std::ostringstream buf;
412 
413     buf << "#version 300 es\n"
414            "in highp vec4 a_position;\n"
415            "in highp "
416         << glu::getDataTypeName(m_dataType)
417         << " a_value;\n"
418            "out highp vec4 v_color;\n"
419            "void main (void)\n"
420            "{\n"
421            "    gl_Position = a_position;\n"
422            "\n";
423 
424     if (m_normalizing)
425         buf << "    highp " << vectorType << " normalizedValue = "
426             << ((glu::getDataTypeScalarType(m_dataType) == glu::TYPE_FLOAT) ? ("") : (vectorType)) << "(a_value"
427             << ((glu::isDataTypeMatrix(m_dataType)) ? ("[1]") : ("")) << ");\n";
428     else
429         buf << "    highp " << vectorType << " normalizedValue = "
430             << ((glu::getDataTypeScalarType(m_dataType) == glu::TYPE_FLOAT) ? ("") : (vectorType)) << "(a_value"
431             << ((glu::isDataTypeMatrix(m_dataType)) ? ("[1]") : ("")) << ") / float(" << s_valueRange << ");\n";
432 
433     if (m_useNegativeValues)
434         buf << "    highp " << vectorType << " positiveNormalizedValue = (normalizedValue + " << vectorType
435             << "(1.0)) / 2.0;\n";
436     else
437         buf << "    highp " << vectorType << " positiveNormalizedValue = normalizedValue;\n";
438 
439     if (components == 1)
440         buf << "    v_color = vec4(positiveNormalizedValue, 0.0, 0.0, 1.0);\n";
441     else if (components == 2)
442         buf << "    v_color = vec4(positiveNormalizedValue.xy, 0.0, 1.0);\n";
443     else if (components == 3)
444         buf << "    v_color = vec4(positiveNormalizedValue.xyz, 1.0);\n";
445     else if (components == 4)
446         buf << "    v_color = vec4((positiveNormalizedValue.xy + positiveNormalizedValue.zz) / 2.0, "
447                "positiveNormalizedValue.w, 1.0);\n";
448     else
449         DE_ASSERT(false);
450 
451     buf << "}\n";
452 
453     return buf.str();
454 }
455 
renderWithValue(const tcu::Vec4 & v)456 bool AttributeCase::renderWithValue(const tcu::Vec4 &v)
457 {
458     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
459 
460     gl.enableLogging(true);
461 
462     const int positionIndex = gl.glGetAttribLocation(m_program->getProgram(), "a_position");
463     const int valueIndex    = gl.glGetAttribLocation(m_program->getProgram(), "a_value");
464     tcu::Surface dest(RENDER_SIZE, RENDER_SIZE);
465     tcu::Vec4 loadedValue;
466 
467     gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
468     gl.glClear(GL_COLOR_BUFFER_BIT);
469     gl.glViewport(0, 0, RENDER_SIZE, RENDER_SIZE);
470     GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup");
471 
472     gl.glBindBuffer(GL_ARRAY_BUFFER, m_bufID);
473     gl.glVertexAttribPointer(positionIndex, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
474     gl.glEnableVertexAttribArray(positionIndex);
475     GLU_EXPECT_NO_ERROR(gl.glGetError(), "position va");
476 
477     // transfer test value. Load to the second column in the matrix case
478     loadedValue = m_loader->load(gl, (glu::isDataTypeMatrix(m_dataType)) ? (valueIndex + 1) : (valueIndex), v);
479     GLU_EXPECT_NO_ERROR(gl.glGetError(), "default va");
480 
481     gl.glUseProgram(m_program->getProgram());
482     gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
483     gl.glUseProgram(0);
484     GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw");
485 
486     glu::readPixels(m_context.getRenderContext(), 0, 0, dest.getAccess());
487 
488     // check whole result is colored correctly
489     return verifyUnicoloredBuffer(dest, computeColor(loadedValue));
490 }
491 
computeColor(const tcu::Vec4 & value)492 tcu::Vec4 AttributeCase::computeColor(const tcu::Vec4 &value)
493 {
494     const tcu::Vec4 normalizedValue = value / ((m_normalizing) ? (1.0f) : ((float)s_valueRange));
495     const tcu::Vec4 positiveNormalizedValue =
496         ((m_useNegativeValues) ? ((normalizedValue + tcu::Vec4(1.0f)) / 2.0f) : (normalizedValue));
497     const int components = (glu::isDataTypeMatrix(m_dataType)) ? (glu::getDataTypeMatrixNumRows(m_dataType)) :
498                                                                  (glu::getDataTypeScalarSize(m_dataType));
499 
500     if (components == 1)
501         return tcu::Vec4(positiveNormalizedValue.x(), 0.0f, 0.0f, 1.0f);
502     else if (components == 2)
503         return tcu::Vec4(positiveNormalizedValue.x(), positiveNormalizedValue.y(), 0.0f, 1.0f);
504     else if (components == 3)
505         return tcu::Vec4(positiveNormalizedValue.x(), positiveNormalizedValue.y(), positiveNormalizedValue.z(), 1.0f);
506     else if (components == 4)
507         return tcu::Vec4((positiveNormalizedValue.x() + positiveNormalizedValue.z()) / 2.0f,
508                          (positiveNormalizedValue.y() + positiveNormalizedValue.z()) / 2.0f,
509                          positiveNormalizedValue.w(), 1.0f);
510     else
511         DE_ASSERT(false);
512 
513     return tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
514 }
515 
verifyUnicoloredBuffer(const tcu::Surface & scene,const tcu::Vec4 & refValue)516 bool AttributeCase::verifyUnicoloredBuffer(const tcu::Surface &scene, const tcu::Vec4 &refValue)
517 {
518     tcu::Surface errorMask(RENDER_SIZE, RENDER_SIZE);
519     const tcu::RGBA refColor(refValue);
520     const int resultThreshold      = 2;
521     const tcu::RGBA colorThreshold = m_context.getRenderTarget().getPixelFormat().getColorThreshold() * resultThreshold;
522     bool error                     = false;
523 
524     tcu::RGBA exampleColor;
525     tcu::IVec2 examplePos;
526 
527     tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toIVec());
528 
529     m_testCtx.getLog() << tcu::TestLog::Message << "Verifying rendered image. Expecting color " << refColor
530                        << ", threshold " << colorThreshold << tcu::TestLog::EndMessage;
531 
532     for (int y = 0; y < RENDER_SIZE; ++y)
533         for (int x = 0; x < RENDER_SIZE; ++x)
534         {
535             const tcu::RGBA color = scene.getPixel(x, y);
536 
537             if (de::abs(color.getRed() - refColor.getRed()) > colorThreshold.getRed() ||
538                 de::abs(color.getGreen() - refColor.getGreen()) > colorThreshold.getGreen() ||
539                 de::abs(color.getBlue() - refColor.getBlue()) > colorThreshold.getBlue())
540             {
541                 // first error
542                 if (!error)
543                 {
544                     exampleColor = color;
545                     examplePos   = tcu::IVec2(x, y);
546                 }
547 
548                 error = true;
549                 errorMask.setPixel(x, y, tcu::RGBA::red());
550             }
551         }
552 
553     if (!error)
554         m_testCtx.getLog() << tcu::TestLog::Message << "Rendered image is valid." << tcu::TestLog::EndMessage;
555     else
556     {
557         m_testCtx.getLog() << tcu::TestLog::Message << "Found invalid pixel(s).\n"
558                            << "Pixel at (" << examplePos.x() << ", " << examplePos.y() << ") color: " << exampleColor
559                            << tcu::TestLog::EndMessage << tcu::TestLog::ImageSet("Result", "Render result")
560                            << tcu::TestLog::Image("Result", "Result", scene)
561                            << tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask) << tcu::TestLog::EndImageSet;
562     }
563 
564     return !error;
565 }
566 
567 } // namespace
568 
DefaultVertexAttributeTests(Context & context)569 DefaultVertexAttributeTests::DefaultVertexAttributeTests(Context &context)
570     : TestCaseGroup(context, "default_vertex_attrib", "Test default vertex attributes")
571 {
572 }
573 
~DefaultVertexAttributeTests(void)574 DefaultVertexAttributeTests::~DefaultVertexAttributeTests(void)
575 {
576 }
577 
init(void)578 void DefaultVertexAttributeTests::init(void)
579 {
580     struct Target
581     {
582         const char *name;
583         glu::DataType dataType;
584         bool reducedTestSets; // !< use reduced coverage
585     };
586 
587     static const Target floatTargets[] = {
588         {"float", glu::TYPE_FLOAT, false},        {"vec2", glu::TYPE_FLOAT_VEC2, true},
589         {"vec3", glu::TYPE_FLOAT_VEC3, true},     {"vec4", glu::TYPE_FLOAT_VEC4, false},
590         {"mat2", glu::TYPE_FLOAT_MAT2, true},     {"mat2x3", glu::TYPE_FLOAT_MAT2X3, true},
591         {"mat2x4", glu::TYPE_FLOAT_MAT2X4, true}, {"mat3", glu::TYPE_FLOAT_MAT3, true},
592         {"mat3x2", glu::TYPE_FLOAT_MAT3X2, true}, {"mat3x4", glu::TYPE_FLOAT_MAT3X4, true},
593         {"mat4", glu::TYPE_FLOAT_MAT4, false},    {"mat4x2", glu::TYPE_FLOAT_MAT4X2, true},
594         {"mat4x3", glu::TYPE_FLOAT_MAT4X3, true},
595     };
596 
597     static const Target intTargets[] = {
598         {"int", glu::TYPE_INT, false},
599         {"ivec2", glu::TYPE_INT_VEC2, true},
600         {"ivec3", glu::TYPE_INT_VEC3, true},
601         {"ivec4", glu::TYPE_INT_VEC4, false},
602     };
603 
604     static const Target uintTargets[] = {
605         {"uint", glu::TYPE_UINT, false},
606         {"uvec2", glu::TYPE_UINT_VEC2, true},
607         {"uvec3", glu::TYPE_UINT_VEC3, true},
608         {"uvec4", glu::TYPE_UINT_VEC4, false},
609     };
610 
611     // float targets
612 
613     for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(floatTargets); ++targetNdx)
614     {
615         tcu::TestCaseGroup *const group =
616             new tcu::TestCaseGroup(m_testCtx, floatTargets[targetNdx].name,
617                                    (std::string("test with ") + floatTargets[targetNdx].name).c_str());
618         const bool fullSet = !floatTargets[targetNdx].reducedTestSets;
619 
620 #define ADD_CASE(X) group->addChild(AttributeCase::create<X>(m_context, floatTargets[targetNdx].dataType))
621 #define ADD_REDUCED_CASE(X) \
622     if (fullSet)            \
623     ADD_CASE(X)
624 
625         ADD_CASE(LoaderVertexAttrib1f);
626         ADD_REDUCED_CASE(LoaderVertexAttrib2f);
627         ADD_REDUCED_CASE(LoaderVertexAttrib3f);
628         ADD_CASE(LoaderVertexAttrib4f);
629 
630         ADD_CASE(LoaderVertexAttrib1fv);
631         ADD_REDUCED_CASE(LoaderVertexAttrib2fv);
632         ADD_REDUCED_CASE(LoaderVertexAttrib3fv);
633         ADD_CASE(LoaderVertexAttrib4fv);
634 
635 #undef ADD_CASE
636 #undef ADD_REDUCED_CASE
637 
638         addChild(group);
639     }
640 
641     // int targets
642 
643     for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(intTargets); ++targetNdx)
644     {
645         tcu::TestCaseGroup *const group = new tcu::TestCaseGroup(
646             m_testCtx, intTargets[targetNdx].name, (std::string("test with ") + intTargets[targetNdx].name).c_str());
647 
648 #define ADD_CASE(X) group->addChild(AttributeCase::create<X>(m_context, intTargets[targetNdx].dataType))
649 
650         ADD_CASE(LoaderVertexAttribI4i);
651         ADD_CASE(LoaderVertexAttribI4iv);
652 
653 #undef ADD_CASE
654 
655         addChild(group);
656     }
657 
658     // uint targets
659 
660     for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(uintTargets); ++targetNdx)
661     {
662         tcu::TestCaseGroup *const group = new tcu::TestCaseGroup(
663             m_testCtx, uintTargets[targetNdx].name, (std::string("test with ") + uintTargets[targetNdx].name).c_str());
664 
665 #define ADD_CASE(X) group->addChild(AttributeCase::create<X>(m_context, uintTargets[targetNdx].dataType))
666 
667         ADD_CASE(LoaderVertexAttribI4ui);
668         ADD_CASE(LoaderVertexAttribI4uiv);
669 
670 #undef ADD_CASE
671 
672         addChild(group);
673     }
674 }
675 
676 } // namespace Functional
677 } // namespace gles3
678 } // namespace deqp
679