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