blob: 2a0cca1f1a1c40fe12ab3342cc64b99773a0c95b [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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::string;
using std::vector;
using tcu::IVec2;
using tcu::TestLog;
namespace deqp
{
namespace gles3
{
namespace Functional
{
using namespace gls::BufferTestUtil;
struct DataStoreSpec
{
DataStoreSpec(void) : target(0), usage(0), size(0)
{
}
DataStoreSpec(uint32_t target_, uint32_t usage_, int size_) : target(target_), usage(usage_), size(size_)
{
}
uint32_t target;
uint32_t 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, uint32_t target, uint32_t 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 uint32_t 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);
uint32_t 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:
uint32_t m_target;
uint32_t 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 uint32_t baseSeed = deStringHash(getName()) ^ 0xbeef;
BufferVerifier verifier(m_renderCtx, m_testCtx.getLog(), m_verify);
ReferenceBuffer refBuf;
const uint32_t 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, uint32_t target, uint32_t 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 uint32_t dataSeed = deStringHash(getName());
BufferVerifier verifier(m_renderCtx, m_testCtx.getLog(), m_verify);
ReferenceBuffer refBuf;
bool isOk = false;
refBuf.setSize(m_size);
uint32_t 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:
uint32_t m_target;
uint32_t 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, uint32_t target, uint32_t 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 uint32_t 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);
uint32_t 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:
uint32_t m_target;
uint32_t 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, uint32_t 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 uint32_t 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 uint32_t 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;
uint32_t 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 uint32_t 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 uint32_t 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.
{
uint32_t 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 uint32_t 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:
uint32_t m_seed;
BufferVerifier *m_verifier;
uint32_t 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 uint32_t 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 uint32_t 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 uint32_t target = bufferTargets[targetNdx];
const uint32_t 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 (false)
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 uint32_t target = bufferTargets[targetNdx];
const uint32_t 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 (false)
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)));
}
}
} // namespace Functional
} // namespace gles3
} // namespace deqp