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 53namespace deqp 54{ 55namespace gls 56{ 57 58using std::vector; 59using std::string; 60using tcu::Vec2; 61using tcu::Vec4; 62using tcu::IVec2; 63using tcu::IVec4; 64 65using gls::InteractionTestUtil::RenderState; 66using gls::InteractionTestUtil::StencilState; 67 68enum 69{ 70 NUM_ITERATIONS = 5, 71 NUM_COMMANDS_PER_ITERATION = 5, 72 VIEWPORT_WIDTH = 64, 73 VIEWPORT_HEIGHT = 64 74}; 75 76namespace 77{ 78 79static 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 105class VertexDataStorage 106{ 107public: 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 119private: 120 std::vector<deUint8> m_data; 121 std::vector<glu::VertexArrayBinding> m_layout; 122}; 123 124VertexDataStorage::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 131static 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 142template<int Size> 143static 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 156template<int Size> 157static 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 167struct Quad 168{ 169 tcu::IVec2 posA; 170 tcu::IVec2 posB; 171}; 172 173struct RenderCommand 174{ 175 Quad quad; 176 float depth; 177 RenderState state; 178 179 RenderCommand (void) : depth(0.0f) {} 180}; 181 182static 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 210static 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 217static 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 224static 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 282static 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 305static 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 311static 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 328void 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 365static 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 376static 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 413static 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 423struct 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 437FragOpInteractionCase::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 453FragOpInteractionCase::~FragOpInteractionCase (void) 454{ 455 FragOpInteractionCase::deinit(); 456} 457 458void 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 497void 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 509FragOpInteractionCase::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 627