775 lines
23 KiB
C++
775 lines
23 KiB
C++
/*-------------------------------------------------------------------------
|
|
* 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
|