/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL ES 3.0 Module * ------------------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Buffer data upload tests. *//*--------------------------------------------------------------------*/ #include "es3fBufferWriteTests.hpp" #include "glsBufferTestUtil.hpp" #include "tcuTestLog.hpp" #include "gluStrUtil.hpp" #include "deMemory.h" #include "deString.h" #include "deRandom.hpp" #include "deStringUtil.hpp" #include "deMath.h" #include "glwEnums.hpp" #include "glwFunctions.hpp" #include <algorithm> #include <list> using std::set; using std::vector; using std::string; using tcu::TestLog; using tcu::IVec2; namespace deqp { namespace gles3 { namespace Functional { using namespace gls::BufferTestUtil; struct DataStoreSpec { DataStoreSpec (void) : target (0) , usage (0) , size (0) { } DataStoreSpec (deUint32 target_, deUint32 usage_, int size_) : target (target_) , usage (usage_) , size (size_) { } deUint32 target; deUint32 usage; int size; }; struct DataStoreSpecVecBuilder { std::vector<DataStoreSpec>& list; DataStoreSpecVecBuilder (std::vector<DataStoreSpec>& list_) : list(list_) { } DataStoreSpecVecBuilder& operator<< (const DataStoreSpec& spec) { list.push_back(spec); return *this; } }; struct RangeVecBuilder { std::vector<tcu::IVec2>& list; RangeVecBuilder (std::vector<tcu::IVec2>& list_) : list(list_) { } RangeVecBuilder& operator<< (const tcu::IVec2& vec) { list.push_back(vec); return *this; } }; template<typename Iterator> static bool isRangeListValid (Iterator begin, Iterator end) { if (begin != end) { // Fetch first. tcu::IVec2 prev = *begin; ++begin; for (; begin != end; ++begin) { tcu::IVec2 cur = *begin; if (cur.x() <= prev.x() || cur.x() <= prev.x()+prev.y()) return false; prev = cur; } } return true; } inline bool rangesIntersect (const tcu::IVec2& a, const tcu::IVec2& b) { return de::inRange(a.x(), b.x(), b.x()+b.y()) || de::inRange(a.x()+a.y(), b.x(), b.x()+b.y()) || de::inRange(b.x(), a.x(), a.x()+a.y()) || de::inRange(b.x()+b.y(), a.x(), a.x()+a.y()); } inline tcu::IVec2 unionRanges (const tcu::IVec2& a, const tcu::IVec2& b) { DE_ASSERT(rangesIntersect(a, b)); int start = de::min(a.x(), b.x()); int end = de::max(a.x()+a.y(), b.x()+b.y()); return tcu::IVec2(start, end-start); } //! Updates range list (start, len) with a new range. std::vector<tcu::IVec2> addRangeToList (const std::vector<tcu::IVec2>& oldList, const tcu::IVec2& newRange) { DE_ASSERT(newRange.y() > 0); std::vector<tcu::IVec2> newList; std::vector<tcu::IVec2>::const_iterator oldListIter = oldList.begin(); // Append ranges that end before the new range. for (; oldListIter != oldList.end() && oldListIter->x()+oldListIter->y() < newRange.x(); ++oldListIter) newList.push_back(*oldListIter); // Join any ranges that intersect new range { tcu::IVec2 curRange = newRange; while (oldListIter != oldList.end() && rangesIntersect(curRange, *oldListIter)) { curRange = unionRanges(curRange, *oldListIter); ++oldListIter; } newList.push_back(curRange); } // Append remaining ranges. for (; oldListIter != oldList.end(); oldListIter++) newList.push_back(*oldListIter); DE_ASSERT(isRangeListValid(newList.begin(), newList.end())); return newList; } class BasicBufferDataCase : public BufferCase { public: BasicBufferDataCase (Context& context, const char* name, const char* desc, deUint32 target, deUint32 usage, int size, VerifyType verify) : BufferCase (context.getTestContext(), context.getRenderContext(), name, desc) , m_target (target) , m_usage (usage) , m_size (size) , m_verify (verify) { } IterateResult iterate (void) { const deUint32 dataSeed = deStringHash(getName()) ^ 0x125; BufferVerifier verifier (m_renderCtx, m_testCtx.getLog(), m_verify); ReferenceBuffer refBuf; bool isOk = false; refBuf.setSize(m_size); fillWithRandomBytes(refBuf.getPtr(), m_size, dataSeed); deUint32 buf = genBuffer(); glBindBuffer(m_target, buf); glBufferData(m_target, m_size, refBuf.getPtr(), m_usage); checkError(); isOk = verifier.verify(buf, refBuf.getPtr(), 0, m_size, m_target); deleteBuffer(buf); m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Buffer verification failed"); return STOP; } private: deUint32 m_target; deUint32 m_usage; int m_size; VerifyType m_verify; }; class RecreateBufferDataStoreCase : public BufferCase { public: RecreateBufferDataStoreCase (Context& context, const char* name, const char* desc, const DataStoreSpec* specs, int numSpecs, VerifyType verify) : BufferCase(context.getTestContext(), context.getRenderContext(), name, desc) , m_specs (specs, specs+numSpecs) , m_verify (verify) { } IterateResult iterate (void) { const deUint32 baseSeed = deStringHash(getName()) ^ 0xbeef; BufferVerifier verifier (m_renderCtx, m_testCtx.getLog(), m_verify); ReferenceBuffer refBuf; const deUint32 buf = genBuffer(); m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); for (vector<DataStoreSpec>::const_iterator spec = m_specs.begin(); spec != m_specs.end(); spec++) { bool iterOk = false; refBuf.setSize(spec->size); fillWithRandomBytes(refBuf.getPtr(), spec->size, baseSeed ^ deInt32Hash(spec->size+spec->target+spec->usage)); glBindBuffer(spec->target, buf); glBufferData(spec->target, spec->size, refBuf.getPtr(), spec->usage); checkError(); iterOk = verifier.verify(buf, refBuf.getPtr(), 0, spec->size, spec->target); if (!iterOk) { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); break; } } deleteBuffer(buf); return STOP; } private: std::vector<DataStoreSpec> m_specs; VerifyType m_verify; }; class BasicBufferSubDataCase : public BufferCase { public: BasicBufferSubDataCase (Context& context, const char* name, const char* desc, deUint32 target, deUint32 usage, int size, int subDataOffs, int subDataSize, VerifyType verify) : BufferCase (context.getTestContext(), context.getRenderContext(), name, desc) , m_target (target) , m_usage (usage) , m_size (size) , m_subDataOffs (subDataOffs) , m_subDataSize (subDataSize) , m_verify (verify) { DE_ASSERT(de::inBounds(subDataOffs, 0, size) && de::inRange(subDataOffs+subDataSize, 0, size)); } IterateResult iterate (void) { const deUint32 dataSeed = deStringHash(getName()); BufferVerifier verifier (m_renderCtx, m_testCtx.getLog(), m_verify); ReferenceBuffer refBuf; bool isOk = false; refBuf.setSize(m_size); deUint32 buf = genBuffer(); glBindBuffer(m_target, buf); // Initialize with glBufferData() fillWithRandomBytes(refBuf.getPtr(), m_size, dataSeed ^ 0x80354f); glBufferData(m_target, m_size, refBuf.getPtr(), m_usage); checkError(); // Re-specify part of buffer fillWithRandomBytes(refBuf.getPtr()+m_subDataOffs, m_subDataSize, dataSeed ^ 0xfac425c); glBufferSubData(m_target, m_subDataOffs, m_subDataSize, refBuf.getPtr()+m_subDataOffs); isOk = verifier.verify(buf, refBuf.getPtr(), 0, m_size, m_target); deleteBuffer(buf); m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Buffer verification failed"); return STOP; } private: deUint32 m_target; deUint32 m_usage; int m_size; int m_subDataOffs; int m_subDataSize; VerifyType m_verify; }; class SubDataToUndefinedCase : public BufferCase { public: SubDataToUndefinedCase (Context& context, const char* name, const char* desc, deUint32 target, deUint32 usage, int size, const tcu::IVec2* ranges, int numRanges, VerifyType verify) : BufferCase (context.getTestContext(), context.getRenderContext(), name, desc) , m_target (target) , m_usage (usage) , m_size (size) , m_ranges (ranges, ranges+numRanges) , m_verify (verify) { } IterateResult iterate (void) { const deUint32 dataSeed = deStringHash(getName()); BufferVerifier verifier (m_renderCtx, m_testCtx.getLog(), m_verify); ReferenceBuffer refBuf; bool isOk = true; std::vector<tcu::IVec2> definedRanges; refBuf.setSize(m_size); deUint32 buf = genBuffer(); glBindBuffer(m_target, buf); // Initialize storage with glBufferData() glBufferData(m_target, m_size, DE_NULL, m_usage); checkError(); // Fill specified ranges with glBufferSubData() for (vector<tcu::IVec2>::const_iterator range = m_ranges.begin(); range != m_ranges.end(); range++) { fillWithRandomBytes(refBuf.getPtr()+range->x(), range->y(), dataSeed ^ deInt32Hash(range->x()+range->y())); glBufferSubData(m_target, range->x(), range->y(), refBuf.getPtr()+range->x()); // Mark range as defined definedRanges = addRangeToList(definedRanges, *range); } // Verify defined parts for (vector<tcu::IVec2>::const_iterator range = definedRanges.begin(); range != definedRanges.end(); range++) { if (!verifier.verify(buf, refBuf.getPtr(), range->x(), range->y(), m_target)) isOk = false; } deleteBuffer(buf); m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Buffer verification failed"); return STOP; } private: deUint32 m_target; deUint32 m_usage; int m_size; std::vector<tcu::IVec2> m_ranges; VerifyType m_verify; }; class RandomBufferWriteCase : public BufferCase { public: RandomBufferWriteCase (Context& context, const char* name, const char* desc, deUint32 seed) : BufferCase(context.getTestContext(), context.getRenderContext(), name, desc) , m_seed (seed) , m_verifier (DE_NULL) , m_buffer (0) , m_curSize (0) , m_iterNdx (0) { } ~RandomBufferWriteCase (void) { delete m_verifier; } void init (void) { BufferCase::init(); m_iterNdx = 0; m_buffer = genBuffer(); m_curSize = 0; m_verifier = new BufferVerifier(m_renderCtx, m_testCtx.getLog(), VERIFY_AS_VERTEX_ARRAY); m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } void deinit (void) { deleteBuffer(m_buffer); m_refBuffer.setSize(0); delete m_verifier; m_verifier = DE_NULL; BufferCase::deinit(); } IterateResult iterate (void) { // Parameters. const int numIterations = 5; const int uploadsPerIteration = 7; const int minSize = 12; const int maxSize = 32*1024; const float respecifyProbability = 0.07f; const float respecifyDataProbability = 0.2f; static const deUint32 bufferTargets[] = { GL_ARRAY_BUFFER, GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, GL_TRANSFORM_FEEDBACK_BUFFER, GL_UNIFORM_BUFFER }; static const deUint32 usageHints[] = { GL_STREAM_DRAW, GL_STREAM_READ, GL_STREAM_COPY, GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY, GL_DYNAMIC_DRAW, GL_DYNAMIC_READ, GL_DYNAMIC_COPY }; bool iterOk = true; deUint32 curBoundTarget = GL_NONE; de::Random rnd (m_seed ^ deInt32Hash(m_iterNdx) ^ 0xacf92e); m_testCtx.getLog() << TestLog::Section(string("Iteration") + de::toString(m_iterNdx+1), string("Iteration ") + de::toString(m_iterNdx+1) + " / " + de::toString(numIterations)); for (int uploadNdx = 0; uploadNdx < uploadsPerIteration; uploadNdx++) { const deUint32 target = bufferTargets[rnd.getInt(0, DE_LENGTH_OF_ARRAY(bufferTargets)-1)]; const bool respecify = m_curSize == 0 || rnd.getFloat() < respecifyProbability; if (target != curBoundTarget) { glBindBuffer(target, m_buffer); curBoundTarget = target; } if (respecify) { const int size = rnd.getInt(minSize, maxSize); const deUint32 hint = usageHints[rnd.getInt(0, DE_LENGTH_OF_ARRAY(usageHints)-1)]; const bool fillWithData = rnd.getFloat() < respecifyDataProbability; m_refBuffer.setSize(size); if (fillWithData) fillWithRandomBytes(m_refBuffer.getPtr(), size, rnd.getUint32()); glBufferData(target, size, fillWithData ? m_refBuffer.getPtr() : DE_NULL, hint); m_validRanges.clear(); if (fillWithData) m_validRanges.push_back(tcu::IVec2(0, size)); m_curSize = size; } else { // \note Non-uniform size distribution. const int size = de::clamp(deRoundFloatToInt32((float)m_curSize * deFloatPow(rnd.getFloat(0.0f, 0.7f), 3.0f)), minSize, m_curSize); const int offset = rnd.getInt(0, m_curSize-size); fillWithRandomBytes(m_refBuffer.getPtr()+offset, size, rnd.getUint32()); glBufferSubData(target, offset, size, m_refBuffer.getPtr()+offset); m_validRanges = addRangeToList(m_validRanges, tcu::IVec2(offset, size)); } } // Check error. { deUint32 err = glGetError(); if (err != GL_NO_ERROR) throw tcu::TestError(string("Got ") + glu::getErrorStr(err).toString()); } // Verify valid ranges. for (vector<IVec2>::const_iterator range = m_validRanges.begin(); range != m_validRanges.end(); range++) { const deUint32 targetHint = GL_ARRAY_BUFFER; if (!m_verifier->verify(m_buffer, m_refBuffer.getPtr(), range->x(), range->y(), targetHint)) { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Buffer verification failed"); iterOk = false; break; } } m_testCtx.getLog() << TestLog::EndSection; DE_ASSERT(iterOk || m_testCtx.getTestResult() != QP_TEST_RESULT_PASS); m_iterNdx += 1; return (iterOk && m_iterNdx < numIterations) ? CONTINUE : STOP; } private: deUint32 m_seed; BufferVerifier* m_verifier; deUint32 m_buffer; ReferenceBuffer m_refBuffer; std::vector<tcu::IVec2> m_validRanges; int m_curSize; int m_iterNdx; }; BufferWriteTests::BufferWriteTests (Context& context) : TestCaseGroup(context, "write", "Buffer data upload tests") { } BufferWriteTests::~BufferWriteTests (void) { } void BufferWriteTests::init (void) { static const deUint32 bufferTargets[] = { GL_ARRAY_BUFFER, GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, GL_TRANSFORM_FEEDBACK_BUFFER, GL_UNIFORM_BUFFER }; static const deUint32 usageHints[] = { GL_STREAM_DRAW, GL_STREAM_READ, GL_STREAM_COPY, GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY, GL_DYNAMIC_DRAW, GL_DYNAMIC_READ, GL_DYNAMIC_COPY }; // .basic { tcu::TestCaseGroup* const basicGroup = new tcu::TestCaseGroup(m_testCtx, "basic", "Basic upload with glBufferData()"); addChild(basicGroup); for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(bufferTargets); targetNdx++) { for (int usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(usageHints); usageNdx++) { const deUint32 target = bufferTargets[targetNdx]; const deUint32 usage = usageHints[usageNdx]; const int size = 1020; const VerifyType verify = VERIFY_AS_VERTEX_ARRAY; const string name = string(getBufferTargetName(target)) + "_" + getUsageHintName(usage); basicGroup->addChild(new BasicBufferDataCase(m_context, name.c_str(), "", target, usage, size, verify)); } } } // .recreate_store { tcu::TestCaseGroup* const recreateStoreGroup = new tcu::TestCaseGroup(m_testCtx, "recreate_store", "Data store recreate using glBufferData()"); addChild(recreateStoreGroup); #define RECREATE_STORE_CASE(NAME, DESC, SPECLIST) \ do { \ std::vector<DataStoreSpec> specs; \ DataStoreSpecVecBuilder builder(specs); \ builder SPECLIST; \ recreateStoreGroup->addChild(new RecreateBufferDataStoreCase(m_context, #NAME, DESC, &specs[0], (int)specs.size(), VERIFY_AS_VERTEX_ARRAY)); \ } while (deGetFalse()) RECREATE_STORE_CASE(identical_1, "Recreate with identical parameters", << DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996) << DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996) << DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996)); RECREATE_STORE_CASE(identical_2, "Recreate with identical parameters", << DataStoreSpec(GL_COPY_WRITE_BUFFER, GL_STATIC_DRAW, 72) << DataStoreSpec(GL_COPY_WRITE_BUFFER, GL_STATIC_DRAW, 72) << DataStoreSpec(GL_COPY_WRITE_BUFFER, GL_STATIC_DRAW, 72)); RECREATE_STORE_CASE(different_target, "Recreate with different target", << DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 504) << DataStoreSpec(GL_COPY_READ_BUFFER, GL_STATIC_DRAW, 504) << DataStoreSpec(GL_COPY_WRITE_BUFFER, GL_STATIC_DRAW, 504) << DataStoreSpec(GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, 504) << DataStoreSpec(GL_PIXEL_PACK_BUFFER, GL_STATIC_DRAW, 504) << DataStoreSpec(GL_PIXEL_UNPACK_BUFFER, GL_STATIC_DRAW, 504) << DataStoreSpec(GL_TRANSFORM_FEEDBACK_BUFFER, GL_STATIC_DRAW, 504) << DataStoreSpec(GL_UNIFORM_BUFFER, GL_STATIC_DRAW, 504) << DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 504)); RECREATE_STORE_CASE(different_usage, "Recreate with different usage", << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 1644) << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_COPY, 1644) << DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_READ, 1644) << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_READ, 1644) << DataStoreSpec(GL_ARRAY_BUFFER, GL_DYNAMIC_COPY, 1644) << DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_COPY, 1644) << DataStoreSpec(GL_ARRAY_BUFFER, GL_DYNAMIC_READ, 1644) << DataStoreSpec(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, 1644) << DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 1644) << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 1644)); RECREATE_STORE_CASE(different_size, "Recreate with different size", << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 1024) << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 12) << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 3327) << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 92) << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 123795) << DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW, 571)); #undef RECREATE_STORE_CASE // Random cases. { const int numRandomCases = 4; const int numUploadsPerCase = 10; const int minSize = 12; const int maxSize = 65536; const VerifyType verify = VERIFY_AS_VERTEX_ARRAY; de::Random rnd (23921); for (int caseNdx = 0; caseNdx < numRandomCases; caseNdx++) { vector<DataStoreSpec> specs(numUploadsPerCase); for (vector<DataStoreSpec>::iterator spec = specs.begin(); spec != specs.end(); spec++) { spec->target = bufferTargets[rnd.getInt(0, DE_LENGTH_OF_ARRAY(bufferTargets)-1)]; spec->usage = usageHints[rnd.getInt(0, DE_LENGTH_OF_ARRAY(usageHints)-1)]; spec->size = rnd.getInt(minSize, maxSize); } recreateStoreGroup->addChild(new RecreateBufferDataStoreCase(m_context, (string("random_") + de::toString(caseNdx+1)).c_str(), "", &specs[0], (int)specs.size(), verify)); } } } // .basic_subdata { tcu::TestCaseGroup* const basicGroup = new tcu::TestCaseGroup(m_testCtx, "basic_subdata", "Basic glBufferSubData() usage"); addChild(basicGroup); for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(bufferTargets); targetNdx++) { for (int usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(usageHints); usageNdx++) { const deUint32 target = bufferTargets[targetNdx]; const deUint32 usage = usageHints[usageNdx]; const int size = 1020; const VerifyType verify = VERIFY_AS_VERTEX_ARRAY; const string name = string(getBufferTargetName(target)) + "_" + getUsageHintName(usage); basicGroup->addChild(new BasicBufferDataCase(m_context, name.c_str(), "", target, usage, size, verify)); } } } // .partial_specify { tcu::TestCaseGroup* const partialSpecifyGroup = new tcu::TestCaseGroup(m_testCtx, "partial_specify", "Partial buffer data specification with glBufferSubData()"); addChild(partialSpecifyGroup); #define PARTIAL_SPECIFY_CASE(NAME, DESC, TARGET, USAGE, SIZE, RANGELIST) \ do { \ std::vector<tcu::IVec2> ranges; \ RangeVecBuilder builder(ranges); \ builder RANGELIST; \ partialSpecifyGroup->addChild(new SubDataToUndefinedCase(m_context, #NAME, DESC, TARGET, USAGE, SIZE, &ranges[0], (int)ranges.size(), VERIFY_AS_VERTEX_ARRAY)); \ } while (deGetFalse()) PARTIAL_SPECIFY_CASE(whole_1, "Whole buffer specification with single glBufferSubData()", GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996, << IVec2(0, 996)); PARTIAL_SPECIFY_CASE(whole_2, "Whole buffer specification with two calls", GL_UNIFORM_BUFFER, GL_DYNAMIC_READ, 1728, << IVec2(729, 999) << IVec2(0, 729)); PARTIAL_SPECIFY_CASE(whole_3, "Whole buffer specification with three calls", GL_TRANSFORM_FEEDBACK_BUFFER, GL_STREAM_COPY, 1944, << IVec2(0, 421) << IVec2(1421, 523) << IVec2(421, 1000)); PARTIAL_SPECIFY_CASE(whole_4, "Whole buffer specification with three calls", GL_TRANSFORM_FEEDBACK_BUFFER, GL_STREAM_COPY, 1200, << IVec2(0, 500) << IVec2(429, 200) << IVec2(513, 687)); PARTIAL_SPECIFY_CASE(low_1, "Low part of buffer specified with single call", GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, 1000, << IVec2(0, 513)); PARTIAL_SPECIFY_CASE(low_2, "Low part of buffer specified with two calls", GL_COPY_READ_BUFFER, GL_DYNAMIC_COPY, 996, << IVec2(0, 98) << IVec2(98, 511)); PARTIAL_SPECIFY_CASE(low_3, "Low part of buffer specified with two calls", GL_COPY_READ_BUFFER, GL_DYNAMIC_COPY, 1200, << IVec2(0, 591) << IVec2(371, 400)); PARTIAL_SPECIFY_CASE(high_1, "High part of buffer specified with single call", GL_COPY_WRITE_BUFFER, GL_STATIC_COPY, 1000, << IVec2(500, 500)); PARTIAL_SPECIFY_CASE(high_2, "High part of buffer specified with two calls", GL_TRANSFORM_FEEDBACK_BUFFER, GL_STREAM_DRAW, 1200, << IVec2(600, 123) << IVec2(723, 477)); PARTIAL_SPECIFY_CASE(high_3, "High part of buffer specified with two calls", GL_PIXEL_PACK_BUFFER, GL_STREAM_READ, 1200, << IVec2(600, 200) << IVec2(601, 599)); PARTIAL_SPECIFY_CASE(middle_1, "Middle part of buffer specified with single call", GL_PIXEL_UNPACK_BUFFER, GL_STREAM_READ, 2500, << IVec2(1000, 799)); PARTIAL_SPECIFY_CASE(middle_2, "Middle part of buffer specified with two calls", GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, 2500, << IVec2(780, 220) << IVec2(1000, 500)); PARTIAL_SPECIFY_CASE(middle_3, "Middle part of buffer specified with two calls", GL_ARRAY_BUFFER, GL_STREAM_READ, 2500, << IVec2(780, 321) << IVec2(1000, 501)); #undef PARTIAL_SPECIFY_CASE } // .random { tcu::TestCaseGroup* const randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Randomized buffer data cases"); addChild(randomGroup); for (int i = 0; i < 10; i++) randomGroup->addChild(new RandomBufferWriteCase(m_context, de::toString(i).c_str(), "", deInt32Hash(i))); } } } // Functional } // gles3 } // deqp