blob: 6dac2b75a004303f832758ccdfc1d824e09840a5 [file] [log] [blame] [edit]
/*-------------------------------------------------------------------------
* drawElements Internal Test 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 Miscellaneous framework tests.
*//*--------------------------------------------------------------------*/
#include "ditFrameworkTests.hpp"
#include "ditTextureFormatTests.hpp"
#include "ditAstcTests.hpp"
#include "ditVulkanTests.hpp"
#include "tcuFloatFormat.hpp"
#include "tcuEither.hpp"
#include "tcuTestLog.hpp"
#include "tcuCommandLine.hpp"
#include "rrRenderer.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuVectorUtil.hpp"
#include "tcuFloat.hpp"
#include "deRandom.hpp"
#include "deArrayUtil.hpp"
#include <stdexcept>
#include <cmath>
namespace dit
{
namespace
{
using std::string;
using std::vector;
using tcu::TestLog;
struct MatchCase
{
enum Expected
{
NO_MATCH,
MATCH_GROUP,
MATCH_CASE,
EXPECTED_LAST
};
const char *path;
Expected expected;
};
const char *getMatchCaseExpectedDesc(MatchCase::Expected expected)
{
static const char *descs[] = {"no match", "group to match", "case to match"};
return de::getSizedArrayElement<MatchCase::EXPECTED_LAST>(descs, expected);
}
class CaseListParserCase : public tcu::TestCase
{
public:
CaseListParserCase(tcu::TestContext &testCtx, const char *name, const char *caseList, const MatchCase *subCases,
int numSubCases)
: tcu::TestCase(testCtx, name, "")
, m_caseList(caseList)
, m_subCases(subCases)
, m_numSubCases(numSubCases)
{
}
IterateResult iterate(void)
{
TestLog &log = m_testCtx.getLog();
tcu::CommandLine cmdLine;
de::MovePtr<tcu::CaseListFilter> caseListFilter;
int numPass = 0;
log << TestLog::Message << "Input:\n\"" << m_caseList << "\"" << TestLog::EndMessage;
{
const char *argv[] = {"deqp", "--deqp-caselist", m_caseList};
if (!cmdLine.parse(DE_LENGTH_OF_ARRAY(argv), argv))
TCU_FAIL("Failed to parse command line");
}
caseListFilter = cmdLine.createCaseListFilter(m_testCtx.getArchive());
for (int subCaseNdx = 0; subCaseNdx < m_numSubCases; subCaseNdx++)
{
const MatchCase &curCase = m_subCases[subCaseNdx];
bool matchGroup;
bool matchCase;
log << TestLog::Message << "Checking \"" << curCase.path << "\""
<< ", expecting " << getMatchCaseExpectedDesc(curCase.expected) << TestLog::EndMessage;
matchGroup = caseListFilter->checkTestGroupName(curCase.path);
matchCase = caseListFilter->checkTestCaseName(curCase.path);
if ((matchGroup == (curCase.expected == MatchCase::MATCH_GROUP)) &&
(matchCase == (curCase.expected == MatchCase::MATCH_CASE)))
{
log << TestLog::Message << " pass" << TestLog::EndMessage;
numPass += 1;
}
else
log << TestLog::Message << " FAIL!" << TestLog::EndMessage;
}
m_testCtx.setTestResult((numPass == m_numSubCases) ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
(numPass == m_numSubCases) ? "All passed" : "Unexpected match result");
return STOP;
}
private:
const char *const m_caseList;
const MatchCase *const m_subCases;
const int m_numSubCases;
};
class NegativeCaseListCase : public tcu::TestCase
{
public:
NegativeCaseListCase(tcu::TestContext &testCtx, const char *name, const char *caseList)
: tcu::TestCase(testCtx, name, "")
, m_caseList(caseList)
{
}
IterateResult iterate(void)
{
TestLog &log = m_testCtx.getLog();
tcu::CommandLine cmdLine;
log << TestLog::Message << "Input:\n\"" << m_caseList << "\"" << TestLog::EndMessage;
{
const char *argv[] = {"deqp", "--deqp-caselist", m_caseList};
TCU_CHECK(cmdLine.parse(DE_LENGTH_OF_ARRAY(argv), argv));
try
{
de::UniquePtr<tcu::CaseListFilter> filter(cmdLine.createCaseListFilter(m_testCtx.getArchive()));
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Parsing passed, should have failed");
}
catch (const std::invalid_argument &e)
{
log << TestLog::Message << e.what() << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Parsing failed as expected");
}
}
return STOP;
}
private:
const char *const m_caseList;
};
class TrieParserTests : public tcu::TestCaseGroup
{
public:
TrieParserTests(tcu::TestContext &testCtx) : tcu::TestCaseGroup(testCtx, "trie", "Test case trie parser tests")
{
}
void init(void)
{
{
static const char *const caseList = "{test}";
static const MatchCase subCases[] = {
{"test", MatchCase::MATCH_CASE},
{"test.cd", MatchCase::NO_MATCH},
};
addChild(
new CaseListParserCase(m_testCtx, "single_case", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "{a{b}}";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_GROUP},
{"b", MatchCase::NO_MATCH},
{"a.b", MatchCase::MATCH_CASE},
{"a.a", MatchCase::NO_MATCH},
};
addChild(
new CaseListParserCase(m_testCtx, "simple_group_1", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "{a{b,c}}";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_GROUP}, {"b", MatchCase::NO_MATCH}, {"a.b", MatchCase::MATCH_CASE},
{"a.a", MatchCase::NO_MATCH}, {"a.c", MatchCase::MATCH_CASE},
};
addChild(
new CaseListParserCase(m_testCtx, "simple_group_2", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "{a{b},c{d,e}}";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_GROUP}, {"b", MatchCase::NO_MATCH}, {"a.b", MatchCase::MATCH_CASE},
{"a.c", MatchCase::NO_MATCH}, {"a.d", MatchCase::NO_MATCH}, {"a.e", MatchCase::NO_MATCH},
{"c", MatchCase::MATCH_GROUP}, {"c.b", MatchCase::NO_MATCH}, {"c.d", MatchCase::MATCH_CASE},
{"c.e", MatchCase::MATCH_CASE},
};
addChild(new CaseListParserCase(m_testCtx, "two_groups", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "{a,c{d,e}}";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_CASE}, {"b", MatchCase::NO_MATCH}, {"a.b", MatchCase::NO_MATCH},
{"a.c", MatchCase::NO_MATCH}, {"a.d", MatchCase::NO_MATCH}, {"a.e", MatchCase::NO_MATCH},
{"c", MatchCase::MATCH_GROUP}, {"c.b", MatchCase::NO_MATCH}, {"c.d", MatchCase::MATCH_CASE},
{"c.e", MatchCase::MATCH_CASE},
};
addChild(new CaseListParserCase(m_testCtx, "case_group", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "{c{d,e},a}";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_CASE}, {"b", MatchCase::NO_MATCH}, {"a.b", MatchCase::NO_MATCH},
{"a.c", MatchCase::NO_MATCH}, {"a.d", MatchCase::NO_MATCH}, {"a.e", MatchCase::NO_MATCH},
{"c", MatchCase::MATCH_GROUP}, {"c.b", MatchCase::NO_MATCH}, {"c.d", MatchCase::MATCH_CASE},
{"c.e", MatchCase::MATCH_CASE},
};
addChild(new CaseListParserCase(m_testCtx, "group_case", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "{test}\r";
static const MatchCase subCases[] = {
{"test", MatchCase::MATCH_CASE},
{"test.cd", MatchCase::NO_MATCH},
};
addChild(
new CaseListParserCase(m_testCtx, "trailing_cr", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "{test}\n";
static const MatchCase subCases[] = {
{"test", MatchCase::MATCH_CASE},
{"test.cd", MatchCase::NO_MATCH},
};
addChild(
new CaseListParserCase(m_testCtx, "trailing_lf", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "{test}\r\n";
static const MatchCase subCases[] = {
{"test", MatchCase::MATCH_CASE},
{"test.cd", MatchCase::NO_MATCH},
};
addChild(
new CaseListParserCase(m_testCtx, "trailing_crlf", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
// Negative tests
addChild(new NegativeCaseListCase(m_testCtx, "empty_string", ""));
addChild(new NegativeCaseListCase(m_testCtx, "empty_line", "\n"));
addChild(new NegativeCaseListCase(m_testCtx, "empty_root", "{}"));
addChild(new NegativeCaseListCase(m_testCtx, "empty_group", "{test{}}"));
addChild(new NegativeCaseListCase(m_testCtx, "empty_group_name_1", "{{}}"));
addChild(new NegativeCaseListCase(m_testCtx, "empty_group_name_2", "{{test}}"));
addChild(new NegativeCaseListCase(m_testCtx, "unterminated_root_1", "{"));
addChild(new NegativeCaseListCase(m_testCtx, "unterminated_root_2", "{test"));
addChild(new NegativeCaseListCase(m_testCtx, "unterminated_root_3", "{test,"));
addChild(new NegativeCaseListCase(m_testCtx, "unterminated_root_4", "{test{a}"));
addChild(new NegativeCaseListCase(m_testCtx, "unterminated_root_5", "{a,b"));
addChild(new NegativeCaseListCase(m_testCtx, "unterminated_group_1", "{test{"));
addChild(new NegativeCaseListCase(m_testCtx, "unterminated_group_2", "{test{a"));
addChild(new NegativeCaseListCase(m_testCtx, "unterminated_group_3", "{test{a,"));
addChild(new NegativeCaseListCase(m_testCtx, "unterminated_group_4", "{test{a,b"));
addChild(new NegativeCaseListCase(m_testCtx, "empty_case_name_1", "{a,,b}"));
addChild(new NegativeCaseListCase(m_testCtx, "empty_case_name_2", "{,b}"));
addChild(new NegativeCaseListCase(m_testCtx, "empty_case_name_3", "{a,}"));
addChild(new NegativeCaseListCase(m_testCtx, "no_separator", "{a{b}c}"));
addChild(new NegativeCaseListCase(m_testCtx, "invalid_char_1", "{a.b}"));
addChild(new NegativeCaseListCase(m_testCtx, "invalid_char_2", "{a[]}"));
addChild(new NegativeCaseListCase(m_testCtx, "trailing_char_1", "{a}}"));
addChild(new NegativeCaseListCase(m_testCtx, "trailing_char_2", "{a}x"));
addChild(new NegativeCaseListCase(m_testCtx, "embedded_newline_1", "{\na}"));
addChild(new NegativeCaseListCase(m_testCtx, "embedded_newline_2", "{a\n,b}"));
addChild(new NegativeCaseListCase(m_testCtx, "embedded_newline_3", "{a,\nb}"));
addChild(new NegativeCaseListCase(m_testCtx, "embedded_newline_4", "{a{b\n}}"));
addChild(new NegativeCaseListCase(m_testCtx, "embedded_newline_5", "{a{b}\n}"));
}
};
class ListParserTests : public tcu::TestCaseGroup
{
public:
ListParserTests(tcu::TestContext &testCtx) : tcu::TestCaseGroup(testCtx, "list", "Test case list parser tests")
{
}
void init(void)
{
{
static const char *const caseList = "test";
static const MatchCase subCases[] = {
{"test", MatchCase::MATCH_CASE},
{"test.cd", MatchCase::NO_MATCH},
};
addChild(
new CaseListParserCase(m_testCtx, "single_case", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "a.b";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_GROUP},
{"b", MatchCase::NO_MATCH},
{"a.b", MatchCase::MATCH_CASE},
{"a.a", MatchCase::NO_MATCH},
};
addChild(
new CaseListParserCase(m_testCtx, "simple_group_1", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "a.b\na.c";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_GROUP}, {"b", MatchCase::NO_MATCH}, {"a.b", MatchCase::MATCH_CASE},
{"a.a", MatchCase::NO_MATCH}, {"a.c", MatchCase::MATCH_CASE},
};
addChild(
new CaseListParserCase(m_testCtx, "simple_group_2", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "a.b\na.c";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_GROUP}, {"b", MatchCase::NO_MATCH}, {"a.b", MatchCase::MATCH_CASE},
{"a.a", MatchCase::NO_MATCH}, {"a.c", MatchCase::MATCH_CASE},
};
addChild(
new CaseListParserCase(m_testCtx, "separator_ln", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "a.b\ra.c";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_GROUP}, {"b", MatchCase::NO_MATCH}, {"a.b", MatchCase::MATCH_CASE},
{"a.a", MatchCase::NO_MATCH}, {"a.c", MatchCase::MATCH_CASE},
};
addChild(
new CaseListParserCase(m_testCtx, "separator_cr", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "a.b\r\na.c";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_GROUP}, {"b", MatchCase::NO_MATCH}, {"a.b", MatchCase::MATCH_CASE},
{"a.a", MatchCase::NO_MATCH}, {"a.c", MatchCase::MATCH_CASE},
};
addChild(
new CaseListParserCase(m_testCtx, "separator_crlf", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "a.b\na.c\n";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_GROUP}, {"b", MatchCase::NO_MATCH}, {"a.b", MatchCase::MATCH_CASE},
{"a.a", MatchCase::NO_MATCH}, {"a.c", MatchCase::MATCH_CASE},
};
addChild(new CaseListParserCase(m_testCtx, "end_ln", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "a.b\na.c\r";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_GROUP}, {"b", MatchCase::NO_MATCH}, {"a.b", MatchCase::MATCH_CASE},
{"a.a", MatchCase::NO_MATCH}, {"a.c", MatchCase::MATCH_CASE},
};
addChild(new CaseListParserCase(m_testCtx, "end_cr", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "a.b\na.c\r\n";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_GROUP}, {"b", MatchCase::NO_MATCH}, {"a.b", MatchCase::MATCH_CASE},
{"a.a", MatchCase::NO_MATCH}, {"a.c", MatchCase::MATCH_CASE},
};
addChild(new CaseListParserCase(m_testCtx, "end_crlf", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "a.b\nc.d\nc.e";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_GROUP}, {"b", MatchCase::NO_MATCH}, {"a.b", MatchCase::MATCH_CASE},
{"a.c", MatchCase::NO_MATCH}, {"a.d", MatchCase::NO_MATCH}, {"a.e", MatchCase::NO_MATCH},
{"c", MatchCase::MATCH_GROUP}, {"c.b", MatchCase::NO_MATCH}, {"c.d", MatchCase::MATCH_CASE},
{"c.e", MatchCase::MATCH_CASE},
};
addChild(new CaseListParserCase(m_testCtx, "two_groups", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "a\nc.d\nc.e";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_CASE}, {"b", MatchCase::NO_MATCH}, {"a.b", MatchCase::NO_MATCH},
{"a.c", MatchCase::NO_MATCH}, {"a.d", MatchCase::NO_MATCH}, {"a.e", MatchCase::NO_MATCH},
{"c", MatchCase::MATCH_GROUP}, {"c.b", MatchCase::NO_MATCH}, {"c.d", MatchCase::MATCH_CASE},
{"c.e", MatchCase::MATCH_CASE},
};
addChild(new CaseListParserCase(m_testCtx, "case_group", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "c.d\nc.e\na";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_CASE}, {"b", MatchCase::NO_MATCH}, {"a.b", MatchCase::NO_MATCH},
{"a.c", MatchCase::NO_MATCH}, {"a.d", MatchCase::NO_MATCH}, {"a.e", MatchCase::NO_MATCH},
{"c", MatchCase::MATCH_GROUP}, {"c.b", MatchCase::NO_MATCH}, {"c.d", MatchCase::MATCH_CASE},
{"c.e", MatchCase::MATCH_CASE},
};
addChild(new CaseListParserCase(m_testCtx, "group_case", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.x";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_GROUP},
{"b", MatchCase::NO_MATCH},
{"a.b", MatchCase::MATCH_GROUP},
{"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.x", MatchCase::MATCH_CASE},
};
addChild(new CaseListParserCase(m_testCtx, "long_name", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "a.b.c.d.e\n"
"a.b.c.f\n"
"x.y.z\n"
"a.b.c.d.g\n"
"a.b.c.x\n";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_GROUP}, {"a.b", MatchCase::MATCH_GROUP},
{"a.b.c.d.e", MatchCase::MATCH_CASE}, {"a.b.c.d.g", MatchCase::MATCH_CASE},
{"x.y", MatchCase::MATCH_GROUP}, {"x.y.z", MatchCase::MATCH_CASE},
{"a.b.c.f", MatchCase::MATCH_CASE}, {"a.b.c.x", MatchCase::MATCH_CASE},
};
addChild(
new CaseListParserCase(m_testCtx, "partial_prefix", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
{
static const char *const caseList = "a.a.c.d\n"
"a.b.c.d\n";
static const MatchCase subCases[] = {
{"a", MatchCase::MATCH_GROUP},
{"a.a", MatchCase::MATCH_GROUP},
{"a.b.c.d", MatchCase::MATCH_CASE},
{"a.b.c.d", MatchCase::MATCH_CASE},
};
addChild(
new CaseListParserCase(m_testCtx, "reparenting", caseList, subCases, DE_LENGTH_OF_ARRAY(subCases)));
}
// Negative tests
addChild(new NegativeCaseListCase(m_testCtx, "empty_string", ""));
addChild(new NegativeCaseListCase(m_testCtx, "empty_line", "\n"));
addChild(new NegativeCaseListCase(m_testCtx, "empty_group_name", ".test"));
addChild(new NegativeCaseListCase(m_testCtx, "empty_case_name", "test."));
}
};
class CaseListParserTests : public tcu::TestCaseGroup
{
public:
CaseListParserTests(tcu::TestContext &testCtx)
: tcu::TestCaseGroup(testCtx, "case_list_parser", "Test case list parser tests")
{
}
void init(void)
{
addChild(new TrieParserTests(m_testCtx));
addChild(new ListParserTests(m_testCtx));
}
};
inline uint32_t ulpDiff(float a, float b)
{
const uint32_t ab = tcu::Float32(a).bits();
const uint32_t bb = tcu::Float32(b).bits();
return de::max(ab, bb) - de::min(ab, bb);
}
template <int Size>
inline tcu::Vector<uint32_t, Size> ulpDiff(const tcu::Vector<float, Size> &a, const tcu::Vector<float, Size> &b)
{
tcu::Vector<uint32_t, Size> res;
for (int ndx = 0; ndx < Size; ndx++)
res[ndx] = ulpDiff(a[ndx], b[ndx]);
return res;
}
class ConstantInterpolationTest : public tcu::TestCase
{
public:
ConstantInterpolationTest(tcu::TestContext &testCtx)
: tcu::TestCase(testCtx, "const_interpolation", "Constant value interpolation")
{
const int supportedMsaaLevels[] = {1, 2, 4, 8, 16};
for (int msaaNdx = 0; msaaNdx < DE_LENGTH_OF_ARRAY(supportedMsaaLevels); msaaNdx++)
{
const int numSamples = supportedMsaaLevels[msaaNdx];
{
SubCase c;
c.rtSize = tcu::IVec3(128, 128, numSamples);
c.vtx[0] = tcu::Vec4(-1.0f, -1.0f, 0.5f, 1.0f);
c.vtx[1] = tcu::Vec4(-1.0f, +1.0f, 0.5f, 1.0f);
c.vtx[2] = tcu::Vec4(+1.0f, -1.0f, 0.5f, 1.0f);
c.varying = tcu::Vec4(0.0f, 1.0f, 8.0f, -8.0f);
m_cases.push_back(c);
}
{
SubCase c;
c.rtSize = tcu::IVec3(128, 128, numSamples);
c.vtx[0] = tcu::Vec4(-1.0f, +1.0f, 0.5f, 1.0f);
c.vtx[1] = tcu::Vec4(+1.0f, -1.0f, 0.5f, 1.0f);
c.vtx[2] = tcu::Vec4(+1.0f, +1.0f, 0.5f, 1.0f);
c.varying = tcu::Vec4(0.0f, 1.0f, 8.0f, -8.0f);
m_cases.push_back(c);
}
{
SubCase c;
c.rtSize = tcu::IVec3(129, 113, numSamples);
c.vtx[0] = tcu::Vec4(-1.0f, -1.0f, 0.5f, 1.0f);
c.vtx[1] = tcu::Vec4(-1.0f, +1.0f, 0.5f, 1.0f);
c.vtx[2] = tcu::Vec4(+1.0f, -1.0f, 0.5f, 1.0f);
c.varying = tcu::Vec4(0.0f, 1.0f, 8.0f, -8.0f);
m_cases.push_back(c);
}
{
SubCase c;
c.rtSize = tcu::IVec3(107, 131, numSamples);
c.vtx[0] = tcu::Vec4(-1.0f, +1.0f, 0.5f, 1.0f);
c.vtx[1] = tcu::Vec4(+1.0f, -1.0f, 0.5f, 1.0f);
c.vtx[2] = tcu::Vec4(+1.0f, +1.0f, 0.5f, 1.0f);
c.varying = tcu::Vec4(0.0f, 1.0f, 8.0f, -8.0f);
m_cases.push_back(c);
}
}
{
de::Random rnd(0x89423f);
for (int ndx = 0; ndx < 25; ndx++)
{
const float depth = rnd.getFloat() * 2.0f - 1.0f;
SubCase c;
c.rtSize.x() = rnd.getInt(16, 256);
c.rtSize.y() = rnd.getInt(16, 256);
c.rtSize.z() = rnd.choose<int>(DE_ARRAY_BEGIN(supportedMsaaLevels), DE_ARRAY_END(supportedMsaaLevels));
for (int vtxNdx = 0; vtxNdx < DE_LENGTH_OF_ARRAY(c.vtx); vtxNdx++)
{
c.vtx[vtxNdx].x() = rnd.getFloat() * 2.0f - 1.0f;
c.vtx[vtxNdx].y() = rnd.getFloat() * 2.0f - 1.0f;
c.vtx[vtxNdx].z() = depth;
c.vtx[vtxNdx].w() = 1.0f;
}
for (int compNdx = 0; compNdx < 4; compNdx++)
{
float v;
do
{
v = tcu::Float32(rnd.getUint32()).asFloat();
} while (std::isinf(v) || std::isnan(v));
c.varying[compNdx] = v;
}
m_cases.push_back(c);
}
}
}
void init(void)
{
m_caseIter = m_cases.begin();
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "All iterations passed");
}
IterateResult iterate(void)
{
{
tcu::ScopedLogSection section(m_testCtx.getLog(), "SubCase", "");
runCase(*m_caseIter);
}
return (++m_caseIter != m_cases.end()) ? CONTINUE : STOP;
}
protected:
struct SubCase
{
tcu::IVec3 rtSize; // (width, height, samples)
tcu::Vec4 vtx[3];
tcu::Vec4 varying;
};
void runCase(const SubCase &subCase)
{
using namespace tcu;
const uint32_t maxColorUlpDiff = 2;
const uint32_t maxDepthUlpDiff = 0;
const int width = subCase.rtSize.x();
const int height = subCase.rtSize.y();
const int numSamples = subCase.rtSize.z();
const float zn = 0.0f;
const float zf = 1.0f;
TextureLevel interpolated(TextureFormat(TextureFormat::RGBA, TextureFormat::FLOAT), numSamples, width, height);
TextureLevel depthStencil(TextureFormat(TextureFormat::DS, TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV),
numSamples, width, height);
m_testCtx.getLog() << TestLog::Message << "RT size (w, h, #samples) = " << subCase.rtSize << "\n"
<< "vtx[0] = " << subCase.vtx[0] << "\n"
<< "vtx[1] = " << subCase.vtx[1] << "\n"
<< "vtx[2] = " << subCase.vtx[2] << "\n"
<< "color = " << subCase.varying << TestLog::EndMessage;
clear(interpolated.getAccess(), subCase.varying - Vec4(0.0f, 0.0f, 0.0f, 1.0f));
clearDepth(depthStencil.getAccess(), 0.0f);
clearStencil(depthStencil.getAccess(), 0);
{
class VtxShader : public rr::VertexShader
{
public:
VtxShader(void) : rr::VertexShader(2, 1)
{
m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
m_inputs[1].type = rr::GENERICVECTYPE_FLOAT;
m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
}
void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets,
const int numPackets) const
{
for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
{
rr::readVertexAttrib(packets[packetNdx]->position, inputs[0], packets[packetNdx]->instanceNdx,
packets[packetNdx]->vertexNdx);
packets[packetNdx]->outputs[0] = rr::readVertexAttribFloat(
inputs[1], packets[packetNdx]->instanceNdx, packets[packetNdx]->vertexNdx);
}
}
} vtxShader;
class FragShader : public rr::FragmentShader
{
public:
FragShader(void) : rr::FragmentShader(1, 1)
{
m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
}
void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
const rr::FragmentShadingContext &context) const
{
for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
{
for (int fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; fragNdx++)
{
const tcu::Vec4 interp =
rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx);
rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, interp);
}
}
}
} fragShader;
const rr::Program program(&vtxShader, &fragShader);
const rr::MultisamplePixelBufferAccess colorAccess =
rr::MultisamplePixelBufferAccess::fromMultisampleAccess(interpolated.getAccess());
const rr::MultisamplePixelBufferAccess dsAccess =
rr::MultisamplePixelBufferAccess::fromMultisampleAccess(depthStencil.getAccess());
const rr::RenderTarget renderTarget(colorAccess, dsAccess, dsAccess);
const rr::VertexAttrib vertexAttribs[] = {
rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, 0, 0, subCase.vtx), rr::VertexAttrib(subCase.varying)};
rr::ViewportState viewport(colorAccess);
rr::RenderState state(viewport, rr::RenderState::DEFAULT_SUBPIXEL_BITS);
const rr::PrimitiveList primitives(rr::PRIMITIVETYPE_TRIANGLES, 3, 0);
const rr::DrawCommand drawCmd(state, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs),
vertexAttribs, primitives);
const rr::Renderer renderer;
viewport.zn = zn;
viewport.zf = zf;
state.fragOps.depthTestEnabled = true;
state.fragOps.depthFunc = rr::TESTFUNC_ALWAYS;
state.fragOps.stencilTestEnabled = true;
state.fragOps.stencilStates[rr::FACETYPE_BACK].func = rr::TESTFUNC_ALWAYS;
state.fragOps.stencilStates[rr::FACETYPE_BACK].dpPass = rr::STENCILOP_INCR;
state.fragOps.stencilStates[rr::FACETYPE_FRONT] = state.fragOps.stencilStates[rr::FACETYPE_BACK];
renderer.draw(drawCmd);
}
// Verify interpolated values
{
TextureLevel resolvedColor(interpolated.getFormat(), width, height); // For debugging
TextureLevel resolvedDepthStencil(depthStencil.getFormat(), width, height); // For debugging
TextureLevel errorMask(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height);
const ConstPixelBufferAccess interpAccess = interpolated.getAccess();
const ConstPixelBufferAccess dsAccess = depthStencil.getAccess();
const PixelBufferAccess errorAccess = errorMask.getAccess();
int numCoveredSamples = 0;
int numFailedColorSamples = 0;
int numFailedDepthSamples = 0;
const bool verifyDepth =
(subCase.vtx[0].z() == subCase.vtx[1].z()) && (subCase.vtx[1].z() == subCase.vtx[2].z());
const float refDepth = subCase.vtx[0].z() * (zf - zn) / 2.0f + (zn + zf) / 2.0f;
rr::resolveMultisampleBuffer(
resolvedColor.getAccess(),
rr::MultisampleConstPixelBufferAccess::fromMultisampleAccess(interpolated.getAccess()));
rr::resolveMultisampleBuffer(
resolvedDepthStencil.getAccess(),
rr::MultisampleConstPixelBufferAccess::fromMultisampleAccess(depthStencil.getAccess()));
clear(errorAccess, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
for (int sampleNdx = 0; sampleNdx < numSamples; sampleNdx++)
{
if (dsAccess.getPixStencil(sampleNdx, x, y) != 0)
{
const Vec4 color = interpAccess.getPixel(sampleNdx, x, y);
const UVec4 colorDiff = ulpDiff(color, subCase.varying);
const bool colorOk = boolAll(lessThanEqual(colorDiff, tcu::UVec4(maxColorUlpDiff)));
const float depth = dsAccess.getPixDepth(sampleNdx, x, y);
const uint32_t depthDiff = ulpDiff(depth, refDepth);
const bool depthOk = verifyDepth && (depthDiff <= maxDepthUlpDiff);
const int maxMsgs = 10;
numCoveredSamples += 1;
if (!colorOk)
{
numFailedColorSamples += 1;
if (numFailedColorSamples <= maxMsgs)
m_testCtx.getLog() << TestLog::Message << "FAIL: " << tcu::IVec3(x, y, sampleNdx)
<< " color ulp diff = " << colorDiff << TestLog::EndMessage;
}
if (!depthOk)
numFailedDepthSamples += 1;
if (!colorOk || !depthOk)
errorAccess.setPixel(errorAccess.getPixel(x, y) +
Vec4(1.0f, -1.0f, 0.0f, 0.0f) / float(numSamples - 1),
x, y);
}
}
}
}
m_testCtx.getLog() << TestLog::Image("ResolvedColor", "Resolved colorbuffer", resolvedColor)
<< TestLog::Image("ResolvedDepthStencil", "Resolved depth- & stencilbuffer",
resolvedDepthStencil);
if (numFailedColorSamples != 0 || numFailedDepthSamples != 0)
{
m_testCtx.getLog() << TestLog::Image("ErrorMask", "Error mask", errorMask);
if (numFailedColorSamples != 0)
m_testCtx.getLog() << TestLog::Message << "FAIL: Found " << numFailedColorSamples
<< " invalid color samples!" << TestLog::EndMessage;
if (numFailedDepthSamples != 0)
m_testCtx.getLog() << TestLog::Message << "FAIL: Found " << numFailedDepthSamples
<< " invalid depth samples!" << TestLog::EndMessage;
if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid samples found");
}
m_testCtx.getLog() << TestLog::Message << (numCoveredSamples - numFailedColorSamples) << " / "
<< numCoveredSamples << " color samples passed" << TestLog::EndMessage;
m_testCtx.getLog() << TestLog::Message << (numCoveredSamples - numFailedDepthSamples) << " / "
<< numCoveredSamples << " depth samples passed" << TestLog::EndMessage;
}
}
vector<SubCase> m_cases;
vector<SubCase>::const_iterator m_caseIter;
};
class CommonFrameworkTests : public tcu::TestCaseGroup
{
public:
CommonFrameworkTests(tcu::TestContext &testCtx)
: tcu::TestCaseGroup(testCtx, "common", "Tests for the common utility framework")
{
}
void init(void)
{
addChild(
new SelfCheckCase(m_testCtx, "float_format", "tcu::FloatFormat_selfTest()", tcu::FloatFormat_selfTest));
addChild(new SelfCheckCase(m_testCtx, "either", "tcu::Either_selfTest()", tcu::Either_selfTest));
}
};
class ReferenceRendererTests : public tcu::TestCaseGroup
{
public:
ReferenceRendererTests(tcu::TestContext &testCtx)
: tcu::TestCaseGroup(testCtx, "reference_renderer", "Reference renderer tests")
{
}
void init(void)
{
addChild(new ConstantInterpolationTest(m_testCtx));
}
};
} // namespace
FrameworkTests::FrameworkTests(tcu::TestContext &testCtx)
: tcu::TestCaseGroup(testCtx, "framework", "Miscellaneous framework tests")
{
}
FrameworkTests::~FrameworkTests(void)
{
}
void FrameworkTests::init(void)
{
addChild(new CommonFrameworkTests(m_testCtx));
addChild(new CaseListParserTests(m_testCtx));
addChild(new ReferenceRendererTests(m_testCtx));
addChild(createTextureFormatTests(m_testCtx));
addChild(createAstcTests(m_testCtx));
addChild(createVulkanTests(m_testCtx));
}
} // namespace dit