xref: /aosp_15_r20/external/deqp/modules/gles2/functional/es2fBufferWriteTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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