Revision control

Copy as Markdown

// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest>
#include <QtCore/qbytearray.h>
#include <QtCore/qfile.h>
#include <rhi/qshaderbaker.h>
#include <QtQuick3DUtils/private/qqsbcollection_p.h>
static const char *shaderDescription() { return "ShaderDescription"; }
static const char *tempOutFileName() { return "qsbctstfile.qsbc"; }
static const char *vertSource() {
return "#version 310 es\n"
"layout (location = 0) in vec3 pos;\n"
"layout (location = 1) out vec4 vertColor;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(pos, 1.0);\n"
" vertColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
"}\n";
}
static const char *fragSource() {
return "#version 310 es\n"
"precision lowp float;\n"
"layout (location = 0) out vec4 glColor;\n"
"layout (location = 1) in vec4 vertColor;\n"
"void main()\n"
"{\n"
" glColor = vertColor;\n"
"}\n";
}
class ShaderCollection : public QObject
{
Q_OBJECT
public:
ShaderCollection() = default;
~ShaderCollection() = default;
private Q_SLOTS:
void initTestCase();
void test_readWriteToFile();
void test_readWriteToBuffer();
void test_readWriteOpenDevice();
void test_mapModes();
void test_inMemoryCollection();
private:
QShader vert;
QShader frag;
QQsbCollection::FeatureSet featureSet;
};
void ShaderCollection::initTestCase()
{
QShaderBaker baker;
baker.setGeneratedShaders({{ QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs) }});
baker.setGeneratedShaderVariants({ QShader::StandardShader });
baker.setSourceString(vertSource(), QShader::VertexStage);
vert = baker.bake();
QVERIFY2(vert.isValid(), qPrintable(baker.errorMessage()));
baker.setSourceString(fragSource(), QShader::FragmentStage);
frag = baker.bake();
QVERIFY2(frag.isValid(), qPrintable(baker.errorMessage()));
featureSet.insert("feature1", true);
featureSet.insert("feature2", false);
}
void ShaderCollection::test_readWriteToFile()
{
const QByteArray hkey = QByteArrayLiteral("12345");
const auto tempFile = QDir::tempPath() + QDir::separator() + tempOutFileName();
QQsbCollection::Entry entry;
{
QQsbIODeviceCollection qsbc(tempFile);
QVERIFY(qsbc.map(QQsbIODeviceCollection::Write));
entry = qsbc.addEntry(hkey, { QByteArray(shaderDescription()), featureSet, vert, frag });
QVERIFY(entry.value != -1);
QCOMPARE(entry.key, hkey);
const auto entries = qsbc.availableEntries();
QCOMPARE(entries.size(), 1);
QCOMPARE(*entries.begin(), entry);
qsbc.unmap();
}
{
QQsbIODeviceCollection qsbc(tempFile);
QVERIFY(qsbc.map(QQsbIODeviceCollection::Read));
const auto entries = qsbc.availableEntries();
QCOMPARE(entries.size(), 1);
QCOMPARE(*entries.begin(), entry);
QQsbCollection::EntryDesc entryDesc;
QVERIFY(qsbc.extractEntry(entry, entryDesc));
QCOMPARE(entryDesc.materialKey, QByteArray(shaderDescription()));
QCOMPARE(entryDesc.vertShader, vert);
QCOMPARE(entryDesc.fragShader, frag);
QCOMPARE(entryDesc.featureSet, featureSet);
qsbc.unmap();
}
}
void ShaderCollection::test_readWriteToBuffer()
{
QBuffer buffer;
const QByteArray hkey = QByteArrayLiteral("12345");
QQsbCollection::Entry entry;
{
QVERIFY(buffer.buffer().isEmpty());
QQsbIODeviceCollection qsbc(buffer);
QVERIFY(qsbc.map(QQsbIODeviceCollection::Write));
entry = qsbc.addEntry(hkey, { QByteArray(shaderDescription()), featureSet, vert, frag });
QVERIFY(entry.value != -1);
QCOMPARE(entry.key, hkey);
qsbc.unmap();
QVERIFY(!buffer.buffer().isEmpty());
}
{
QQsbIODeviceCollection qsbc(buffer);
QVERIFY(qsbc.map(QQsbIODeviceCollection::Read));
QQsbCollection::EntryDesc entryDesc;
QVERIFY(qsbc.extractEntry(entry, entryDesc));
QCOMPARE(entryDesc.materialKey, QByteArray(shaderDescription()));
QCOMPARE(entryDesc.vertShader, vert);
QCOMPARE(entryDesc.fragShader, frag);
QCOMPARE(entryDesc.featureSet, featureSet);
qsbc.unmap();
}
}
void ShaderCollection::test_readWriteOpenDevice()
{
QBuffer buffer;
const QByteArray hkey = QByteArrayLiteral("12345");
QQsbCollection::Entry entry;
{
buffer.open(QIODevice::WriteOnly | QIODevice::Truncate);
QCOMPARE(buffer.isOpen(), true);
QVERIFY(buffer.buffer().isEmpty());
QQsbIODeviceCollection qsbc(buffer);
QVERIFY(qsbc.map(QQsbIODeviceCollection::Write));
entry = qsbc.addEntry(hkey, { QByteArray(shaderDescription()), featureSet, vert, frag });
QVERIFY(entry.value != -1);
QCOMPARE(entry.key, hkey);
qsbc.unmap();
QVERIFY(!buffer.buffer().isEmpty());
}
QCOMPARE(buffer.isOpen(), false);
{
buffer.open(QIODevice::ReadOnly);
QCOMPARE(buffer.isOpen(), true);
QQsbIODeviceCollection qsbc(buffer);
QVERIFY(qsbc.map(QQsbIODeviceCollection::Read));
QQsbCollection::EntryDesc entryDesc;
QVERIFY(qsbc.extractEntry(entry, entryDesc));
QCOMPARE(entryDesc.materialKey, QByteArray(shaderDescription()));
QCOMPARE(entryDesc.vertShader, vert);
QCOMPARE(entryDesc.fragShader, frag);
QCOMPARE(entryDesc.featureSet, featureSet);
qsbc.unmap();
}
}
void ShaderCollection::test_mapModes()
{
{
QBuffer buffer;
const QByteArray hkey = QByteArrayLiteral("12345");
QQsbCollection::Entry entry;
{
buffer.open(QIODevice::ReadWrite | QIODevice::Truncate);
QCOMPARE(buffer.isOpen(), true);
QVERIFY(buffer.buffer().isEmpty());
QQsbIODeviceCollection qsbc(buffer);
QVERIFY(qsbc.map(QQsbIODeviceCollection::Write));
entry = qsbc.addEntry(hkey, { QByteArray(shaderDescription()), featureSet, vert, frag });
QVERIFY(entry.value != -1);
QCOMPARE(entry.key, hkey);
qsbc.unmap();
QVERIFY(!buffer.buffer().isEmpty());
}
QCOMPARE(buffer.isOpen(), false);
{
buffer.open(QIODevice::ReadOnly);
QCOMPARE(buffer.isOpen(), true);
QQsbIODeviceCollection qsbc(buffer);
QVERIFY(qsbc.map(QQsbIODeviceCollection::Read));
QQsbCollection::EntryDesc entryDesc;
QVERIFY(qsbc.extractEntry(entry, entryDesc));
QCOMPARE(entryDesc.materialKey, QByteArray(shaderDescription()));
QCOMPARE(entryDesc.vertShader, vert);
QCOMPARE(entryDesc.fragShader, frag);
QCOMPARE(entryDesc.featureSet, featureSet);
qsbc.unmap();
}
}
{
QBuffer buffer;
const QByteArray hkey = QByteArrayLiteral("12345");
QQsbCollection::Entry entry;
{ // Test invalid input (missing Truncate)
buffer.open(QIODevice::ReadWrite);
QCOMPARE(buffer.isOpen(), true);
QVERIFY(buffer.buffer().isEmpty());
QQsbIODeviceCollection qsbc(buffer);
QCOMPARE(qsbc.map(QQsbIODeviceCollection::Write), false);
entry = qsbc.addEntry(hkey, { QByteArray(shaderDescription()), featureSet, vert, frag });
QCOMPARE(entry.isValid(), false);
qsbc.unmap();
QVERIFY(buffer.buffer().isEmpty());
}
{ // Test invalid input (Text)
buffer.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text);
QCOMPARE(buffer.isOpen(), true);
QVERIFY(buffer.buffer().isEmpty());
QQsbIODeviceCollection qsbc(buffer);
QCOMPARE(qsbc.map(QQsbIODeviceCollection::Write), false);
entry = qsbc.addEntry(hkey, { QByteArray(shaderDescription()), featureSet, vert, frag });
QCOMPARE(entry.isValid(), false);
qsbc.unmap();
QVERIFY(buffer.buffer().isEmpty());
}
}
}
void ShaderCollection::test_inMemoryCollection()
{
QQsbInMemoryCollection qsbc;
QVERIFY(qsbc.availableEntries().isEmpty());
const QByteArray hkey = QByteArrayLiteral("12345");
const QByteArray otherKey = QByteArrayLiteral("12346");
QQsbCollection::Entry entry;
QVERIFY(!entry.isValid());
{
entry = qsbc.addEntry(hkey, { QByteArray(shaderDescription()), featureSet, vert, frag });
QVERIFY(entry.isValid());
QVERIFY(qsbc.availableEntries().contains(entry));
qsbc.clear();
QVERIFY(qsbc.availableEntries().isEmpty());
}
{
entry = qsbc.addEntry(hkey, { QByteArray(shaderDescription()), featureSet, vert, frag });
QVERIFY(entry.isValid());
entry = qsbc.addEntry(hkey, { QByteArray(shaderDescription()), featureSet, vert, frag });
QVERIFY(!entry.isValid()); // already added, this must fail
entry = qsbc.addEntry(otherKey, { QByteArray(shaderDescription()), featureSet, vert, frag });
QVERIFY(entry.isValid());
QVERIFY(qsbc.availableEntries().count() == 2);
QQsbCollection::EntryDesc entryDesc;
QVERIFY(qsbc.extractEntry(entry, entryDesc));
QCOMPARE(entryDesc.materialKey, QByteArray(shaderDescription()));
QCOMPARE(entryDesc.vertShader, vert);
QCOMPARE(entryDesc.fragShader, frag);
QCOMPARE(entryDesc.featureSet, featureSet);
}
}
QTEST_APPLESS_MAIN(ShaderCollection)
#include "tst_shadercollection.moc"