1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 2.0 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Drawing tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es2sDrawTests.hpp" 25 #include "glsDrawTest.hpp" 26 #include "tcuRenderTarget.hpp" 27 #include "deRandom.hpp" 28 #include "deStringUtil.hpp" 29 #include "deUniquePtr.hpp" 30 31 #include "glwEnums.hpp" 32 33 #include <set> 34 35 namespace deqp 36 { 37 namespace gles2 38 { 39 namespace Stress 40 { 41 namespace 42 { 43 44 static void genBasicSpec (gls::DrawTestSpec& spec, gls::DrawTestSpec::DrawMethod method) 45 { 46 spec.apiType = glu::ApiType::es(2,0); 47 spec.primitive = gls::DrawTestSpec::PRIMITIVE_TRIANGLES; 48 spec.primitiveCount = 5; 49 spec.drawMethod = method; 50 spec.indexType = gls::DrawTestSpec::INDEXTYPE_LAST; 51 spec.indexPointerOffset = 0; 52 spec.indexStorage = gls::DrawTestSpec::STORAGE_LAST; 53 spec.first = 0; 54 spec.indexMin = 0; 55 spec.indexMax = 0; 56 spec.instanceCount = 1; 57 58 spec.attribs.resize(2); 59 60 spec.attribs[0].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; 61 spec.attribs[0].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; 62 spec.attribs[0].storage = gls::DrawTestSpec::STORAGE_BUFFER; 63 spec.attribs[0].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; 64 spec.attribs[0].componentCount = 4; 65 spec.attribs[0].offset = 0; 66 spec.attribs[0].stride = 0; 67 spec.attribs[0].normalize = false; 68 spec.attribs[0].instanceDivisor = 0; 69 spec.attribs[0].useDefaultAttribute = false; 70 71 spec.attribs[1].inputType = gls::DrawTestSpec::INPUTTYPE_FLOAT; 72 spec.attribs[1].outputType = gls::DrawTestSpec::OUTPUTTYPE_VEC2; 73 spec.attribs[1].storage = gls::DrawTestSpec::STORAGE_BUFFER; 74 spec.attribs[1].usage = gls::DrawTestSpec::USAGE_STATIC_DRAW; 75 spec.attribs[1].componentCount = 2; 76 spec.attribs[1].offset = 0; 77 spec.attribs[1].stride = 0; 78 spec.attribs[1].normalize = false; 79 spec.attribs[1].instanceDivisor = 0; 80 spec.attribs[1].useDefaultAttribute = false; 81 } 82 83 class IndexGroup : public TestCaseGroup 84 { 85 public: 86 IndexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod); 87 ~IndexGroup (void); 88 89 void init (void); 90 91 private: 92 gls::DrawTestSpec::DrawMethod m_method; 93 }; 94 95 IndexGroup::IndexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod) 96 : TestCaseGroup (context, name, descr) 97 , m_method (drawMethod) 98 { 99 } 100 101 IndexGroup::~IndexGroup (void) 102 { 103 } 104 105 void IndexGroup::init (void) 106 { 107 struct IndexTest 108 { 109 gls::DrawTestSpec::Storage storage; 110 gls::DrawTestSpec::IndexType type; 111 bool aligned; 112 int offsets[3]; 113 }; 114 115 const IndexTest tests[] = 116 { 117 { gls::DrawTestSpec::STORAGE_BUFFER, gls::DrawTestSpec::INDEXTYPE_SHORT, false, { 1, 3, -1 } }, 118 }; 119 120 gls::DrawTestSpec spec; 121 122 tcu::TestCaseGroup* unalignedBufferGroup = new tcu::TestCaseGroup(m_testCtx, "unaligned_buffer", "unaligned buffer"); 123 124 genBasicSpec(spec, m_method); 125 126 this->addChild(unalignedBufferGroup); 127 128 for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx) 129 { 130 const IndexTest& indexTest = tests[testNdx]; 131 132 DE_ASSERT(indexTest.storage != gls::DrawTestSpec::STORAGE_USER); 133 DE_ASSERT(!indexTest.aligned); 134 tcu::TestCaseGroup* group = unalignedBufferGroup; 135 136 const std::string name = std::string("index_") + gls::DrawTestSpec::indexTypeToString(indexTest.type); 137 const std::string desc = std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type) + " in " + gls::DrawTestSpec::storageToString(indexTest.storage); 138 de::MovePtr<gls::DrawTest> test (new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str())); 139 140 spec.indexType = indexTest.type; 141 spec.indexStorage = indexTest.storage; 142 143 for (int iterationNdx = 0; iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.offsets) && indexTest.offsets[iterationNdx] != -1; ++iterationNdx) 144 { 145 const std::string iterationDesc = std::string("offset ") + de::toString(indexTest.offsets[iterationNdx]); 146 spec.indexPointerOffset = indexTest.offsets[iterationNdx]; 147 test->addIteration(spec, iterationDesc.c_str()); 148 } 149 150 DE_ASSERT(spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET || 151 spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE); 152 group->addChild(test.release()); 153 } 154 } 155 156 class MethodGroup : public TestCaseGroup 157 { 158 public: 159 MethodGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod); 160 ~MethodGroup (void); 161 162 void init (void); 163 164 private: 165 gls::DrawTestSpec::DrawMethod m_method; 166 }; 167 168 MethodGroup::MethodGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod) 169 : TestCaseGroup (context, name, descr) 170 , m_method (drawMethod) 171 { 172 } 173 174 MethodGroup::~MethodGroup (void) 175 { 176 } 177 178 void MethodGroup::init (void) 179 { 180 const bool indexed = (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS) || (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED) || (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED); 181 182 DE_ASSERT(indexed); 183 DE_UNREF(indexed); 184 185 this->addChild(new IndexGroup(m_context, "indices", "Index tests", m_method)); 186 } 187 188 class RandomGroup : public TestCaseGroup 189 { 190 public: 191 RandomGroup (Context& context, const char* name, const char* descr); 192 ~RandomGroup (void); 193 194 void init (void); 195 }; 196 197 template <int SIZE> 198 struct UniformWeightArray 199 { 200 float weights[SIZE]; 201 202 UniformWeightArray (void) 203 { 204 for (int i=0; i<SIZE; ++i) 205 weights[i] = 1.0f; 206 } 207 }; 208 209 RandomGroup::RandomGroup (Context& context, const char* name, const char* descr) 210 : TestCaseGroup (context, name, descr) 211 { 212 } 213 214 RandomGroup::~RandomGroup (void) 215 { 216 } 217 218 void RandomGroup::init (void) 219 { 220 const int numAttempts = 100; 221 222 const int attribCounts[] = { 1, 2, 5 }; 223 const float attribWeights[] = { 30, 10, 1 }; 224 const int primitiveCounts[] = { 1, 5, 64 }; 225 const float primitiveCountWeights[] = { 20, 10, 1 }; 226 const int indexOffsets[] = { 0, 7, 13 }; 227 const float indexOffsetWeights[] = { 20, 20, 1 }; 228 const int firsts[] = { 0, 7, 13 }; 229 const float firstWeights[] = { 20, 20, 1 }; 230 const int offsets[] = { 0, 1, 5, 12 }; 231 const float offsetWeights[] = { 50, 10, 10, 10 }; 232 const int strides[] = { 0, 7, 16, 17 }; 233 const float strideWeights[] = { 50, 10, 10, 10 }; 234 235 gls::DrawTestSpec::Primitive primitives[] = 236 { 237 gls::DrawTestSpec::PRIMITIVE_POINTS, 238 gls::DrawTestSpec::PRIMITIVE_TRIANGLES, 239 gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN, 240 gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP, 241 gls::DrawTestSpec::PRIMITIVE_LINES, 242 gls::DrawTestSpec::PRIMITIVE_LINE_STRIP, 243 gls::DrawTestSpec::PRIMITIVE_LINE_LOOP 244 }; 245 const UniformWeightArray<DE_LENGTH_OF_ARRAY(primitives)> primitiveWeights; 246 247 gls::DrawTestSpec::DrawMethod drawMethods[] = 248 { 249 gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS, 250 gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS, 251 }; 252 const UniformWeightArray<DE_LENGTH_OF_ARRAY(drawMethods)> drawMethodWeights; 253 254 gls::DrawTestSpec::IndexType indexTypes[] = 255 { 256 gls::DrawTestSpec::INDEXTYPE_BYTE, 257 gls::DrawTestSpec::INDEXTYPE_SHORT, 258 }; 259 const UniformWeightArray<DE_LENGTH_OF_ARRAY(indexTypes)> indexTypeWeights; 260 261 gls::DrawTestSpec::Storage storages[] = 262 { 263 gls::DrawTestSpec::STORAGE_USER, 264 gls::DrawTestSpec::STORAGE_BUFFER, 265 }; 266 const UniformWeightArray<DE_LENGTH_OF_ARRAY(storages)> storageWeights; 267 268 gls::DrawTestSpec::InputType inputTypes[] = 269 { 270 gls::DrawTestSpec::INPUTTYPE_FLOAT, 271 gls::DrawTestSpec::INPUTTYPE_FIXED, 272 gls::DrawTestSpec::INPUTTYPE_BYTE, 273 gls::DrawTestSpec::INPUTTYPE_SHORT, 274 gls::DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE, 275 gls::DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT 276 }; 277 const UniformWeightArray<DE_LENGTH_OF_ARRAY(inputTypes)> inputTypeWeights; 278 279 gls::DrawTestSpec::OutputType outputTypes[] = 280 { 281 gls::DrawTestSpec::OUTPUTTYPE_FLOAT, 282 gls::DrawTestSpec::OUTPUTTYPE_VEC2, 283 gls::DrawTestSpec::OUTPUTTYPE_VEC3, 284 gls::DrawTestSpec::OUTPUTTYPE_VEC4, 285 }; 286 const UniformWeightArray<DE_LENGTH_OF_ARRAY(outputTypes)> outputTypeWeights; 287 288 gls::DrawTestSpec::Usage usages[] = 289 { 290 gls::DrawTestSpec::USAGE_STATIC_DRAW, 291 gls::DrawTestSpec::USAGE_DYNAMIC_DRAW, 292 gls::DrawTestSpec::USAGE_STREAM_DRAW, 293 }; 294 const UniformWeightArray<DE_LENGTH_OF_ARRAY(usages)> usageWeights; 295 296 const deUint32 blacklistedCases[]= 297 { 298 3153, //!< extremely narrow triangle, results depend on sample positions 299 }; 300 301 std::set<deUint32> insertedHashes; 302 size_t insertedCount = 0; 303 304 for (int ndx = 0; ndx < numAttempts; ++ndx) 305 { 306 de::Random random(0xc551393 + ndx); // random does not depend on previous cases 307 308 int attributeCount = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(attribCounts), DE_ARRAY_END(attribCounts), attribWeights); 309 gls::DrawTestSpec spec; 310 311 spec.apiType = glu::ApiType::es(2,0); 312 spec.primitive = random.chooseWeighted<gls::DrawTestSpec::Primitive> (DE_ARRAY_BEGIN(primitives), DE_ARRAY_END(primitives), primitiveWeights.weights); 313 spec.primitiveCount = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(primitiveCounts), DE_ARRAY_END(primitiveCounts), primitiveCountWeights); 314 spec.drawMethod = random.chooseWeighted<gls::DrawTestSpec::DrawMethod> (DE_ARRAY_BEGIN(drawMethods), DE_ARRAY_END(drawMethods), drawMethodWeights.weights); 315 spec.indexType = random.chooseWeighted<gls::DrawTestSpec::IndexType> (DE_ARRAY_BEGIN(indexTypes), DE_ARRAY_END(indexTypes), indexTypeWeights.weights); 316 spec.indexPointerOffset = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(indexOffsets), DE_ARRAY_END(indexOffsets), indexOffsetWeights); 317 spec.indexStorage = random.chooseWeighted<gls::DrawTestSpec::Storage> (DE_ARRAY_BEGIN(storages), DE_ARRAY_END(storages), storageWeights.weights); 318 spec.first = random.chooseWeighted<int, const int*, const float*> (DE_ARRAY_BEGIN(firsts), DE_ARRAY_END(firsts), firstWeights); 319 spec.indexMin = 0; 320 spec.indexMax = 0; 321 spec.instanceCount = 0; 322 323 // check spec is legal 324 if (!spec.valid()) 325 continue; 326 327 for (int attrNdx = 0; attrNdx < attributeCount;) 328 { 329 bool valid; 330 gls::DrawTestSpec::AttributeSpec attribSpec; 331 332 attribSpec.inputType = random.chooseWeighted<gls::DrawTestSpec::InputType> (DE_ARRAY_BEGIN(inputTypes), DE_ARRAY_END(inputTypes), inputTypeWeights.weights); 333 attribSpec.outputType = random.chooseWeighted<gls::DrawTestSpec::OutputType> (DE_ARRAY_BEGIN(outputTypes), DE_ARRAY_END(outputTypes), outputTypeWeights.weights); 334 attribSpec.storage = random.chooseWeighted<gls::DrawTestSpec::Storage> (DE_ARRAY_BEGIN(storages), DE_ARRAY_END(storages), storageWeights.weights); 335 attribSpec.usage = random.chooseWeighted<gls::DrawTestSpec::Usage> (DE_ARRAY_BEGIN(usages), DE_ARRAY_END(usages), usageWeights.weights); 336 attribSpec.componentCount = random.getInt(1, 4); 337 attribSpec.offset = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), offsetWeights); 338 attribSpec.stride = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(strides), DE_ARRAY_END(strides), strideWeights); 339 attribSpec.normalize = random.getBool(); 340 attribSpec.instanceDivisor = 0; 341 attribSpec.useDefaultAttribute = random.getBool(); 342 343 // check spec is legal 344 valid = attribSpec.valid(spec.apiType); 345 346 // we do not want interleaved elements. (Might result in some weird floating point values) 347 if (attribSpec.stride && attribSpec.componentCount * gls::DrawTestSpec::inputTypeSize(attribSpec.inputType) > attribSpec.stride) 348 valid = false; 349 350 // try again if not valid 351 if (valid) 352 { 353 spec.attribs.push_back(attribSpec); 354 ++attrNdx; 355 } 356 } 357 358 // Do not collapse all vertex positions to a single positions 359 if (spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS) 360 spec.attribs[0].instanceDivisor = 0; 361 362 // Is render result meaningful? 363 { 364 // Only one vertex 365 if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && spec.indexMin == spec.indexMax && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS) 366 continue; 367 if (spec.attribs[0].useDefaultAttribute && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS) 368 continue; 369 370 // Triangle only on one axis 371 if (spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLES || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP) 372 { 373 if (spec.attribs[0].componentCount == 1) 374 continue; 375 if (spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_FLOAT || spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_INT || spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_UINT) 376 continue; 377 if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && (spec.indexMax - spec.indexMin) < 2) 378 continue; 379 } 380 } 381 382 // Add case 383 { 384 deUint32 hash = spec.hash(); 385 for (int attrNdx = 0; attrNdx < attributeCount; ++attrNdx) 386 hash = (hash << 2) ^ (deUint32)spec.attribs[attrNdx].hash(); 387 388 if (insertedHashes.find(hash) == insertedHashes.end() && 389 std::find(DE_ARRAY_BEGIN(blacklistedCases), DE_ARRAY_END(blacklistedCases), hash) == DE_ARRAY_END(blacklistedCases)) 390 { 391 // Only unaligned cases 392 if (spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET || 393 spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE) 394 this->addChild(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), spec, de::toString(insertedCount).c_str(), spec.getDesc().c_str())); 395 insertedHashes.insert(hash); 396 397 ++insertedCount; 398 } 399 } 400 } 401 } 402 403 } // anonymous 404 405 DrawTests::DrawTests (Context& context) 406 : TestCaseGroup(context, "draw", "Drawing tests") 407 { 408 } 409 410 DrawTests::~DrawTests (void) 411 { 412 } 413 414 void DrawTests::init (void) 415 { 416 tcu::TestCaseGroup* const unalignedGroup = new tcu::TestCaseGroup(m_testCtx, "unaligned_data", "Test with unaligned data"); 417 418 addChild(unalignedGroup); 419 420 // .unaligned_data 421 { 422 const gls::DrawTestSpec::DrawMethod basicMethods[] = 423 { 424 // gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS, 425 gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS, 426 }; 427 428 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(basicMethods); ++ndx) 429 { 430 std::string name = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]); 431 std::string desc = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]); 432 433 unalignedGroup->addChild(new MethodGroup(m_context, name.c_str(), desc.c_str(), basicMethods[ndx])); 434 } 435 436 // Random 437 438 unalignedGroup->addChild(new RandomGroup(m_context, "random", "random draw commands.")); 439 } 440 441 } 442 443 } // Stress 444 } // gles2 445 } // deqp 446