mirror of
https://github.com/lubosz/overte.git
synced 2025-04-07 15:22:09 +02:00
Working on texture test
This commit is contained in:
parent
1d403b4d67
commit
7fbad47351
7 changed files with 214 additions and 49 deletions
3
libraries/test-utils/CMakeLists.txt
Normal file
3
libraries/test-utils/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
set(TARGET_NAME test-utils)
|
||||
setup_hifi_library(Network Gui)
|
||||
|
21
libraries/test-utils/src/test-utils/FileDownloader.cpp
Normal file
21
libraries/test-utils/src/test-utils/FileDownloader.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "FileDownloader.h"
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
FileDownloader::FileDownloader(QUrl url, const Handler& handler, QObject* parent) : QObject(parent), _handler(handler) {
|
||||
connect(&_accessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(fileDownloaded(QNetworkReply*)));
|
||||
_accessManager.get(QNetworkRequest(url));
|
||||
}
|
||||
|
||||
void FileDownloader::waitForDownload() {
|
||||
while (!_complete) {
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
}
|
||||
|
||||
void FileDownloader::fileDownloaded(QNetworkReply* pReply) {
|
||||
_handler(pReply->readAll());
|
||||
pReply->deleteLater();
|
||||
_complete = true;
|
||||
}
|
23
libraries/test-utils/src/test-utils/FileDownloader.h
Normal file
23
libraries/test-utils/src/test-utils/FileDownloader.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
|
||||
class FileDownloader : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using Handler = std::function<void(const QByteArray& data)>;
|
||||
|
||||
FileDownloader(QUrl url, const Handler& handler, QObject* parent = 0);
|
||||
|
||||
void waitForDownload();
|
||||
|
||||
private slots:
|
||||
void fileDownloaded(QNetworkReply* pReply);
|
||||
|
||||
private:
|
||||
QNetworkAccessManager _accessManager;
|
||||
Handler _handler;
|
||||
bool _complete { false };
|
||||
};
|
|
@ -13,8 +13,9 @@
|
|||
#define hifi_QTestExtensions_hpp
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <functional>
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
#include "GLMTestUtils.h"
|
||||
|
||||
// Implements several extensions to QtTest.
|
||||
|
@ -302,3 +303,43 @@ inline auto errorTest (float actual, float expected, float acceptableRelativeErr
|
|||
QCOMPARE_WITH_LAMBDA(actual, expected, errorTest(actual, expected, relativeError))
|
||||
|
||||
|
||||
|
||||
inline QString getTestResource(const QString& relativePath) {
|
||||
static QDir dir;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, []{
|
||||
QFileInfo fileInfo(__FILE__);
|
||||
auto parentDir = fileInfo.absoluteDir();
|
||||
auto rootDir = parentDir.absoluteFilePath("..");
|
||||
dir = QDir::cleanPath(rootDir);
|
||||
});
|
||||
|
||||
return QDir::cleanPath(dir.absoluteFilePath(relativePath));
|
||||
}
|
||||
|
||||
inline bool afterUsecs(uint64_t& startUsecs, uint64_t maxIntervalUecs) {
|
||||
auto now = usecTimestampNow();
|
||||
auto interval = now - startUsecs;
|
||||
if (interval > maxIntervalUecs) {
|
||||
startUsecs = now;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool afterSecs(uint64_t& startUsecs, uint64_t maxIntervalSecs) {
|
||||
return afterUsecs(startUsecs, maxIntervalSecs * USECS_PER_SECOND);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void reportEvery(uint64_t& lastReportUsecs, uint64_t secs, F lamdba) {
|
||||
if (afterSecs(lastReportUsecs, secs)) {
|
||||
lamdba();
|
||||
}
|
||||
}
|
||||
|
||||
inline void failAfter(uint64_t startUsecs, uint64_t secs, const char* message) {
|
||||
if (afterSecs(startUsecs, secs)) {
|
||||
QFAIL(message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
# Declare dependencies
|
||||
macro (setup_testcase_dependencies)
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared ktx gpu gl ${PLATFORM_GL_BACKEND})
|
||||
link_hifi_libraries(shared test-utils ktx gpu gl ${PLATFORM_GL_BACKEND})
|
||||
package_libraries_for_deployment()
|
||||
target_opengl()
|
||||
target_zlib()
|
||||
find_package(QuaZip REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${QUAZIP_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${QUAZIP_LIBRARIES})
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${QUAZIP_DLL_PATH})
|
||||
add_dependency_external_projects(wasapi)
|
||||
endif ()
|
||||
endmacro ()
|
||||
|
||||
setup_hifi_testcase()
|
||||
|
|
|
@ -8,16 +8,27 @@
|
|||
|
||||
#include "TextureTest.h"
|
||||
|
||||
#include <QtCore/QTemporaryFile>
|
||||
|
||||
#include <gpu/Forward.h>
|
||||
#include <gl/Config.h>
|
||||
#include <gl/GLHelpers.h>
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <test-utils/FileDownloader.h>
|
||||
|
||||
#include <quazip5/quazip.h>
|
||||
#include <quazip5/JlCompress.h>
|
||||
|
||||
#include "../../QTestExtensions.h"
|
||||
|
||||
#pragma optimize("", off)
|
||||
|
||||
QTEST_MAIN(TextureTest)
|
||||
#pragma optimize("", off)
|
||||
|
||||
#define LOAD_TEXTURE_COUNT 40
|
||||
static const QDir TEST_DIR("D:/ktx_texture_test");
|
||||
|
||||
static const QString TEST_DATA("https://hifi-public.s3.amazonaws.com/austin/test_data/test_ktx.zip");
|
||||
|
||||
std::string vertexShaderSource = R"SHADER(
|
||||
#line 14
|
||||
|
@ -54,7 +65,10 @@ void main() {
|
|||
|
||||
)SHADER";
|
||||
|
||||
#define USE_SERVER_DATA 1
|
||||
|
||||
void TextureTest::initTestCase() {
|
||||
_resourcesPath = getTestResource("interface/resources");
|
||||
getDefaultOpenGLSurfaceFormat();
|
||||
_canvas.create();
|
||||
if (!_canvas.makeCurrent()) {
|
||||
|
@ -63,7 +77,32 @@ void TextureTest::initTestCase() {
|
|||
gl::initModuleGl();
|
||||
gpu::Context::init<gpu::gl::GLBackend>();
|
||||
_gpuContext = std::make_shared<gpu::Context>();
|
||||
gpu::Texture::setAllowedGPUMemoryUsage(MB_TO_BYTES(4096));
|
||||
#if USE_SERVER_DATA
|
||||
if (!_testDataDir.isValid()) {
|
||||
qFatal("Unable to create temp directory");
|
||||
}
|
||||
|
||||
QString path = _testDataDir.path();
|
||||
FileDownloader(TEST_DATA,
|
||||
[&](const QByteArray& data) {
|
||||
QTemporaryFile zipFile;
|
||||
if (zipFile.open()) {
|
||||
zipFile.write(data);
|
||||
zipFile.close();
|
||||
}
|
||||
if (!_testDataDir.isValid()) {
|
||||
qFatal("Unable to create temp dir");
|
||||
}
|
||||
auto files = JlCompress::extractDir(zipFile.fileName(), _testDataDir.path());
|
||||
for (const auto& file : files) {
|
||||
qDebug() << file;
|
||||
}
|
||||
})
|
||||
.waitForDownload();
|
||||
_resourcesPath = _testDataDir.path();
|
||||
#else
|
||||
_resourcesPath = "D:/test_ktx";
|
||||
#endif
|
||||
|
||||
_canvas.makeCurrent();
|
||||
{
|
||||
|
@ -80,19 +119,21 @@ void TextureTest::initTestCase() {
|
|||
_pipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
{ _framebuffer.reset(gpu::Framebuffer::create("cached", gpu::Element::COLOR_SRGBA_32, _size.x, _size.y)); }
|
||||
_framebuffer.reset(gpu::Framebuffer::create("cached", gpu::Element::COLOR_SRGBA_32, _size.x, _size.y));
|
||||
|
||||
// Find the test textures
|
||||
{
|
||||
auto entryList = TEST_DIR.entryList({ "*.ktx" }, QDir::Filter::Files);
|
||||
QDir resourcesDir(_resourcesPath);
|
||||
auto entryList = resourcesDir.entryList({ "*.ktx" }, QDir::Filter::Files);
|
||||
_textureFiles.reserve(entryList.size());
|
||||
for (auto entry : entryList) {
|
||||
auto textureFile = TEST_DIR.absoluteFilePath(entry).toStdString();
|
||||
auto textureFile = resourcesDir.absoluteFilePath(entry).toStdString();
|
||||
_textureFiles.push_back(textureFile);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the test textures
|
||||
{
|
||||
std::shuffle(_textureFiles.begin(), _textureFiles.end(), std::default_random_engine());
|
||||
size_t newTextureCount = std::min<size_t>(_textureFiles.size(), LOAD_TEXTURE_COUNT);
|
||||
for (size_t i = 0; i < newTextureCount; ++i) {
|
||||
const auto& textureFile = _textureFiles[i];
|
||||
|
@ -103,6 +144,9 @@ void TextureTest::initTestCase() {
|
|||
}
|
||||
|
||||
void TextureTest::cleanupTestCase() {
|
||||
_framebuffer.reset();
|
||||
_pipeline.reset();
|
||||
_gpuContext->recycle();
|
||||
_gpuContext.reset();
|
||||
}
|
||||
|
||||
|
@ -133,35 +177,8 @@ void TextureTest::renderFrame(const std::function<void(gpu::Batch&)>& renderLamb
|
|||
endFrame();
|
||||
}
|
||||
|
||||
|
||||
inline bool afterUsecs(uint64_t& startUsecs, uint64_t maxIntervalUecs) {
|
||||
auto now = usecTimestampNow();
|
||||
auto interval = now - startUsecs;
|
||||
if (interval > maxIntervalUecs) {
|
||||
startUsecs = now;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool afterSecs(uint64_t& startUsecs, uint64_t maxIntervalSecs) {
|
||||
return afterUsecs(startUsecs, maxIntervalSecs * USECS_PER_SECOND);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void reportEvery(uint64_t& lastReportUsecs, uint64_t secs, F lamdba) {
|
||||
if (afterSecs(lastReportUsecs, secs)) {
|
||||
lamdba();
|
||||
}
|
||||
}
|
||||
|
||||
inline void failAfter(uint64_t startUsecs, uint64_t secs, const char* message) {
|
||||
if (afterSecs(startUsecs, secs)) {
|
||||
qFatal(message);
|
||||
}
|
||||
}
|
||||
|
||||
void TextureTest::testTextureLoading() {
|
||||
QVERIFY(_textures.size() > 0);
|
||||
auto renderTexturesLamdba = [this](gpu::Batch& batch) {
|
||||
batch.setPipeline(_pipeline);
|
||||
for (const auto& texture : _textures) {
|
||||
|
@ -170,39 +187,87 @@ void TextureTest::testTextureLoading() {
|
|||
}
|
||||
};
|
||||
|
||||
size_t totalSize = 0;
|
||||
size_t expectedAllocation = 0;
|
||||
for (const auto& texture : _textures) {
|
||||
totalSize += texture->evalTotalSize();
|
||||
expectedAllocation += texture->evalTotalSize();
|
||||
}
|
||||
QVERIFY(_textures.size() > 0);
|
||||
|
||||
auto reportLambda = [=] {
|
||||
qDebug() << "Expected" << totalSize;
|
||||
qDebug() << "Allowed " << gpu::Texture::getAllowedGPUMemoryUsage();
|
||||
qDebug() << "Allowed " << gpu::Texture::getAllowedGPUMemoryUsage();
|
||||
qDebug() << "Allocated " << gpu::Context::getTextureResourceGPUMemSize();
|
||||
qDebug() << "Populated " << gpu::Context::getTextureResourcePopulatedGPUMemSize();
|
||||
qDebug() << "Pending " << gpu::Context::getTexturePendingGPUTransferMemSize();
|
||||
};
|
||||
|
||||
auto allocatedMemory = gpu::Context::getTextureResourceGPUMemSize();
|
||||
auto populatedMemory = gpu::Context::getTextureResourcePopulatedGPUMemSize();
|
||||
|
||||
// Cycle frames we're fully allocated
|
||||
// We need to use the texture rendering lambda
|
||||
auto lastReport = usecTimestampNow();
|
||||
auto start = usecTimestampNow();
|
||||
while (totalSize != gpu::Context::getTextureResourceGPUMemSize()) {
|
||||
while (expectedAllocation != allocatedMemory) {
|
||||
reportEvery(lastReport, 4, reportLambda);
|
||||
failAfter(start, 10, "Failed to allocate texture memory after 10 seconds");
|
||||
renderFrame(renderTexturesLamdba);
|
||||
allocatedMemory = gpu::Context::getTextureResourceGPUMemSize();
|
||||
populatedMemory = gpu::Context::getTextureResourcePopulatedGPUMemSize();
|
||||
}
|
||||
QCOMPARE(allocatedMemory, expectedAllocation);
|
||||
|
||||
// Restart the timer
|
||||
start = usecTimestampNow();
|
||||
auto allocatedMemory = gpu::Context::getTextureResourceGPUMemSize();
|
||||
auto populatedMemory = gpu::Context::getTextureResourcePopulatedGPUMemSize();
|
||||
while (allocatedMemory != populatedMemory && 0 != gpu::Context::getTexturePendingGPUTransferMemSize()) {
|
||||
// Cycle frames we're fully populated
|
||||
while (allocatedMemory != populatedMemory || 0 != gpu::Context::getTexturePendingGPUTransferMemSize()) {
|
||||
reportEvery(lastReport, 4, reportLambda);
|
||||
failAfter(start, 10, "Failed to populate texture memory after 10 seconds");
|
||||
renderFrame();
|
||||
allocatedMemory = gpu::Context::getTextureResourceGPUMemSize();
|
||||
populatedMemory = gpu::Context::getTextureResourcePopulatedGPUMemSize();
|
||||
}
|
||||
QCOMPARE(allocatedMemory, totalSize);
|
||||
QCOMPARE(populatedMemory, totalSize);
|
||||
}
|
||||
reportLambda();
|
||||
QCOMPARE(populatedMemory, allocatedMemory);
|
||||
|
||||
// FIXME workaround a race condition in the difference between populated size and the actual _populatedMip value in the texture
|
||||
for (size_t i = 0; i < _textures.size(); ++i) {
|
||||
renderFrame();
|
||||
}
|
||||
|
||||
// Test on-demand deallocation of memory
|
||||
auto maxMemory = allocatedMemory / 2;
|
||||
gpu::Texture::setAllowedGPUMemoryUsage(maxMemory);
|
||||
|
||||
// Restart the timer
|
||||
start = usecTimestampNow();
|
||||
// Cycle frames until the allocated memory is below the max memory
|
||||
while (allocatedMemory > maxMemory || allocatedMemory != populatedMemory) {
|
||||
reportEvery(lastReport, 4, reportLambda);
|
||||
failAfter(start, 10, "Failed to deallocate texture memory after 10 seconds");
|
||||
renderFrame(renderTexturesLamdba);
|
||||
allocatedMemory = gpu::Context::getTextureResourceGPUMemSize();
|
||||
populatedMemory = gpu::Context::getTextureResourcePopulatedGPUMemSize();
|
||||
}
|
||||
reportLambda();
|
||||
|
||||
// Verify that the allocation is now below the target
|
||||
QVERIFY(allocatedMemory <= maxMemory);
|
||||
// Verify that populated memory is the same as allocated memory
|
||||
QCOMPARE(populatedMemory, allocatedMemory);
|
||||
|
||||
// Restart the timer
|
||||
start = usecTimestampNow();
|
||||
// Reset the max memory to automatic
|
||||
gpu::Texture::setAllowedGPUMemoryUsage(0);
|
||||
// Cycle frames we're fully populated
|
||||
while (allocatedMemory != expectedAllocation || allocatedMemory != populatedMemory) {
|
||||
reportEvery(lastReport, 4, reportLambda);
|
||||
failAfter(start, 10, "Failed to populate texture memory after 10 seconds");
|
||||
renderFrame();
|
||||
allocatedMemory = gpu::Context::getTextureResourceGPUMemSize();
|
||||
populatedMemory = gpu::Context::getTextureResourcePopulatedGPUMemSize();
|
||||
}
|
||||
reportLambda();
|
||||
QCOMPARE(allocatedMemory, expectedAllocation);
|
||||
QCOMPARE(populatedMemory, allocatedMemory);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
#include <QtCore/QTemporaryDir>
|
||||
|
||||
#include <gpu/Forward.h>
|
||||
#include <gl/OffscreenGLCanvas.h>
|
||||
|
||||
|
@ -18,7 +20,7 @@ class TextureTest : public QObject {
|
|||
private:
|
||||
void beginFrame();
|
||||
void endFrame();
|
||||
void renderFrame(const std::function<void(gpu::Batch&)>& = [](gpu::Batch&){});
|
||||
void renderFrame(const std::function<void(gpu::Batch&)>& = [](gpu::Batch&) {});
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
|
@ -26,6 +28,8 @@ private slots:
|
|||
void testTextureLoading();
|
||||
|
||||
private:
|
||||
QString _resourcesPath;
|
||||
QTemporaryDir _testDataDir;
|
||||
OffscreenGLCanvas _canvas;
|
||||
gpu::ContextPointer _gpuContext;
|
||||
gpu::PipelinePointer _pipeline;
|
||||
|
|
Loading…
Reference in a new issue