Merge "Fix color change verification in dithering tests" into nougat-cts-dev am:...
[platform/upstream/VK-GL-CTS.git] / modules / glshared / glsFragOpInteractionCase.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL (ES) 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 Shader - render state interaction case.
22  *//*--------------------------------------------------------------------*/
23
24 #include "glsFragOpInteractionCase.hpp"
25
26 #include "glsRandomShaderProgram.hpp"
27 #include "glsFragmentOpUtil.hpp"
28 #include "glsInteractionTestUtil.hpp"
29
30 #include "gluRenderContext.hpp"
31 #include "gluContextInfo.hpp"
32
33 #include "rsgShader.hpp"
34 #include "rsgProgramGenerator.hpp"
35 #include "rsgUtils.hpp"
36
37 #include "sglrContext.hpp"
38 #include "sglrReferenceContext.hpp"
39 #include "sglrGLContext.hpp"
40 #include "sglrContextUtil.hpp"
41
42 #include "tcuRenderTarget.hpp"
43 #include "tcuImageCompare.hpp"
44
45 #include "deRandom.hpp"
46 #include "deString.h"
47 #include "deStringUtil.hpp"
48
49 #include "glwEnums.hpp"
50
51 #include "gluDrawUtil.hpp"
52
53 namespace deqp
54 {
55 namespace gls
56 {
57
58 using std::vector;
59 using std::string;
60 using tcu::Vec2;
61 using tcu::Vec4;
62 using tcu::IVec2;
63 using tcu::IVec4;
64
65 using gls::InteractionTestUtil::RenderState;
66 using gls::InteractionTestUtil::StencilState;
67
68 enum
69 {
70         NUM_ITERATIONS                                  = 5,
71         NUM_COMMANDS_PER_ITERATION              = 5,
72         VIEWPORT_WIDTH                                  = 64,
73         VIEWPORT_HEIGHT                                 = 64
74 };
75
76 namespace
77 {
78
79 static void computeVertexLayout (const vector<rsg::ShaderInput*>& attributes, int numVertices, vector<glu::VertexArrayBinding>* layout, int* stride)
80 {
81         DE_ASSERT(layout->empty());
82
83         int curOffset = 0;
84
85         for (vector<rsg::ShaderInput*>::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
86         {
87                 const rsg::ShaderInput*         attrib          = *iter;
88                 const rsg::Variable*            var                     = attrib->getVariable();
89                 const rsg::VariableType&        type            = var->getType();
90                 const int                                       numComps        = type.getNumElements();
91
92                 TCU_CHECK_INTERNAL(type.getBaseType() == rsg::VariableType::TYPE_FLOAT && de::inRange(type.getNumElements(), 1, 4));
93
94                 layout->push_back(glu::va::Float(var->getName(), numComps, numVertices, 0 /* computed later */, (const float*)(deUintptr)curOffset));
95
96                 curOffset += numComps * (int)sizeof(float);
97         }
98
99         for (vector<glu::VertexArrayBinding>::iterator vaIter = layout->begin(); vaIter != layout->end(); ++vaIter)
100                 vaIter->pointer.stride = curOffset;
101
102         *stride = curOffset;
103 }
104
105 class VertexDataStorage
106 {
107 public:
108                                                                                                 VertexDataStorage       (const vector<rsg::ShaderInput*>& attributes, int numVertices);
109
110         int                                                                                     getDataSize                     (void) const    { return (int)m_data.size();                                    }
111         void*                                                                           getBasePtr                      (void)                  { return m_data.empty() ? DE_NULL : &m_data[0]; }
112         const void*                                                                     getBasePtr                      (void) const    { return m_data.empty() ? DE_NULL : &m_data[0]; }
113
114         const std::vector<glu::VertexArrayBinding>&     getLayout                       (void) const    { return m_layout; }
115
116         int                                                                                     getNumEntries           (void) const    { return (int)m_layout.size();  }
117         const glu::VertexArrayBinding&                          getLayoutEntry          (int ndx) const { return m_layout[ndx];                 }
118
119 private:
120         std::vector<deUint8>                                            m_data;
121         std::vector<glu::VertexArrayBinding>            m_layout;
122 };
123
124 VertexDataStorage::VertexDataStorage (const vector<rsg::ShaderInput*>& attributes, int numVertices)
125 {
126         int stride = 0;
127         computeVertexLayout(attributes, numVertices, &m_layout, &stride);
128         m_data.resize(stride * numVertices);
129 }
130
131 static inline glu::VertexArrayBinding getEntryWithPointer (const VertexDataStorage& data, int ndx)
132 {
133         const glu::VertexArrayBinding& entry = data.getLayoutEntry(ndx);
134         return glu::VertexArrayBinding(entry.binding, glu::VertexArrayPointer(entry.pointer.componentType,
135                                                                                                                                                   entry.pointer.convert,
136                                                                                                                                                   entry.pointer.numComponents,
137                                                                                                                                                   entry.pointer.numElements,
138                                                                                                                                                   entry.pointer.stride,
139                                                                                                                                                   (const void*)((deUintptr)entry.pointer.data+(deUintptr)data.getBasePtr())));
140 }
141
142 template<int Size>
143 static void setVertex (const glu::VertexArrayPointer& pointer, int vertexNdx, const tcu::Vector<float, Size>& value)
144 {
145         // \todo [2013-12-14 pyry] Implement other modes.
146         DE_ASSERT(pointer.componentType == glu::VTX_COMP_FLOAT && pointer.convert == glu::VTX_COMP_CONVERT_NONE);
147         DE_ASSERT(pointer.numComponents == Size);
148         DE_ASSERT(de::inBounds(vertexNdx, 0, pointer.numElements));
149
150         float* dst = (float*)((deUint8*)pointer.data + pointer.stride*vertexNdx);
151
152         for (int ndx = 0; ndx < Size; ndx++)
153                 dst[ndx] = value[ndx];
154 }
155
156 template<int Size>
157 static tcu::Vector<float, Size> interpolateRange (const rsg::ConstValueRangeAccess& range, const tcu::Vector<float, Size>& t)
158 {
159         tcu::Vector<float, Size> result;
160
161         for (int ndx = 0; ndx < Size; ndx++)
162                 result[ndx] = range.getMin().component(ndx).asFloat()*(1.0f - t[ndx]) + range.getMax().component(ndx).asFloat()*t[ndx];
163
164         return result;
165 }
166
167 struct Quad
168 {
169         tcu::IVec2      posA;
170         tcu::IVec2      posB;
171 };
172
173 struct RenderCommand
174 {
175         Quad            quad;
176         float           depth;
177         RenderState     state;
178
179         RenderCommand (void) : depth(0.0f) {}
180 };
181
182 static Quad getRandomQuad (de::Random& rnd, int targetW, int targetH)
183 {
184         // \note In viewport coordinates.
185         // \todo [2012-12-18 pyry] Out-of-bounds values.
186         const int               maxOutOfBounds  = 0;
187         const float             minSize                 = 0.5f;
188
189         const int               minW                    = deCeilFloatToInt32(minSize * (float)targetW);
190         const int               minH                    = deCeilFloatToInt32(minSize * (float)targetH);
191         const int               maxW                    = targetW + 2*maxOutOfBounds;
192         const int               maxH                    = targetH + 2*maxOutOfBounds;
193
194         const int               width                   = rnd.getInt(minW, maxW);
195         const int               height                  = rnd.getInt(minH, maxH);
196         const int               x                               = rnd.getInt(-maxOutOfBounds, targetW+maxOutOfBounds-width);
197         const int               y                               = rnd.getInt(-maxOutOfBounds, targetH+maxOutOfBounds-height);
198
199         const bool              flipX                   = rnd.getBool();
200         const bool              flipY                   = rnd.getBool();
201
202         Quad                    quad;
203
204         quad.posA       = tcu::IVec2(flipX ? (x+width-1) : x, flipY ? (y+height-1) : y);
205         quad.posB       = tcu::IVec2(flipX ? x : (x+width-1), flipY ? y : (y+height-1));
206
207         return quad;
208 }
209
210 static float getRandomDepth (de::Random& rnd)
211 {
212         // \note Not using depth 1.0 since clearing with 1.0 and rendering with 1.0 may not be same value.
213         static const float depthValues[] = { 0.0f, 0.2f, 0.4f, 0.5f, 0.51f, 0.6f, 0.8f, 0.95f };
214         return rnd.choose<float>(DE_ARRAY_BEGIN(depthValues), DE_ARRAY_END(depthValues));
215 }
216
217 static void computeRandomRenderCommand (de::Random& rnd, RenderCommand& command, glu::ApiType apiType, int targetW, int targetH)
218 {
219         command.quad    = getRandomQuad(rnd, targetW, targetH);
220         command.depth   = getRandomDepth(rnd);
221         gls::InteractionTestUtil::computeRandomRenderState(rnd, command.state, apiType, targetW, targetH);
222 }
223
224 static void setRenderState (sglr::Context& ctx, const RenderState& state)
225 {
226         if (state.scissorTestEnabled)
227         {
228                 ctx.enable(GL_SCISSOR_TEST);
229                 ctx.scissor(state.scissorRectangle.left, state.scissorRectangle.bottom,
230                                         state.scissorRectangle.width, state.scissorRectangle.height);
231         }
232         else
233                 ctx.disable(GL_SCISSOR_TEST);
234
235         if (state.stencilTestEnabled)
236         {
237                 ctx.enable(GL_STENCIL_TEST);
238
239                 for (int face = 0; face < rr::FACETYPE_LAST; face++)
240                 {
241                         deUint32                                glFace  = face == rr::FACETYPE_BACK ? GL_BACK : GL_FRONT;
242                         const StencilState&             sParams = state.stencil[face];
243
244                         ctx.stencilFuncSeparate(glFace, sParams.function, sParams.reference, sParams.compareMask);
245                         ctx.stencilOpSeparate(glFace, sParams.stencilFailOp, sParams.depthFailOp, sParams.depthPassOp);
246                         ctx.stencilMaskSeparate(glFace, sParams.writeMask);
247                 }
248         }
249         else
250                 ctx.disable(GL_STENCIL_TEST);
251
252         if (state.depthTestEnabled)
253         {
254                 ctx.enable(GL_DEPTH_TEST);
255                 ctx.depthFunc(state.depthFunc);
256                 ctx.depthMask(state.depthWriteMask ? GL_TRUE : GL_FALSE);
257         }
258         else
259                 ctx.disable(GL_DEPTH_TEST);
260
261         if (state.blendEnabled)
262         {
263                 ctx.enable(GL_BLEND);
264                 ctx.blendEquationSeparate(state.blendRGBState.equation, state.blendAState.equation);
265                 ctx.blendFuncSeparate(state.blendRGBState.srcFunc, state.blendRGBState.dstFunc, state.blendAState.srcFunc, state.blendAState.dstFunc);
266                 ctx.blendColor(state.blendColor.x(), state.blendColor.y(), state.blendColor.z(), state.blendColor.w());
267         }
268         else
269                 ctx.disable(GL_BLEND);
270
271         if (state.ditherEnabled)
272                 ctx.enable(GL_DITHER);
273         else
274                 ctx.disable(GL_DITHER);
275
276         ctx.colorMask(state.colorMask[0] ? GL_TRUE : GL_FALSE,
277                                   state.colorMask[1] ? GL_TRUE : GL_FALSE,
278                                   state.colorMask[2] ? GL_TRUE : GL_FALSE,
279                                   state.colorMask[3] ? GL_TRUE : GL_FALSE);
280 }
281
282 static void renderQuad (sglr::Context& ctx, const glu::VertexArrayPointer& posPtr, const Quad& quad, const float depth)
283 {
284         const deUint16  indices[]       = { 0, 1, 2, 2, 1, 3 };
285
286         const bool              flipX           = quad.posB.x() < quad.posA.x();
287         const bool              flipY           = quad.posB.y() < quad.posA.y();
288         const int               viewportX       = de::min(quad.posA.x(), quad.posB.x());
289         const int               viewportY       = de::min(quad.posA.y(), quad.posB.y());
290         const int               viewportW       = de::abs(quad.posA.x()-quad.posB.x())+1;
291         const int               viewportH       = de::abs(quad.posA.y()-quad.posB.y())+1;
292
293         const Vec2              pA                      (flipX ? 1.0f : -1.0f, flipY ? 1.0f : -1.0f);
294         const Vec2              pB                      (flipX ? -1.0f : 1.0f, flipY ? -1.0f : 1.0f);
295
296         setVertex(posPtr, 0, Vec4(pA.x(), pA.y(), depth, 1.0f));
297         setVertex(posPtr, 1, Vec4(pB.x(), pA.y(), depth, 1.0f));
298         setVertex(posPtr, 2, Vec4(pA.x(), pB.y(), depth, 1.0f));
299         setVertex(posPtr, 3, Vec4(pB.x(), pB.y(), depth, 1.0f));
300
301         ctx.viewport(viewportX, viewportY, viewportW, viewportH);
302         ctx.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]);
303 }
304
305 static void render (sglr::Context& ctx, const glu::VertexArrayPointer& posPtr, const RenderCommand& cmd)
306 {
307         setRenderState(ctx, cmd.state);
308         renderQuad(ctx, posPtr, cmd.quad, cmd.depth);
309 }
310
311 static void setupAttributes (sglr::Context& ctx, const VertexDataStorage& vertexData, deUint32 program)
312 {
313         for (int attribNdx = 0; attribNdx < vertexData.getNumEntries(); ++attribNdx)
314         {
315                 const glu::VertexArrayBinding   bindingPtr      = getEntryWithPointer(vertexData, attribNdx);
316                 const int                                               attribLoc       = bindingPtr.binding.type == glu::BindingPoint::TYPE_NAME ? ctx.getAttribLocation(program, bindingPtr.binding.name.c_str()) : bindingPtr.binding.location;
317
318                 DE_ASSERT(bindingPtr.pointer.componentType == glu::VTX_COMP_FLOAT);
319
320                 if (attribLoc >= 0)
321                 {
322                         ctx.enableVertexAttribArray(attribLoc);
323                         ctx.vertexAttribPointer(attribLoc, bindingPtr.pointer.numComponents, GL_FLOAT, GL_FALSE, bindingPtr.pointer.stride, bindingPtr.pointer.data);
324                 }
325         }
326 }
327
328 void setUniformValue (sglr::Context& ctx, int location, rsg::ConstValueAccess value)
329 {
330         DE_STATIC_ASSERT(sizeof(rsg::Scalar) == sizeof(float));
331         DE_STATIC_ASSERT(sizeof(rsg::Scalar) == sizeof(int));
332
333         switch (value.getType().getBaseType())
334         {
335                 case rsg::VariableType::TYPE_FLOAT:
336                         switch (value.getType().getNumElements())
337                         {
338                                 case 1:         ctx.uniform1fv(location, 1, (float*)value.value().getValuePtr());       break;
339                                 case 2:         ctx.uniform2fv(location, 1, (float*)value.value().getValuePtr());       break;
340                                 case 3:         ctx.uniform3fv(location, 1, (float*)value.value().getValuePtr());       break;
341                                 case 4:         ctx.uniform4fv(location, 1, (float*)value.value().getValuePtr());       break;
342                                 default:        TCU_FAIL("Unsupported type");                                                                           break;
343                         }
344                         break;
345
346                 case rsg::VariableType::TYPE_INT:
347                 case rsg::VariableType::TYPE_BOOL:
348                 case rsg::VariableType::TYPE_SAMPLER_2D:
349                 case rsg::VariableType::TYPE_SAMPLER_CUBE:
350                         switch (value.getType().getNumElements())
351                         {
352                                 case 1:         ctx.uniform1iv(location, 1, (int*)value.value().getValuePtr());         break;
353                                 case 2:         ctx.uniform2iv(location, 1, (int*)value.value().getValuePtr());         break;
354                                 case 3:         ctx.uniform3iv(location, 1, (int*)value.value().getValuePtr());         break;
355                                 case 4:         ctx.uniform4iv(location, 1, (int*)value.value().getValuePtr());         break;
356                                 default:        TCU_FAIL("Unsupported type");                                                                           break;
357                         }
358                         break;
359
360                 default:
361                         throw tcu::InternalError("Unsupported type", "", __FILE__, __LINE__);
362         }
363 }
364
365 static int findShaderInputIndex (const vector<rsg::ShaderInput*>& vars, const char* name)
366 {
367         for (int ndx = 0; ndx < (int)vars.size(); ++ndx)
368         {
369                 if (deStringEqual(vars[ndx]->getVariable()->getName(), name))
370                         return ndx;
371         }
372
373         throw tcu::InternalError(string(name) + " not found in shader inputs");
374 }
375
376 static float getWellBehavingChannelColor (float v, int numBits)
377 {
378         DE_ASSERT(de::inRange(numBits, 0, 32));
379
380         // clear color may not be accurately representable in the target format. If the clear color is
381         // on a representable value mapping range border, it could be rounded differently by the GL and in
382         // SGLR adding an unexpected error source. However, selecting an accurately representable background
383         // color would effectively disable dithering. To allow dithering and to prevent undefined rounding
384         // direction from affecting results, round accurate color to target color format with 8 sub-units
385         // (3 bits). If the selected sub-unit value is 3 or 4 (bordering 0.5), replace it with 2 and 5,
386         // respectively.
387
388         if (numBits == 0 || v <= 0.0f || v >= 1.0f)
389         {
390                 // already accurately representable
391                 return v;
392         }
393         else
394         {
395                 const deUint64 numSubBits               = 3;
396                 const deUint64 subUnitBorderLo  = (1u << (numSubBits - 1u)) - 1u;
397                 const deUint64 subUnitBorderHi  = 1u << (numSubBits - 1u);
398                 const deUint64 maxFixedValue    = (1u << (numBits + numSubBits)) - 1u;
399                 const deUint64 fixedValue               = deRoundFloatToInt64(v * (float)maxFixedValue);
400
401                 const deUint64 units                    = fixedValue >> numSubBits;
402                 const deUint64 subUnits                 = fixedValue & ((1u << numSubBits) - 1u);
403
404                 const deUint64 tweakedSubUnits  = (subUnits == subUnitBorderLo) ? (subUnitBorderLo - 1)
405                                                                                 : (subUnits == subUnitBorderHi) ? (subUnitBorderHi + 1)
406                                                                                 : (subUnits);
407                 const deUint64 tweakedValue             = (units << numSubBits) | (tweakedSubUnits);
408
409                 return float(tweakedValue) / float(maxFixedValue);
410         }
411 }
412
413 static tcu::Vec4 getWellBehavingColor (const tcu::Vec4& accurateColor, const tcu::PixelFormat& format)
414 {
415         return tcu::Vec4(getWellBehavingChannelColor(accurateColor[0], format.redBits),
416                                          getWellBehavingChannelColor(accurateColor[1], format.greenBits),
417                                          getWellBehavingChannelColor(accurateColor[2], format.blueBits),
418                                          getWellBehavingChannelColor(accurateColor[3], format.alphaBits));
419 }
420
421 } // anonymous
422
423 struct FragOpInteractionCase::ReferenceContext
424 {
425         const sglr::ReferenceContextLimits      limits;
426         sglr::ReferenceContextBuffers           buffers;
427         sglr::ReferenceContext                          context;
428
429         ReferenceContext (glu::RenderContext& renderCtx, int width, int height)
430                 : limits        (renderCtx)
431                 , buffers       (renderCtx.getRenderTarget().getPixelFormat(), renderCtx.getRenderTarget().getDepthBits(), renderCtx.getRenderTarget().getStencilBits(), width, height)
432                 , context       (limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer())
433         {
434         }
435 };
436
437 FragOpInteractionCase::FragOpInteractionCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const rsg::ProgramParameters& params)
438         : TestCase                      (testCtx, name, "")
439         , m_renderCtx           (renderCtx)
440         , m_ctxInfo                     (ctxInfo)
441         , m_params                      (params)
442         , m_vertexShader        (rsg::Shader::TYPE_VERTEX)
443         , m_fragmentShader      (rsg::Shader::TYPE_FRAGMENT)
444         , m_program                     (DE_NULL)
445         , m_glCtx                       (DE_NULL)
446         , m_referenceCtx        (DE_NULL)
447         , m_glProgram           (0)
448         , m_refProgram          (0)
449         , m_iterNdx                     (0)
450 {
451 }
452
453 FragOpInteractionCase::~FragOpInteractionCase (void)
454 {
455         FragOpInteractionCase::deinit();
456 }
457
458 void FragOpInteractionCase::init (void)
459 {
460         de::Random                              rnd                             (m_params.seed ^ 0x232faac);
461         const int                               viewportW               = de::min<int>(m_renderCtx.getRenderTarget().getWidth(),        VIEWPORT_WIDTH);
462         const int                               viewportH               = de::min<int>(m_renderCtx.getRenderTarget().getHeight(),       VIEWPORT_HEIGHT);
463         const int                               viewportX               = rnd.getInt(0, m_renderCtx.getRenderTarget().getWidth()        - viewportW);
464         const int                               viewportY               = rnd.getInt(0, m_renderCtx.getRenderTarget().getHeight()       - viewportH);
465
466         rsg::ProgramGenerator   generator;
467
468         generator.generate(m_params, m_vertexShader, m_fragmentShader);
469         rsg::computeUnifiedUniforms(m_vertexShader, m_fragmentShader, m_unifiedUniforms);
470
471         try
472         {
473                 DE_ASSERT(!m_program);
474                 m_program = new gls::RandomShaderProgram(m_vertexShader, m_fragmentShader, (int)m_unifiedUniforms.size(), m_unifiedUniforms.empty() ? DE_NULL : &m_unifiedUniforms[0]);
475
476                 DE_ASSERT(!m_referenceCtx);
477                 m_referenceCtx = new ReferenceContext(m_renderCtx, viewportW, viewportH);
478
479                 DE_ASSERT(!m_glCtx);
480                 m_glCtx = new sglr::GLContext(m_renderCtx, m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS|sglr::GLCONTEXT_LOG_PROGRAMS, IVec4(viewportX, viewportY, viewportW, viewportH));
481
482                 m_refProgram    = m_referenceCtx->context.createProgram(m_program);
483                 m_glProgram             = m_glCtx->createProgram(m_program);
484
485                 m_viewportSize  = tcu::IVec2(viewportW, viewportH);
486                 m_iterNdx               = 0;
487                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
488         }
489         catch (...)
490         {
491                 // Save some memory by cleaning up stuff.
492                 FragOpInteractionCase::deinit();
493                 throw;
494         }
495 }
496
497 void FragOpInteractionCase::deinit (void)
498 {
499         delete m_referenceCtx;
500         m_referenceCtx = DE_NULL;
501
502         delete m_glCtx;
503         m_glCtx = DE_NULL;
504
505         delete m_program;
506         m_program = DE_NULL;
507 }
508
509 FragOpInteractionCase::IterateResult FragOpInteractionCase::iterate (void)
510 {
511         de::Random                                                      rnd                                     (m_params.seed ^ deInt32Hash(m_iterNdx));
512         const tcu::ScopedLogSection                     section                         (m_testCtx.getLog(), string("Iter") + de::toString(m_iterNdx), string("Iteration ") + de::toString(m_iterNdx));
513
514         const int                                                       positionNdx                     = findShaderInputIndex(m_vertexShader.getInputs(), "dEQP_Position");
515
516         const int                                                       numVertices                     = 4;
517         VertexDataStorage                                       vertexData                      (m_vertexShader.getInputs(), numVertices);
518         std::vector<rsg::VariableValue>         uniformValues;
519         std::vector<RenderCommand>                      renderCmds                      (NUM_COMMANDS_PER_ITERATION);
520
521         tcu::Surface                                            rendered                        (m_viewportSize.x(), m_viewportSize.y());
522         tcu::Surface                                            reference                       (m_viewportSize.x(), m_viewportSize.y());
523
524         const tcu::Vec4                                         vtxInterpFactors[]      =
525         {
526                 tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
527                 tcu::Vec4(1.0f, 0.0f, 0.5f, 0.5f),
528                 tcu::Vec4(0.0f, 1.0f, 0.5f, 0.5f),
529                 tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)
530         };
531
532         rsg::computeUniformValues(rnd, uniformValues, m_unifiedUniforms);
533
534         for (int attribNdx = 0; attribNdx < (int)m_vertexShader.getInputs().size(); ++attribNdx)
535         {
536                 if (attribNdx == positionNdx)
537                         continue;
538
539                 const rsg::ShaderInput*                         shaderIn                = m_vertexShader.getInputs()[attribNdx];
540                 const rsg::VariableType&                        varType                 = shaderIn->getVariable()->getType();
541                 const rsg::ConstValueRangeAccess        valueRange              = shaderIn->getValueRange();
542                 const int                                                       numComponents   = varType.getNumElements();
543                 const glu::VertexArrayBinding           layoutEntry             = getEntryWithPointer(vertexData, attribNdx);
544
545                 DE_ASSERT(varType.getBaseType() == rsg::VariableType::TYPE_FLOAT);
546
547                 for (int vtxNdx = 0; vtxNdx < 4; vtxNdx++)
548                 {
549                         const int                       fNdx    = (attribNdx+vtxNdx+m_iterNdx)%DE_LENGTH_OF_ARRAY(vtxInterpFactors);
550                         const tcu::Vec4&        f               = vtxInterpFactors[fNdx];
551
552                         switch (numComponents)
553                         {
554                                 case 1: setVertex(layoutEntry.pointer, vtxNdx, interpolateRange(valueRange, f.toWidth<1>()));   break;
555                                 case 2: setVertex(layoutEntry.pointer, vtxNdx, interpolateRange(valueRange, f.toWidth<2>()));   break;
556                                 case 3: setVertex(layoutEntry.pointer, vtxNdx, interpolateRange(valueRange, f.toWidth<3>()));   break;
557                                 case 4: setVertex(layoutEntry.pointer, vtxNdx, interpolateRange(valueRange, f.toWidth<4>()));   break;
558                                 default:
559                                         DE_ASSERT(false);
560                         }
561                 }
562         }
563
564         for (vector<RenderCommand>::iterator cmdIter = renderCmds.begin(); cmdIter != renderCmds.end(); ++cmdIter)
565                 computeRandomRenderCommand(rnd, *cmdIter, m_renderCtx.getType().getAPI(), m_viewportSize.x(), m_viewportSize.y());
566
567         // Workaround for inaccurate barycentric/depth computation in current reference renderer:
568         // Small bias is added to the draw call depths, in increasing order, to avoid accuracy issues in depth comparison.
569         for (int cmdNdx = 0; cmdNdx < (int)renderCmds.size(); cmdNdx++)
570                 renderCmds[cmdNdx].depth += 0.0231725f * float(cmdNdx);
571
572         {
573                 const glu::VertexArrayPointer           posPtr                          = getEntryWithPointer(vertexData, positionNdx).pointer;
574
575                 sglr::Context* const                            contexts[]                      = { m_glCtx, &m_referenceCtx->context };
576                 const deUint32                                          programs[]                      = { m_glProgram, m_refProgram };
577                 tcu::PixelBufferAccess                          readDst[]                       = { rendered.getAccess(), reference.getAccess() };
578
579                 const tcu::Vec4                                         accurateClearColor      = tcu::Vec4(0.0f, 0.25f, 0.5f, 1.0f);
580                 const tcu::Vec4                                         clearColor                      = getWellBehavingColor(accurateClearColor, m_renderCtx.getRenderTarget().getPixelFormat());
581
582                 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(contexts); ndx++)
583                 {
584                         sglr::Context&  ctx                     = *contexts[ndx];
585                         const deUint32  program         = programs[ndx];
586
587                         setupAttributes(ctx, vertexData, program);
588
589                         ctx.disable             (GL_SCISSOR_TEST);
590                         ctx.colorMask   (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
591                         ctx.depthMask   (GL_TRUE);
592                         ctx.stencilMask (~0u);
593                         ctx.clearColor  (clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
594                         ctx.clear               (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
595
596                         ctx.useProgram  (program);
597
598                         for (vector<rsg::VariableValue>::const_iterator uniformIter = uniformValues.begin(); uniformIter != uniformValues.end(); ++uniformIter)
599                                 setUniformValue(ctx, ctx.getUniformLocation(program, uniformIter->getVariable()->getName()), uniformIter->getValue());
600
601                         for (vector<RenderCommand>::const_iterator cmdIter = renderCmds.begin(); cmdIter != renderCmds.end(); ++cmdIter)
602                                 render(ctx, posPtr, *cmdIter);
603
604                         GLU_EXPECT_NO_ERROR(ctx.getError(), "Rendering failed");
605
606                         ctx.readPixels(0, 0, m_viewportSize.x(), m_viewportSize.y(), GL_RGBA, GL_UNSIGNED_BYTE, readDst[ndx].getDataPtr());
607                 }
608         }
609
610         {
611                 const tcu::RGBA         threshold               = m_renderCtx.getRenderTarget().getPixelFormat().getColorThreshold()+tcu::RGBA(3,3,3,3);
612                 const bool                      compareOk               = tcu::bilinearCompare(m_testCtx.getLog(), "CompareResult", "Image comparison result", reference.getAccess(), rendered.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
613
614                 if (!compareOk)
615                 {
616                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
617                         return STOP;
618                 }
619         }
620
621         m_iterNdx += 1;
622         return (m_iterNdx < NUM_ITERATIONS) ? CONTINUE : STOP;
623 }
624
625 } // gls
626 } // deqp