| /*------------------------------------------------------------------------- |
| * 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 |