/*-------------------------------------------------------------------------
* 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 copying tests.
*//*--------------------------------------------------------------------*/
#include "es3fBufferCopyTests.hpp"
#include "glsBufferTestUtil.hpp"
#include "tcuTestLog.hpp"
#include "deMemory.h"
#include "deString.h"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include <algorithm>
using std::vector;
using std::string;
using tcu::TestLog;
namespace deqp
{
namespace gles3
{
namespace Functional
{
using namespace gls::BufferTestUtil;
class BasicBufferCopyCase : public BufferCase
{
public:
BasicBufferCopyCase (Context& context,
const char* name,
const char* desc,
deUint32 srcTarget,
int srcSize,
deUint32 srcHint,
deUint32 dstTarget,
int dstSize,
deUint32 dstHint,
int copySrcOffset,
int copyDstOffset,
int copySize,
VerifyType verifyType)
: BufferCase (context.getTestContext(), context.getRenderContext(), name, desc)
, m_srcTarget (srcTarget)
, m_srcSize (srcSize)
, m_srcHint (srcHint)
, m_dstTarget (dstTarget)
, m_dstSize (dstSize)
, m_dstHint (dstHint)
, m_copySrcOffset (copySrcOffset)
, m_copyDstOffset (copyDstOffset)
, m_copySize (copySize)
, m_verifyType (verifyType)
{
DE_ASSERT(de::inBounds(m_copySrcOffset, 0, m_srcSize) && de::inRange(m_copySrcOffset+m_copySize, m_copySrcOffset, m_srcSize));
DE_ASSERT(de::inBounds(m_copyDstOffset, 0, m_dstSize) && de::inRange(m_copyDstOffset+m_copySize, m_copyDstOffset, m_dstSize));
}
IterateResult iterate (void)
{
BufferVerifier verifier (m_renderCtx, m_testCtx.getLog(), m_verifyType);
ReferenceBuffer srcRef;
ReferenceBuffer dstRef;
deUint32 srcBuf = 0;
deUint32 dstBuf = 0;
deUint32 srcSeed = deStringHash(getName()) ^ 0xabcd;
deUint32 dstSeed = deStringHash(getName()) ^ 0xef01;
bool isOk = true;
srcRef.setSize(m_srcSize);
fillWithRandomBytes(srcRef.getPtr(), m_srcSize, srcSeed);
dstRef.setSize(m_dstSize);
fillWithRandomBytes(dstRef.getPtr(), m_dstSize, dstSeed);
// Create source buffer and fill with data.
srcBuf = genBuffer();
glBindBuffer(m_srcTarget, srcBuf);
glBufferData(m_srcTarget, m_srcSize, srcRef.getPtr(), m_srcHint);
GLU_CHECK_MSG("glBufferData");
// Create destination buffer and fill with data.
dstBuf = genBuffer();
glBindBuffer(m_dstTarget, dstBuf);
glBufferData(m_dstTarget, m_dstSize, dstRef.getPtr(), m_dstHint);
GLU_CHECK_MSG("glBufferData");
// Verify both buffers before executing copy.
isOk = verifier.verify(srcBuf, srcRef.getPtr(), 0, m_srcSize, m_srcTarget) && isOk;
isOk = verifier.verify(dstBuf, dstRef.getPtr(), 0, m_dstSize, m_dstTarget) && isOk;
// Execute copy.
deMemcpy(dstRef.getPtr()+m_copyDstOffset, srcRef.getPtr()+m_copySrcOffset, m_copySize);
glBindBuffer(m_srcTarget, srcBuf);
glBindBuffer(m_dstTarget, dstBuf);
glCopyBufferSubData(m_srcTarget, m_dstTarget, m_copySrcOffset, m_copyDstOffset, m_copySize);
GLU_CHECK_MSG("glCopyBufferSubData");
// Verify both buffers after copy.
isOk = verifier.verify(srcBuf, srcRef.getPtr(), 0, m_srcSize, m_srcTarget) && isOk;
isOk = verifier.verify(dstBuf, dstRef.getPtr(), 0, m_dstSize, m_dstTarget) && isOk;
m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
isOk ? "Pass" : "Buffer verification failed");
return STOP;
}
private:
deUint32 m_srcTarget;
int m_srcSize;
deUint32 m_srcHint;
deUint32 m_dstTarget;
int m_dstSize;
deUint32 m_dstHint;
int m_copySrcOffset;
int m_copyDstOffset;
int m_copySize;
VerifyType m_verifyType;
};
// Case B: same buffer, take range as parameter
class SingleBufferCopyCase : public BufferCase
{
public:
SingleBufferCopyCase (Context& context,
const char* name,
const char* desc,
deUint32 srcTarget,
deUint32 dstTarget,
deUint32 hint,
VerifyType verifyType)
: BufferCase (context.getTestContext(), context.getRenderContext(), name, desc)
, m_srcTarget (srcTarget)
, m_dstTarget (dstTarget)
, m_hint (hint)
, m_verifyType (verifyType)
{
}
IterateResult iterate (void)
{
const int size = 1000;
BufferVerifier verifier (m_renderCtx, m_testCtx.getLog(), m_verifyType);
ReferenceBuffer ref;
deUint32 buf = 0;
deUint32 baseSeed = deStringHash(getName());
bool isOk = true;
ref.setSize(size);
// Create buffer.
buf = genBuffer();
glBindBuffer(m_srcTarget, buf);
static const struct
{
int srcOffset;
int dstOffset;
int copySize;
} copyRanges[] =
{
{ 57, 701, 101 }, // Non-adjecent, from low to high.
{ 640, 101, 101 }, // Non-adjecent, from high to low.
{ 0, 500, 500 }, // Lower half to upper half.
{ 500, 0, 500 } // Upper half to lower half.
};
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(copyRanges) && isOk; ndx++)
{
int srcOffset = copyRanges[ndx].srcOffset;
int dstOffset = copyRanges[ndx].dstOffset;
int copySize = copyRanges[ndx].copySize;
fillWithRandomBytes(ref.getPtr(), size, baseSeed ^ deInt32Hash(ndx));
// Fill with data.
glBindBuffer(m_srcTarget, buf);
glBufferData(m_srcTarget, size, ref.getPtr(), m_hint);
GLU_CHECK_MSG("glBufferData");
// Execute copy.
deMemcpy(ref.getPtr()+dstOffset, ref.getPtr()+srcOffset, copySize);
glBindBuffer(m_dstTarget, buf);
glCopyBufferSubData(m_srcTarget, m_dstTarget, srcOffset, dstOffset, copySize);
GLU_CHECK_MSG("glCopyBufferSubData");
// Verify buffer after copy.
isOk = verifier.verify(buf, ref.getPtr(), 0, size, m_dstTarget) && isOk;
}
m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
isOk ? "Pass" : "Buffer verification failed");
return STOP;
}
private:
deUint32 m_srcTarget;
deUint32 m_dstTarget;
deUint32 m_hint;
VerifyType m_verifyType;
};
BufferCopyTests::BufferCopyTests (Context& context)
: TestCaseGroup(context, "copy", "Buffer copy tests")
{
}
BufferCopyTests::~BufferCopyTests (void)
{
}
void BufferCopyTests::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
};
// .basic
{
tcu::TestCaseGroup* basicGroup = new tcu::TestCaseGroup(m_testCtx, "basic", "Basic buffer copy cases");
addChild(basicGroup);
for (int srcTargetNdx = 0; srcTargetNdx < DE_LENGTH_OF_ARRAY(bufferTargets); srcTargetNdx++)
{
for (int dstTargetNdx = 0; dstTargetNdx < DE_LENGTH_OF_ARRAY(bufferTargets); dstTargetNdx++)
{
if (srcTargetNdx == dstTargetNdx)
continue;
deUint32 srcTarget = bufferTargets[srcTargetNdx];
deUint32 dstTarget = bufferTargets[dstTargetNdx];
const int size = 1017;
const deUint32 hint = GL_STATIC_DRAW;
VerifyType verify = VERIFY_AS_VERTEX_ARRAY;
string name = string(getBufferTargetName(srcTarget)) + "_" + getBufferTargetName(dstTarget);
basicGroup->addChild(new BasicBufferCopyCase(m_context, name.c_str(), "", srcTarget, size, hint, dstTarget, size, hint, 0, 0, size, verify));
}
}
}
// .subrange
{
tcu::TestCaseGroup* subrangeGroup = new tcu::TestCaseGroup(m_testCtx, "subrange", "Buffer subrange copy tests");
addChild(subrangeGroup);
static const struct
{
const char* name;
int srcSize;
int dstSize;
int srcOffset;
int dstOffset;
int copySize;
} cases[] =
{
// srcSize dstSize srcOffs dstOffs copySize
{ "middle", 1000, 1000, 250, 250, 500 },
{ "small_to_large", 100, 1000, 0, 409, 100 },
{ "large_to_small", 1000, 100, 409, 0, 100 },
{ "low_to_high_1", 1000, 1000, 0, 500, 500 },
{ "low_to_high_2", 997, 1027, 0, 701, 111 },
{ "high_to_low_1", 1000, 1000, 500, 0, 500 },
{ "high_to_low_2", 1027, 997, 701, 17, 111 }
};
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++)
{
deUint32 srcTarget = GL_COPY_READ_BUFFER;
deUint32 dstTarget = GL_COPY_WRITE_BUFFER;
deUint32 hint = GL_STATIC_DRAW;
VerifyType verify = VERIFY_AS_VERTEX_ARRAY;
subrangeGroup->addChild(new BasicBufferCopyCase(m_context, cases[ndx].name, "",
srcTarget, cases[ndx].srcSize, hint,
dstTarget, cases[ndx].dstSize, hint,
cases[ndx].srcOffset, cases[ndx].dstOffset, cases[ndx].copySize,
verify));
}
}
// .single_buffer
{
tcu::TestCaseGroup* singleBufGroup = new tcu::TestCaseGroup(m_testCtx, "single_buffer", "Copies within single buffer");
addChild(singleBufGroup);
for (int srcTargetNdx = 0; srcTargetNdx < DE_LENGTH_OF_ARRAY(bufferTargets); srcTargetNdx++)
{
for (int dstTargetNdx = 0; dstTargetNdx < DE_LENGTH_OF_ARRAY(bufferTargets); dstTargetNdx++)
{
if (srcTargetNdx == dstTargetNdx)
continue;
deUint32 srcTarget = bufferTargets[srcTargetNdx];
deUint32 dstTarget = bufferTargets[dstTargetNdx];
const deUint32 hint = GL_STATIC_DRAW;
VerifyType verify = VERIFY_AS_VERTEX_ARRAY;
string name = string(getBufferTargetName(srcTarget)) + "_" + getBufferTargetName(dstTarget);
singleBufGroup->addChild(new SingleBufferCopyCase(m_context, name.c_str(), "", srcTarget, dstTarget, hint, verify));
}
}
}
}
} // Functional
} // gles3
} // deqp