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 ¶ms)
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