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