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 Buffer data upload tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es2fBufferWriteTests.hpp"
25 #include "es2fBufferTestUtil.hpp"
26 #include "tcuTestLog.hpp"
27 #include "gluStrUtil.hpp"
28 #include "deMemory.h"
29 #include "deString.h"
30 #include "deRandom.hpp"
31 #include "deStringUtil.hpp"
32 #include "deMath.h"
33 #include "glwEnums.hpp"
34 #include "glwFunctions.hpp"
35
36 #include <algorithm>
37 #include <list>
38
39 using std::set;
40 using std::string;
41 using std::vector;
42 using tcu::IVec2;
43 using tcu::TestLog;
44
45 namespace deqp
46 {
47 namespace gles2
48 {
49 namespace Functional
50 {
51
52 using namespace BufferTestUtil;
53
54 struct DataStoreSpec
55 {
DataStoreSpecdeqp::gles2::Functional::DataStoreSpec56 DataStoreSpec(void) : target(0), usage(0), size(0)
57 {
58 }
59
DataStoreSpecdeqp::gles2::Functional::DataStoreSpec60 DataStoreSpec(uint32_t target_, uint32_t usage_, int size_) : target(target_), usage(usage_), size(size_)
61 {
62 }
63
64 uint32_t target;
65 uint32_t usage;
66 int size;
67 };
68
69 struct DataStoreSpecVecBuilder
70 {
71 std::vector<DataStoreSpec> &list;
72
DataStoreSpecVecBuilderdeqp::gles2::Functional::DataStoreSpecVecBuilder73 DataStoreSpecVecBuilder(std::vector<DataStoreSpec> &list_) : list(list_)
74 {
75 }
76
operator <<deqp::gles2::Functional::DataStoreSpecVecBuilder77 DataStoreSpecVecBuilder &operator<<(const DataStoreSpec &spec)
78 {
79 list.push_back(spec);
80 return *this;
81 }
82 };
83
84 struct RangeVecBuilder
85 {
86 std::vector<tcu::IVec2> &list;
87
RangeVecBuilderdeqp::gles2::Functional::RangeVecBuilder88 RangeVecBuilder(std::vector<tcu::IVec2> &list_) : list(list_)
89 {
90 }
91
operator <<deqp::gles2::Functional::RangeVecBuilder92 RangeVecBuilder &operator<<(const tcu::IVec2 &vec)
93 {
94 list.push_back(vec);
95 return *this;
96 }
97 };
98
99 template <typename Iterator>
isRangeListValid(Iterator begin,Iterator end)100 static bool isRangeListValid(Iterator begin, Iterator end)
101 {
102 if (begin != end)
103 {
104 // Fetch first.
105 tcu::IVec2 prev = *begin;
106 ++begin;
107
108 for (; begin != end; ++begin)
109 {
110 tcu::IVec2 cur = *begin;
111 if (cur.x() <= prev.x() || cur.x() <= prev.x() + prev.y())
112 return false;
113 prev = cur;
114 }
115 }
116
117 return true;
118 }
119
rangesIntersect(const tcu::IVec2 & a,const tcu::IVec2 & b)120 inline bool rangesIntersect(const tcu::IVec2 &a, const tcu::IVec2 &b)
121 {
122 return de::inRange(a.x(), b.x(), b.x() + b.y()) || de::inRange(a.x() + a.y(), b.x(), b.x() + b.y()) ||
123 de::inRange(b.x(), a.x(), a.x() + a.y()) || de::inRange(b.x() + b.y(), a.x(), a.x() + a.y());
124 }
125
unionRanges(const tcu::IVec2 & a,const tcu::IVec2 & b)126 inline tcu::IVec2 unionRanges(const tcu::IVec2 &a, const tcu::IVec2 &b)
127 {
128 DE_ASSERT(rangesIntersect(a, b));
129
130 int start = de::min(a.x(), b.x());
131 int end = de::max(a.x() + a.y(), b.x() + b.y());
132
133 return tcu::IVec2(start, end - start);
134 }
135
136 //! Updates range list (start, len) with a new range.
addRangeToList(const std::vector<tcu::IVec2> & oldList,const tcu::IVec2 & newRange)137 std::vector<tcu::IVec2> addRangeToList(const std::vector<tcu::IVec2> &oldList, const tcu::IVec2 &newRange)
138 {
139 DE_ASSERT(newRange.y() > 0);
140
141 std::vector<tcu::IVec2> newList;
142 std::vector<tcu::IVec2>::const_iterator oldListIter = oldList.begin();
143
144 // Append ranges that end before the new range.
145 for (; oldListIter != oldList.end() && oldListIter->x() + oldListIter->y() < newRange.x(); ++oldListIter)
146 newList.push_back(*oldListIter);
147
148 // Join any ranges that intersect new range
149 {
150 tcu::IVec2 curRange = newRange;
151 while (oldListIter != oldList.end() && rangesIntersect(curRange, *oldListIter))
152 {
153 curRange = unionRanges(curRange, *oldListIter);
154 ++oldListIter;
155 }
156
157 newList.push_back(curRange);
158 }
159
160 // Append remaining ranges.
161 for (; oldListIter != oldList.end(); oldListIter++)
162 newList.push_back(*oldListIter);
163
164 DE_ASSERT(isRangeListValid(newList.begin(), newList.end()));
165
166 return newList;
167 }
168
169 class BasicBufferDataCase : public BufferCase
170 {
171 public:
BasicBufferDataCase(Context & context,const char * name,const char * desc,uint32_t target,uint32_t usage,int size,VerifyType verify)172 BasicBufferDataCase(Context &context, const char *name, const char *desc, uint32_t target, uint32_t usage, int size,
173 VerifyType verify)
174 : BufferCase(context, name, desc)
175 , m_target(target)
176 , m_usage(usage)
177 , m_size(size)
178 , m_verify(verify)
179 {
180 }
181
iterate(void)182 IterateResult iterate(void)
183 {
184 const uint32_t dataSeed = deStringHash(getName()) ^ 0x125;
185 BufferVerifier verifier(m_context, m_verify);
186 ReferenceBuffer refBuf;
187 bool isOk = false;
188
189 refBuf.setSize(m_size);
190 fillWithRandomBytes(refBuf.getPtr(), m_size, dataSeed);
191
192 uint32_t buf = genBuffer();
193 glBindBuffer(m_target, buf);
194 glBufferData(m_target, m_size, refBuf.getPtr(), m_usage);
195
196 checkError();
197
198 isOk = verifier.verify(buf, refBuf.getPtr(), 0, m_size);
199
200 deleteBuffer(buf);
201
202 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
203 isOk ? "Pass" : "Buffer verification failed");
204 return STOP;
205 }
206
207 private:
208 uint32_t m_target;
209 uint32_t m_usage;
210 int m_size;
211 VerifyType m_verify;
212 };
213
214 class RecreateBufferDataStoreCase : public BufferCase
215 {
216 public:
RecreateBufferDataStoreCase(Context & context,const char * name,const char * desc,const DataStoreSpec * specs,int numSpecs,VerifyType verify)217 RecreateBufferDataStoreCase(Context &context, const char *name, const char *desc, const DataStoreSpec *specs,
218 int numSpecs, VerifyType verify)
219 : BufferCase(context, name, desc)
220 , m_specs(specs, specs + numSpecs)
221 , m_verify(verify)
222 {
223 }
224
iterate(void)225 IterateResult iterate(void)
226 {
227 const uint32_t baseSeed = deStringHash(getName()) ^ 0xbeef;
228 BufferVerifier verifier(m_context, m_verify);
229 ReferenceBuffer refBuf;
230 const uint32_t buf = genBuffer();
231
232 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
233
234 for (vector<DataStoreSpec>::const_iterator spec = m_specs.begin(); spec != m_specs.end(); spec++)
235 {
236 bool iterOk = false;
237
238 refBuf.setSize(spec->size);
239 fillWithRandomBytes(refBuf.getPtr(), spec->size,
240 baseSeed ^ deInt32Hash(spec->size + spec->target + spec->usage));
241
242 glBindBuffer(spec->target, buf);
243 glBufferData(spec->target, spec->size, refBuf.getPtr(), spec->usage);
244
245 checkError();
246
247 iterOk = verifier.verify(buf, refBuf.getPtr(), 0, spec->size);
248
249 if (!iterOk)
250 {
251 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
252 break;
253 }
254 }
255
256 deleteBuffer(buf);
257 return STOP;
258 }
259
260 private:
261 std::vector<DataStoreSpec> m_specs;
262 VerifyType m_verify;
263 };
264
265 class BasicBufferSubDataCase : public BufferCase
266 {
267 public:
BasicBufferSubDataCase(Context & context,const char * name,const char * desc,uint32_t target,uint32_t usage,int size,int subDataOffs,int subDataSize,VerifyType verify)268 BasicBufferSubDataCase(Context &context, const char *name, const char *desc, uint32_t target, uint32_t usage,
269 int size, int subDataOffs, int subDataSize, VerifyType verify)
270 : BufferCase(context, name, desc)
271 , m_target(target)
272 , m_usage(usage)
273 , m_size(size)
274 , m_subDataOffs(subDataOffs)
275 , m_subDataSize(subDataSize)
276 , m_verify(verify)
277 {
278 DE_ASSERT(de::inBounds(subDataOffs, 0, size) && de::inRange(subDataOffs + subDataSize, 0, size));
279 }
280
iterate(void)281 IterateResult iterate(void)
282 {
283 const uint32_t dataSeed = deStringHash(getName());
284 BufferVerifier verifier(m_context, m_verify);
285 ReferenceBuffer refBuf;
286 bool isOk = false;
287
288 refBuf.setSize(m_size);
289
290 uint32_t buf = genBuffer();
291 glBindBuffer(m_target, buf);
292
293 // Initialize with glBufferData()
294 fillWithRandomBytes(refBuf.getPtr(), m_size, dataSeed ^ 0x80354f);
295 glBufferData(m_target, m_size, refBuf.getPtr(), m_usage);
296 checkError();
297
298 // Re-specify part of buffer
299 fillWithRandomBytes(refBuf.getPtr() + m_subDataOffs, m_subDataSize, dataSeed ^ 0xfac425c);
300 glBufferSubData(m_target, m_subDataOffs, m_subDataSize, refBuf.getPtr() + m_subDataOffs);
301
302 isOk = verifier.verify(buf, refBuf.getPtr(), 0, m_size);
303
304 deleteBuffer(buf);
305
306 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
307 isOk ? "Pass" : "Buffer verification failed");
308 return STOP;
309 }
310
311 private:
312 uint32_t m_target;
313 uint32_t m_usage;
314 int m_size;
315 int m_subDataOffs;
316 int m_subDataSize;
317 VerifyType m_verify;
318 };
319
320 class SubDataToUndefinedCase : public BufferCase
321 {
322 public:
SubDataToUndefinedCase(Context & context,const char * name,const char * desc,uint32_t target,uint32_t usage,int size,const tcu::IVec2 * ranges,int numRanges,VerifyType verify)323 SubDataToUndefinedCase(Context &context, const char *name, const char *desc, uint32_t target, uint32_t usage,
324 int size, const tcu::IVec2 *ranges, int numRanges, VerifyType verify)
325 : BufferCase(context, name, desc)
326 , m_target(target)
327 , m_usage(usage)
328 , m_size(size)
329 , m_ranges(ranges, ranges + numRanges)
330 , m_verify(verify)
331 {
332 }
333
iterate(void)334 IterateResult iterate(void)
335 {
336 const uint32_t dataSeed = deStringHash(getName());
337 BufferVerifier verifier(m_context, m_verify);
338 ReferenceBuffer refBuf;
339 bool isOk = true;
340 std::vector<tcu::IVec2> definedRanges;
341
342 refBuf.setSize(m_size);
343
344 uint32_t buf = genBuffer();
345 glBindBuffer(m_target, buf);
346
347 // Initialize storage with glBufferData()
348 glBufferData(m_target, m_size, DE_NULL, m_usage);
349 checkError();
350
351 // Fill specified ranges with glBufferSubData()
352 for (vector<tcu::IVec2>::const_iterator range = m_ranges.begin(); range != m_ranges.end(); range++)
353 {
354 fillWithRandomBytes(refBuf.getPtr() + range->x(), range->y(),
355 dataSeed ^ deInt32Hash(range->x() + range->y()));
356 glBufferSubData(m_target, range->x(), range->y(), refBuf.getPtr() + range->x());
357
358 // Mark range as defined
359 definedRanges = addRangeToList(definedRanges, *range);
360 }
361
362 // Verify defined parts
363 for (vector<tcu::IVec2>::const_iterator range = definedRanges.begin(); range != definedRanges.end(); range++)
364 {
365 if (!verifier.verify(buf, refBuf.getPtr(), range->x(), range->y()))
366 isOk = false;
367 }
368
369 deleteBuffer(buf);
370
371 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
372 isOk ? "Pass" : "Buffer verification failed");
373 return STOP;
374 }
375
376 private:
377 uint32_t m_target;
378 uint32_t m_usage;
379 int m_size;
380 std::vector<tcu::IVec2> m_ranges;
381 VerifyType m_verify;
382 };
383
384 class RandomBufferWriteCase : public BufferCase
385 {
386 public:
RandomBufferWriteCase(Context & context,const char * name,const char * desc,uint32_t seed)387 RandomBufferWriteCase(Context &context, const char *name, const char *desc, uint32_t seed)
388 : BufferCase(context, name, desc)
389 , m_seed(seed)
390 , m_verifier(DE_NULL)
391 , m_buffer(0)
392 , m_curSize(0)
393 , m_iterNdx(0)
394 {
395 }
396
~RandomBufferWriteCase(void)397 ~RandomBufferWriteCase(void)
398 {
399 delete m_verifier;
400 }
401
init(void)402 void init(void)
403 {
404 BufferCase::init();
405
406 m_iterNdx = 0;
407 m_buffer = genBuffer();
408 m_curSize = 0;
409 m_verifier = new BufferVerifier(m_context, VERIFY_AS_VERTEX_ARRAY);
410
411 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
412 }
413
deinit(void)414 void deinit(void)
415 {
416 deleteBuffer(m_buffer);
417 m_refBuffer.setSize(0);
418
419 delete m_verifier;
420 m_verifier = DE_NULL;
421
422 BufferCase::deinit();
423 }
424
iterate(void)425 IterateResult iterate(void)
426 {
427 // Parameters.
428 const int numIterations = 5;
429 const int uploadsPerIteration = 7;
430 const int minSize = 12;
431 const int maxSize = 32 * 1024;
432 const float respecifyProbability = 0.07f;
433 const float respecifyDataProbability = 0.2f;
434
435 static const uint32_t bufferTargets[] = {GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER};
436
437 static const uint32_t usageHints[] = {
438 GL_STREAM_DRAW,
439 GL_STATIC_DRAW,
440 GL_DYNAMIC_DRAW,
441 };
442
443 bool iterOk = true;
444 uint32_t curBoundTarget = GL_NONE;
445 de::Random rnd(m_seed ^ deInt32Hash(m_iterNdx) ^ 0xacf92e);
446
447 m_testCtx.getLog() << TestLog::Section(string("Iteration") + de::toString(m_iterNdx + 1),
448 string("Iteration ") + de::toString(m_iterNdx + 1) + " / " +
449 de::toString(numIterations));
450
451 for (int uploadNdx = 0; uploadNdx < uploadsPerIteration; uploadNdx++)
452 {
453 const uint32_t target = bufferTargets[rnd.getInt(0, DE_LENGTH_OF_ARRAY(bufferTargets) - 1)];
454 const bool respecify = m_curSize == 0 || rnd.getFloat() < respecifyProbability;
455
456 if (target != curBoundTarget)
457 {
458 glBindBuffer(target, m_buffer);
459 curBoundTarget = target;
460 }
461
462 if (respecify)
463 {
464 const int size = rnd.getInt(minSize, maxSize);
465 const uint32_t hint = usageHints[rnd.getInt(0, DE_LENGTH_OF_ARRAY(usageHints) - 1)];
466 const bool fillWithData = rnd.getFloat() < respecifyDataProbability;
467
468 m_refBuffer.setSize(size);
469 if (fillWithData)
470 fillWithRandomBytes(m_refBuffer.getPtr(), size, rnd.getUint32());
471
472 glBufferData(target, size, fillWithData ? m_refBuffer.getPtr() : DE_NULL, hint);
473
474 m_validRanges.clear();
475 if (fillWithData)
476 m_validRanges.push_back(tcu::IVec2(0, size));
477
478 m_curSize = size;
479 }
480 else
481 {
482 // \note Non-uniform size distribution.
483 const int size =
484 de::clamp(deRoundFloatToInt32((float)m_curSize * deFloatPow(rnd.getFloat(0.0f, 0.7f), 3.0f)),
485 minSize, m_curSize);
486 const int offset = rnd.getInt(0, m_curSize - size);
487
488 fillWithRandomBytes(m_refBuffer.getPtr() + offset, size, rnd.getUint32());
489 glBufferSubData(target, offset, size, m_refBuffer.getPtr() + offset);
490
491 m_validRanges = addRangeToList(m_validRanges, tcu::IVec2(offset, size));
492 }
493 }
494
495 // Check error.
496 {
497 uint32_t err = glGetError();
498 if (err != GL_NO_ERROR)
499 throw tcu::TestError(string("Got ") + glu::getErrorStr(err).toString());
500 }
501
502 // Verify valid ranges.
503 for (vector<IVec2>::const_iterator range = m_validRanges.begin(); range != m_validRanges.end(); range++)
504 {
505 if (!m_verifier->verify(m_buffer, m_refBuffer.getPtr(), range->x(), range->y()))
506 {
507 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Buffer verification failed");
508 iterOk = false;
509 break;
510 }
511 }
512
513 m_testCtx.getLog() << TestLog::EndSection;
514
515 DE_ASSERT(iterOk || m_testCtx.getTestResult() != QP_TEST_RESULT_PASS);
516
517 m_iterNdx += 1;
518 return (iterOk && m_iterNdx < numIterations) ? CONTINUE : STOP;
519 }
520
521 private:
522 uint32_t m_seed;
523
524 BufferVerifier *m_verifier;
525 uint32_t m_buffer;
526 ReferenceBuffer m_refBuffer;
527 std::vector<tcu::IVec2> m_validRanges;
528 int m_curSize;
529 int m_iterNdx;
530 };
531
BufferWriteTests(Context & context)532 BufferWriteTests::BufferWriteTests(Context &context) : TestCaseGroup(context, "write", "Buffer data upload tests")
533 {
534 }
535
~BufferWriteTests(void)536 BufferWriteTests::~BufferWriteTests(void)
537 {
538 }
539
init(void)540 void BufferWriteTests::init(void)
541 {
542 static const uint32_t bufferTargets[] = {GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER};
543
544 static const uint32_t usageHints[] = {GL_STREAM_DRAW, GL_STATIC_DRAW, GL_DYNAMIC_DRAW};
545
546 static const struct
547 {
548 const char *name;
549 VerifyType verify;
550 } verifyTypes[] = {{"vertex_array", VERIFY_AS_VERTEX_ARRAY}, {"index_array", VERIFY_AS_INDEX_ARRAY}};
551
552 // .basic
553 {
554 tcu::TestCaseGroup *const basicGroup =
555 new tcu::TestCaseGroup(m_testCtx, "basic", "Basic upload with glBufferData()");
556 addChild(basicGroup);
557
558 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(bufferTargets); targetNdx++)
559 {
560 for (int usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(usageHints); usageNdx++)
561 {
562 const uint32_t target = bufferTargets[targetNdx];
563 const uint32_t usage = usageHints[usageNdx];
564 const int size = 1020;
565 const VerifyType verify = VERIFY_AS_VERTEX_ARRAY;
566 const string name = string(getBufferTargetName(target)) + "_" + getUsageHintName(usage);
567
568 basicGroup->addChild(new BasicBufferDataCase(m_context, name.c_str(), "", target, usage, size, verify));
569 }
570 }
571 }
572
573 // .use
574 {
575 tcu::TestCaseGroup *const useGroup = new tcu::TestCaseGroup(m_testCtx, "use", "Buffer uses");
576 addChild(useGroup);
577
578 for (int verifyNdx = 0; verifyNdx < DE_LENGTH_OF_ARRAY(verifyTypes); verifyNdx++)
579 {
580 tcu::TestCaseGroup *const verifyGroup = new tcu::TestCaseGroup(m_testCtx, verifyTypes[verifyNdx].name, "");
581 useGroup->addChild(verifyGroup);
582
583 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(bufferTargets); targetNdx++)
584 {
585 const uint32_t target = bufferTargets[targetNdx];
586 const uint32_t usage = GL_STATIC_DRAW;
587 const int size = 763;
588 const VerifyType verify = verifyTypes[verifyNdx].verify;
589 const string name = getBufferTargetName(target);
590
591 verifyGroup->addChild(
592 new BasicBufferDataCase(m_context, name.c_str(), "", target, usage, size, verify));
593 }
594 }
595 }
596
597 // .recreate_store
598 {
599 tcu::TestCaseGroup *const recreateStoreGroup =
600 new tcu::TestCaseGroup(m_testCtx, "recreate_store", "Data store recreate using glBufferData()");
601 addChild(recreateStoreGroup);
602
603 #define RECREATE_STORE_CASE(NAME, DESC, SPECLIST) \
604 do \
605 { \
606 std::vector<DataStoreSpec> specs; \
607 DataStoreSpecVecBuilder builder(specs); \
608 builder SPECLIST; \
609 recreateStoreGroup->addChild(new RecreateBufferDataStoreCase(m_context, #NAME, DESC, &specs[0], \
610 (int)specs.size(), VERIFY_AS_VERTEX_ARRAY)); \
611 } while (false)
612
613 RECREATE_STORE_CASE(identical_1, "Recreate with identical parameters",
614 << DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996)
615 << DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996)
616 << DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996));
617
618 RECREATE_STORE_CASE(identical_2, "Recreate with identical parameters",
619 << DataStoreSpec(GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, 72)
620 << DataStoreSpec(GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, 72)
621 << DataStoreSpec(GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, 72));
622
623 RECREATE_STORE_CASE(different_target_1, "Recreate with different target",
624 << DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 504)
625 << DataStoreSpec(GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, 504));
626
627 RECREATE_STORE_CASE(different_target_2, "Recreate with different target",
628 << DataStoreSpec(GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, 716)
629 << DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 716)
630 << DataStoreSpec(GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, 716));
631
632 RECREATE_STORE_CASE(different_usage, "Recreate with different usage",
633 << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 1644)
634 << DataStoreSpec(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, 1644)
635 << DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 1644)
636 << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 1644));
637
638 RECREATE_STORE_CASE(different_size, "Recreate with different size",
639 << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 1024)
640 << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 12)
641 << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 3327)
642 << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 92)
643 << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 12379)
644 << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 571));
645
646 #undef RECREATE_STORE_CASE
647
648 // Random cases.
649 {
650 const int numRandomCases = 4;
651 const int numUploadsPerCase = 10;
652 const int minSize = 12;
653 const int maxSize = 65536;
654 const VerifyType verify = VERIFY_AS_VERTEX_ARRAY;
655 de::Random rnd(23921);
656
657 for (int caseNdx = 0; caseNdx < numRandomCases; caseNdx++)
658 {
659 vector<DataStoreSpec> specs(numUploadsPerCase);
660
661 for (vector<DataStoreSpec>::iterator spec = specs.begin(); spec != specs.end(); spec++)
662 {
663 spec->target = bufferTargets[rnd.getInt(0, DE_LENGTH_OF_ARRAY(bufferTargets) - 1)];
664 spec->usage = usageHints[rnd.getInt(0, DE_LENGTH_OF_ARRAY(usageHints) - 1)];
665 spec->size = rnd.getInt(minSize, maxSize);
666 }
667
668 recreateStoreGroup->addChild(
669 new RecreateBufferDataStoreCase(m_context, (string("random_") + de::toString(caseNdx + 1)).c_str(),
670 "", &specs[0], (int)specs.size(), verify));
671 }
672 }
673 }
674
675 // .basic_subdata
676 {
677 tcu::TestCaseGroup *const basicGroup =
678 new tcu::TestCaseGroup(m_testCtx, "basic_subdata", "Basic glBufferSubData() usage");
679 addChild(basicGroup);
680
681 for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(bufferTargets); targetNdx++)
682 {
683 for (int usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(usageHints); usageNdx++)
684 {
685 const uint32_t target = bufferTargets[targetNdx];
686 const uint32_t usage = usageHints[usageNdx];
687 const int size = 1020;
688 const VerifyType verify = VERIFY_AS_VERTEX_ARRAY;
689 const string name = string(getBufferTargetName(target)) + "_" + getUsageHintName(usage);
690
691 basicGroup->addChild(new BasicBufferDataCase(m_context, name.c_str(), "", target, usage, size, verify));
692 }
693 }
694 }
695
696 // .partial_specify
697 {
698 tcu::TestCaseGroup *const partialSpecifyGroup = new tcu::TestCaseGroup(
699 m_testCtx, "partial_specify", "Partial buffer data specification with glBufferSubData()");
700 addChild(partialSpecifyGroup);
701
702 #define PARTIAL_SPECIFY_CASE(NAME, DESC, TARGET, USAGE, SIZE, RANGELIST) \
703 do \
704 { \
705 std::vector<tcu::IVec2> ranges; \
706 RangeVecBuilder builder(ranges); \
707 builder RANGELIST; \
708 partialSpecifyGroup->addChild(new SubDataToUndefinedCase( \
709 m_context, #NAME, DESC, TARGET, USAGE, SIZE, &ranges[0], (int)ranges.size(), VERIFY_AS_VERTEX_ARRAY)); \
710 } while (false)
711
712 PARTIAL_SPECIFY_CASE(whole_1, "Whole buffer specification with single glBufferSubData()", GL_ARRAY_BUFFER,
713 GL_STATIC_DRAW, 996, << IVec2(0, 996));
714 PARTIAL_SPECIFY_CASE(whole_2, "Whole buffer specification with two calls", GL_ELEMENT_ARRAY_BUFFER,
715 GL_DYNAMIC_DRAW, 1728, << IVec2(729, 999) << IVec2(0, 729));
716 PARTIAL_SPECIFY_CASE(whole_3, "Whole buffer specification with three calls", GL_ARRAY_BUFFER, GL_STREAM_DRAW,
717 1944, << IVec2(0, 421) << IVec2(1421, 523) << IVec2(421, 1000));
718 PARTIAL_SPECIFY_CASE(whole_4, "Whole buffer specification with three calls", GL_ELEMENT_ARRAY_BUFFER,
719 GL_STREAM_DRAW, 1200, << IVec2(0, 500) << IVec2(429, 200) << IVec2(513, 687));
720
721 PARTIAL_SPECIFY_CASE(low_1, "Low part of buffer specified with single call", GL_ELEMENT_ARRAY_BUFFER,
722 GL_STATIC_DRAW, 1000, << IVec2(0, 513));
723 PARTIAL_SPECIFY_CASE(low_2, "Low part of buffer specified with two calls", GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996,
724 << IVec2(0, 98) << IVec2(98, 511));
725 PARTIAL_SPECIFY_CASE(low_3, "Low part of buffer specified with two calls", GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW,
726 1200, << IVec2(0, 591) << IVec2(371, 400));
727
728 PARTIAL_SPECIFY_CASE(high_1, "High part of buffer specified with single call", GL_ELEMENT_ARRAY_BUFFER,
729 GL_STATIC_DRAW, 1000, << IVec2(500, 500));
730 PARTIAL_SPECIFY_CASE(high_2, "High part of buffer specified with two calls", GL_ARRAY_BUFFER, GL_STREAM_DRAW,
731 1200, << IVec2(600, 123) << IVec2(723, 477));
732 PARTIAL_SPECIFY_CASE(high_3, "High part of buffer specified with two calls", GL_ARRAY_BUFFER, GL_STREAM_DRAW,
733 1200, << IVec2(600, 200) << IVec2(601, 599));
734
735 PARTIAL_SPECIFY_CASE(middle_1, "Middle part of buffer specified with single call", GL_ELEMENT_ARRAY_BUFFER,
736 GL_STREAM_DRAW, 2500, << IVec2(1000, 799));
737 PARTIAL_SPECIFY_CASE(middle_2, "Middle part of buffer specified with two calls", GL_ELEMENT_ARRAY_BUFFER,
738 GL_STATIC_DRAW, 2500, << IVec2(780, 220) << IVec2(1000, 500));
739 PARTIAL_SPECIFY_CASE(middle_3, "Middle part of buffer specified with two calls", GL_ARRAY_BUFFER,
740 GL_DYNAMIC_DRAW, 2500, << IVec2(780, 321) << IVec2(1000, 501));
741
742 #undef PARTIAL_SPECIFY_CASE
743 }
744
745 // .random
746 {
747 tcu::TestCaseGroup *const randomGroup =
748 new tcu::TestCaseGroup(m_testCtx, "random", "Randomized buffer data cases");
749 addChild(randomGroup);
750
751 for (int i = 0; i < 10; i++)
752 randomGroup->addChild(new RandomBufferWriteCase(m_context, de::toString(i).c_str(), "", deInt32Hash(i)));
753 }
754 }
755
756 } // namespace Functional
757 } // namespace gles2
758 } // namespace deqp
759