mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-11 09:12:25 +02:00
Merge pull request #13125 from jherico/feature/testing
Working on improved unit testing, adding texture transfer testing
This commit is contained in:
commit
fd9669b42d
89 changed files with 1175 additions and 114 deletions
|
@ -180,6 +180,7 @@ add_subdirectory(tools)
|
|||
|
||||
if (BUILD_TESTS)
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(tests-manual)
|
||||
endif()
|
||||
|
||||
if (BUILD_INSTALLER)
|
||||
|
|
|
@ -124,15 +124,14 @@ macro(SETUP_HIFI_TESTCASE)
|
|||
# This target will also build + run the other test targets using ctest when built.
|
||||
|
||||
add_custom_target(${TEST_TARGET}
|
||||
COMMAND ctest .
|
||||
SOURCES ${TEST_PROJ_SRC_FILES} # display source files under the testcase target
|
||||
DEPENDS ${${TEST_PROJ_NAME}_TARGETS})
|
||||
|
||||
set_target_properties(${TEST_TARGET} PROPERTIES
|
||||
FOLDER "Tests"
|
||||
EXCLUDE_FROM_DEFAULT_BUILD TRUE
|
||||
EXCLUDE_FROM_ALL TRUE)
|
||||
|
||||
set_target_properties(${TEST_TARGET} PROPERTIES FOLDER "Tests")
|
||||
|
||||
list (APPEND ALL_TEST_TARGETS ${TEST_TARGET})
|
||||
set(ALL_TEST_TARGETS "${ALL_TEST_TARGETS}" PARENT_SCOPE)
|
||||
else ()
|
||||
|
|
|
@ -103,12 +103,15 @@ void OffscreenGLCanvas::onMessageLogged(const QOpenGLDebugMessage& debugMessage)
|
|||
|
||||
bool OffscreenGLCanvas::makeCurrent() {
|
||||
bool result = _context->makeCurrent(_offscreenSurface);
|
||||
std::call_once(_reportOnce, []{
|
||||
qCDebug(glLogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION));
|
||||
qCDebug(glLogging) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
qCDebug(glLogging) << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR));
|
||||
qCDebug(glLogging) << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER));
|
||||
});
|
||||
if (glGetString) {
|
||||
std::call_once(_reportOnce, [] {
|
||||
qCDebug(glLogging) << "GL Version: " << QString((const char*)glGetString(GL_VERSION));
|
||||
qCDebug(glLogging) << "GL Shader Language Version: "
|
||||
<< QString((const char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
qCDebug(glLogging) << "GL Vendor: " << QString((const char*)glGetString(GL_VENDOR));
|
||||
qCDebug(glLogging) << "GL Renderer: " << QString((const char*)glGetString(GL_RENDERER));
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
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 };
|
||||
};
|
8
tests-manual/CMakeLists.txt
Normal file
8
tests-manual/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
# add the manual test directories
|
||||
file(GLOB TEST_SUBDIRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/*")
|
||||
foreach(DIR ${TEST_SUBDIRS})
|
||||
if((IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${DIR}") AND (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${DIR}/CMakeLists.txt"))
|
||||
set(TEST_PROJ_NAME ${DIR})
|
||||
add_subdirectory(${DIR})
|
||||
endif()
|
||||
endforeach()
|
16
tests-manual/gpu-textures/CMakeLists.txt
Normal file
16
tests-manual/gpu-textures/CMakeLists.txt
Normal file
|
@ -0,0 +1,16 @@
|
|||
set(TARGET_NAME gpu-textures-tests)
|
||||
AUTOSCRIBE_SHADER_LIB(gpu graphics render-utils)
|
||||
# This is not a testcase -- just set it up as a regular hifi project
|
||||
setup_hifi_project(Quick Gui Script)
|
||||
setup_memory_debugger()
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||
link_hifi_libraries(
|
||||
shared task networking gl
|
||||
ktx gpu octree
|
||||
${PLATFORM_GL_BACKEND}
|
||||
)
|
||||
|
||||
set(EXTRA_DEPLOY_OPTIONS "--qmldir \"${PROJECT_SOURCE_DIR}/qml\"")
|
||||
package_libraries_for_deployment()
|
||||
|
||||
target_nsight()
|
52
tests-manual/gpu-textures/qml/textureStats.qml
Normal file
52
tests-manual/gpu-textures/qml/textureStats.qml
Normal file
|
@ -0,0 +1,52 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 2.3
|
||||
|
||||
Item {
|
||||
width: 400
|
||||
height: 600
|
||||
|
||||
Column {
|
||||
spacing: 10
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 10
|
||||
|
||||
Text { text: qsTr("Total") }
|
||||
Text { text: Stats.total + " MB" }
|
||||
Text { text: qsTr("Allocated") }
|
||||
Text { text: Stats.allocated }
|
||||
Text { text: qsTr("Populated") }
|
||||
Text { text: Stats.populated }
|
||||
Text { text: qsTr("Pending") }
|
||||
Text { text: Stats.pending }
|
||||
Text { text: qsTr("Current Index") }
|
||||
Text { text: Stats.index }
|
||||
Text { text: qsTr("Current Source") }
|
||||
Text { text: Stats.source }
|
||||
Text { text: qsTr("Current Rez") }
|
||||
Text { text: Stats.rez.width + " x " + Stats.rez.height }
|
||||
}
|
||||
|
||||
Row {
|
||||
id: row1
|
||||
spacing: 10
|
||||
anchors.bottom: row2.top
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 10
|
||||
Button { text: "1024"; onClicked: Stats.maxTextureMemory(1024); }
|
||||
Button { text: "256"; onClicked: Stats.maxTextureMemory(256); }
|
||||
}
|
||||
|
||||
Row {
|
||||
id: row2
|
||||
spacing: 10
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 10
|
||||
Button { text: "Change Textures"; onClicked: Stats.changeTextures(); }
|
||||
Button { text: "Next"; onClicked: Stats.nextTexture(); }
|
||||
Button { text: "Previous"; onClicked: Stats.prevTexture(); }
|
||||
}
|
||||
|
||||
}
|
||||
|
26
tests-manual/gpu-textures/src/TestHelpers.cpp
Normal file
26
tests-manual/gpu-textures/src/TestHelpers.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/16
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "TestHelpers.h"
|
||||
#include <QtCore/QFileInfo>
|
||||
|
||||
gpu::ShaderPointer makeShader(const std::string & vertexShaderSrc, const std::string & fragmentShaderSrc, const gpu::Shader::BindingSet & bindings) {
|
||||
auto vs = gpu::Shader::createVertex(vertexShaderSrc);
|
||||
auto fs = gpu::Shader::createPixel(fragmentShaderSrc);
|
||||
auto shader = gpu::Shader::createProgram(vs, fs);
|
||||
if (!gpu::Shader::makeProgram(*shader, bindings)) {
|
||||
printf("Could not compile shader\n");
|
||||
exit(-1);
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
QString projectRootDir() {
|
||||
static QString projectRootPath = QFileInfo(QFileInfo(__FILE__).absolutePath() + "/..").absoluteFilePath();
|
||||
return projectRootPath;
|
||||
}
|
40
tests-manual/gpu-textures/src/TestHelpers.h
Normal file
40
tests-manual/gpu-textures/src/TestHelpers.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/16
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <Transform.h>
|
||||
#include <NumericalConstants.h>
|
||||
|
||||
#include <gpu/Resource.h>
|
||||
#include <gpu/Forward.h>
|
||||
#include <gpu/Shader.h>
|
||||
#include <gpu/Stream.h>
|
||||
|
||||
struct RenderArgs {
|
||||
gpu::ContextPointer _context;
|
||||
ivec4 _viewport;
|
||||
gpu::Batch* _batch;
|
||||
};
|
||||
|
||||
class GpuTestBase : public QObject {
|
||||
public:
|
||||
virtual ~GpuTestBase() {}
|
||||
virtual bool isReady() const { return true; }
|
||||
virtual size_t getTestCount() const { return 1; }
|
||||
virtual void renderTest(size_t test, const RenderArgs& args) = 0;
|
||||
virtual QObject * statsObject() { return nullptr; }
|
||||
virtual QUrl statUrl() { return QUrl(); }
|
||||
};
|
||||
|
||||
uint32_t toCompactColor(const glm::vec4& color);
|
||||
gpu::ShaderPointer makeShader(const std::string & vertexShaderSrc, const std::string & fragmentShaderSrc, const gpu::Shader::BindingSet & bindings);
|
||||
QString projectRootDir();
|
166
tests-manual/gpu-textures/src/TestTextures.cpp
Normal file
166
tests-manual/gpu-textures/src/TestTextures.cpp
Normal file
|
@ -0,0 +1,166 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/16
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "TestTextures.h"
|
||||
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
|
||||
#include <QtCore/QDir>
|
||||
#include <QtQuick/QQuickView>
|
||||
#include <QtQml/QQmlContext>
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Context.h>
|
||||
|
||||
#include "TestHelpers.h"
|
||||
|
||||
std::string vertexShaderSource = R"SHADER(
|
||||
#line 14
|
||||
layout(location = 0) out vec2 outTexCoord0;
|
||||
|
||||
const vec4 VERTICES[] = vec4[](
|
||||
vec4(-1.0, -1.0, 0.0, 1.0),
|
||||
vec4( 1.0, -1.0, 0.0, 1.0),
|
||||
vec4(-1.0, 1.0, 0.0, 1.0),
|
||||
vec4( 1.0, 1.0, 0.0, 1.0)
|
||||
);
|
||||
|
||||
void main() {
|
||||
outTexCoord0 = VERTICES[gl_VertexID].xy;
|
||||
outTexCoord0 += 1.0;
|
||||
outTexCoord0 /= 2.0;
|
||||
gl_Position = VERTICES[gl_VertexID];
|
||||
}
|
||||
)SHADER";
|
||||
|
||||
std::string fragmentShaderSource = R"SHADER(
|
||||
#line 28
|
||||
|
||||
uniform sampler2D tex;
|
||||
|
||||
layout(location = 0) in vec2 inTexCoord0;
|
||||
layout(location = 0) out vec4 outFragColor;
|
||||
|
||||
void main() {
|
||||
outFragColor = texture(tex, inTexCoord0);
|
||||
outFragColor.a = 1.0;
|
||||
//outFragColor.rb = inTexCoord0;
|
||||
}
|
||||
|
||||
)SHADER";
|
||||
|
||||
#define STAT_UPDATE(name, src) \
|
||||
{ \
|
||||
auto val = src; \
|
||||
if (_##name != val) { \
|
||||
_##name = val; \
|
||||
emit name##Changed(); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
void TextureTestStats::update(int curIndex, const gpu::TexturePointer& texture) {
|
||||
STAT_UPDATE(total, (int)BYTES_TO_MB(gpu::Context::getTextureGPUMemSize()));
|
||||
STAT_UPDATE(allocated, (int)gpu::Context::getTextureResourceGPUMemSize());
|
||||
STAT_UPDATE(pending, (int)gpu::Context::getTexturePendingGPUTransferMemSize());
|
||||
STAT_UPDATE(populated, (int)gpu::Context::getTextureResourcePopulatedGPUMemSize());
|
||||
STAT_UPDATE(source, texture->source().c_str());
|
||||
STAT_UPDATE(index, curIndex);
|
||||
auto dims = texture->getDimensions();
|
||||
STAT_UPDATE(rez, QSize(dims.x, dims.y));
|
||||
}
|
||||
|
||||
TexturesTest::TexturesTest() {
|
||||
connect(&stats, &TextureTestStats::changeTextures, this, &TexturesTest::onChangeTextures);
|
||||
connect(&stats, &TextureTestStats::nextTexture, this, &TexturesTest::onNextTexture);
|
||||
connect(&stats, &TextureTestStats::prevTexture, this, &TexturesTest::onPrevTexture);
|
||||
connect(&stats, &TextureTestStats::maxTextureMemory, this, &TexturesTest::onMaxTextureMemory);
|
||||
{
|
||||
auto VS = gpu::Shader::createVertex(vertexShaderSource);
|
||||
auto PS = gpu::Shader::createPixel(fragmentShaderSource);
|
||||
auto program = gpu::Shader::createProgram(VS, PS);
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
// If the pipeline did not exist, make it
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_NONE);
|
||||
state->setDepthTest({});
|
||||
state->setBlendFunction({ false });
|
||||
pipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
onChangeTextures();
|
||||
}
|
||||
|
||||
|
||||
void TexturesTest::renderTest(size_t testId, const RenderArgs& args) {
|
||||
stats.update((int)index, textures[index]);
|
||||
gpu::Batch& batch = *(args._batch);
|
||||
batch.setPipeline(pipeline);
|
||||
batch.setInputFormat(vertexFormat);
|
||||
for (const auto& texture : textures) {
|
||||
batch.setResourceTexture(0, texture);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4, 0);
|
||||
}
|
||||
batch.setResourceTexture(0, textures[index]);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4, 0);
|
||||
}
|
||||
|
||||
#define LOAD_TEXTURE_COUNT 64
|
||||
|
||||
void TexturesTest::onChangeTextures() {
|
||||
static const QDir TEST_DIR("D:/ktx_texture_test");
|
||||
static std::vector<std::string> ALL_TEXTURE_FILES;
|
||||
if (ALL_TEXTURE_FILES.empty()) {
|
||||
auto entryList = TEST_DIR.entryList({ "*.ktx" }, QDir::Filter::Files);
|
||||
ALL_TEXTURE_FILES.reserve(entryList.size());
|
||||
for (auto entry : entryList) {
|
||||
auto textureFile = TEST_DIR.absoluteFilePath(entry).toStdString();
|
||||
ALL_TEXTURE_FILES.push_back(textureFile);
|
||||
}
|
||||
}
|
||||
|
||||
oldTextures.clear();
|
||||
oldTextures.swap(textures);
|
||||
|
||||
#if 0
|
||||
static const std::string bad = "D:/ktx_texture_test/b4beed38675dbc7a827ecd576399c1f4.ktx";
|
||||
auto texture = gpu::Texture::unserialize(bad);
|
||||
auto texelFormat = texture->getTexelFormat();
|
||||
qDebug() << texture->getTexelFormat().getSemantic();
|
||||
qDebug() << texture->getTexelFormat().getScalarCount();
|
||||
textures.push_back(texture);
|
||||
#else
|
||||
std::shuffle(ALL_TEXTURE_FILES.begin(), ALL_TEXTURE_FILES.end(), std::default_random_engine());
|
||||
size_t newTextureCount = std::min<size_t>(ALL_TEXTURE_FILES.size(), LOAD_TEXTURE_COUNT);
|
||||
for (size_t i = 0; i < newTextureCount; ++i) {
|
||||
const auto& textureFile = ALL_TEXTURE_FILES[i];
|
||||
auto texture = gpu::Texture::unserialize(textureFile);
|
||||
qDebug() << textureFile.c_str();
|
||||
qDebug() << texture->getTexelFormat().getSemantic();
|
||||
qDebug() << texture->getTexelFormat().getScalarCount();
|
||||
textures.push_back(texture);
|
||||
}
|
||||
#endif
|
||||
index = 0;
|
||||
qDebug() << "Done";
|
||||
}
|
||||
|
||||
void TexturesTest::onNextTexture() {
|
||||
index += textures.size() + 1;
|
||||
index %= textures.size();
|
||||
}
|
||||
|
||||
void TexturesTest::onPrevTexture() {
|
||||
index += textures.size() - 1;
|
||||
index %= textures.size();
|
||||
}
|
||||
|
||||
void TexturesTest::onMaxTextureMemory(int maxTextureMemory) {
|
||||
gpu::Texture::setAllowedGPUMemoryUsage(MB_TO_BYTES(maxTextureMemory));
|
||||
}
|
74
tests-manual/gpu-textures/src/TestTextures.h
Normal file
74
tests-manual/gpu-textures/src/TestTextures.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/16
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "TestHelpers.h"
|
||||
|
||||
#define STATS_PROPERTY(type, name, initialValue) \
|
||||
Q_PROPERTY(type name READ name NOTIFY name##Changed) \
|
||||
public: \
|
||||
type name() { return _##name; }; \
|
||||
private: \
|
||||
type _##name{ initialValue };
|
||||
|
||||
|
||||
class TextureTestStats : public QObject {
|
||||
Q_OBJECT;
|
||||
STATS_PROPERTY(int, pending, 0)
|
||||
STATS_PROPERTY(int, total, 0)
|
||||
STATS_PROPERTY(int, populated, 0)
|
||||
STATS_PROPERTY(int, allocated, 0)
|
||||
STATS_PROPERTY(int, index, 0)
|
||||
|
||||
STATS_PROPERTY(QString, source, QString())
|
||||
STATS_PROPERTY(QSize, rez, QSize(0, 0))
|
||||
|
||||
public:
|
||||
void update(int index, const gpu::TexturePointer& texture);
|
||||
|
||||
signals:
|
||||
void pendingChanged();
|
||||
void totalChanged();
|
||||
void populatedChanged();
|
||||
void allocatedChanged();
|
||||
void changeTextures();
|
||||
void rezChanged();
|
||||
void indexChanged();
|
||||
void sourceChanged();
|
||||
void maxTextureMemory(int);
|
||||
|
||||
void nextTexture();
|
||||
void prevTexture();
|
||||
};
|
||||
|
||||
|
||||
class TexturesTest : public GpuTestBase {
|
||||
Q_OBJECT
|
||||
|
||||
gpu::Stream::FormatPointer vertexFormat { std::make_shared<gpu::Stream::Format>() };
|
||||
std::vector<gpu::TexturePointer> textures;
|
||||
std::vector<gpu::TexturePointer> oldTextures;
|
||||
gpu::PipelinePointer pipeline;
|
||||
TextureTestStats stats;
|
||||
size_t index{ 0 };
|
||||
|
||||
public:
|
||||
TexturesTest();
|
||||
QObject* statsObject() override { return &stats; }
|
||||
QUrl statUrl() override { return QUrl::fromLocalFile(projectRootDir() + "/qml/textureStats.qml"); }
|
||||
void renderTest(size_t testId, const RenderArgs& args) override;
|
||||
|
||||
protected slots:
|
||||
void onChangeTextures();
|
||||
void onMaxTextureMemory(int newValue);
|
||||
void onNextTexture();
|
||||
void onPrevTexture();
|
||||
|
||||
};
|
||||
|
||||
|
117
tests-manual/gpu-textures/src/TestWindow.cpp
Normal file
117
tests-manual/gpu-textures/src/TestWindow.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/16
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "TestWindow.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtGui/QResizeEvent>
|
||||
|
||||
#include <gl/GLHelpers.h>
|
||||
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
|
||||
TestWindow::TestWindow() {
|
||||
|
||||
auto timer = new QTimer(this);
|
||||
timer->setTimerType(Qt::PreciseTimer);
|
||||
timer->setInterval(5);
|
||||
connect(timer, &QTimer::timeout, [&] { draw(); });
|
||||
timer->start();
|
||||
|
||||
connect(qApp, &QCoreApplication::aboutToQuit, [this, timer] {
|
||||
timer->stop();
|
||||
_aboutToQuit = true;
|
||||
});
|
||||
|
||||
setSurfaceType(QSurface::OpenGLSurface);
|
||||
|
||||
QSurfaceFormat format = getDefaultOpenGLSurfaceFormat();
|
||||
format.setOption(QSurfaceFormat::DebugContext);
|
||||
setFormat(format);
|
||||
_glContext.setFormat(format);
|
||||
_glContext.create();
|
||||
_glContext.makeCurrent(this);
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
void TestWindow::initGl() {
|
||||
_glContext.makeCurrent(this);
|
||||
gl::initModuleGl();
|
||||
gpu::Context::init<gpu::gl::GLBackend>();
|
||||
_renderArgs->_context = std::make_shared<gpu::Context>();
|
||||
_glContext.makeCurrent(this);
|
||||
resize(QSize(800, 600));
|
||||
}
|
||||
|
||||
void TestWindow::resizeWindow(const QSize& size) {
|
||||
_size = size;
|
||||
_renderArgs->_viewport = ivec4(0, 0, _size.width(), _size.height());
|
||||
}
|
||||
|
||||
void TestWindow::beginFrame() {
|
||||
_renderArgs->_context->recycle();
|
||||
_renderArgs->_context->beginFrame();
|
||||
gpu::doInBatch("TestWindow::beginFrame", _renderArgs->_context, [&](gpu::Batch& batch) {
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLORS, { 0.0f, 0.1f, 0.2f, 1.0f });
|
||||
batch.clearDepthFramebuffer(1e4);
|
||||
batch.setViewportTransform({ 0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio() });
|
||||
});
|
||||
|
||||
gpu::doInBatch("TestWindow::beginFrame", _renderArgs->_context, [&](gpu::Batch& batch) {
|
||||
batch.setViewportTransform(_renderArgs->_viewport);
|
||||
batch.setStateScissorRect(_renderArgs->_viewport);
|
||||
batch.setProjectionTransform(_projectionMatrix);
|
||||
});
|
||||
}
|
||||
|
||||
void TestWindow::endFrame() {
|
||||
gpu::doInBatch("TestWindow::endFrame::finish", _renderArgs->_context, [&](gpu::Batch& batch) {
|
||||
batch.resetStages();
|
||||
});
|
||||
auto framePointer = _renderArgs->_context->endFrame();
|
||||
_renderArgs->_context->consumeFrameUpdates(framePointer);
|
||||
_renderArgs->_context->executeFrame(framePointer);
|
||||
_glContext.swapBuffers(this);
|
||||
}
|
||||
|
||||
void TestWindow::draw() {
|
||||
if (_aboutToQuit) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempting to draw before we're visible and have a valid size will
|
||||
// produce GL errors.
|
||||
if (!isVisible() || _size.width() <= 0 || _size.height() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_glContext.makeCurrent(this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] { initGl(); });
|
||||
beginFrame();
|
||||
|
||||
renderFrame();
|
||||
|
||||
endFrame();
|
||||
}
|
||||
|
||||
void TestWindow::resizeEvent(QResizeEvent* ev) {
|
||||
resizeWindow(ev->size());
|
||||
float fov_degrees = 60.0f;
|
||||
float aspect_ratio = (float)_size.width() / _size.height();
|
||||
float near_clip = 0.1f;
|
||||
float far_clip = 1000.0f;
|
||||
_projectionMatrix = glm::perspective(glm::radians(fov_degrees), aspect_ratio, near_clip, far_clip);
|
||||
}
|
41
tests-manual/gpu-textures/src/TestWindow.h
Normal file
41
tests-manual/gpu-textures/src/TestWindow.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/16
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtGui/QWindow>
|
||||
#include <QtCore/QTime>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
#include <gpu/Forward.h>
|
||||
#include "TestHelpers.h"
|
||||
|
||||
#define DEFERRED_LIGHTING
|
||||
|
||||
class TestWindow : public QWindow {
|
||||
protected:
|
||||
QOpenGLContextWrapper _glContext;
|
||||
QSize _size;
|
||||
glm::mat4 _projectionMatrix;
|
||||
bool _aboutToQuit { false };
|
||||
std::shared_ptr<RenderArgs> _renderArgs{ std::make_shared<RenderArgs>() };
|
||||
|
||||
TestWindow();
|
||||
virtual void initGl();
|
||||
virtual void renderFrame() = 0;
|
||||
|
||||
private:
|
||||
void resizeWindow(const QSize& size);
|
||||
|
||||
void beginFrame();
|
||||
void endFrame();
|
||||
void draw();
|
||||
void resizeEvent(QResizeEvent* ev) override;
|
||||
};
|
||||
|
170
tests-manual/gpu-textures/src/main.cpp
Normal file
170
tests-manual/gpu-textures/src/main.cpp
Normal file
|
@ -0,0 +1,170 @@
|
|||
//
|
||||
// main.cpp
|
||||
// tests/gpu-test/src
|
||||
//
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <cstdio>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include <QtCore/QTime>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
||||
#include <QtGui/QDesktopServices>
|
||||
#include <QtGui/QResizeEvent>
|
||||
#include <QtGui/QWindow>
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QImage>
|
||||
#include <QtGui/QScreen>
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
|
||||
#include <gl/Config.h>
|
||||
|
||||
#include <QtQuick/QQuickWindow>
|
||||
#include <QtQuick/QQuickView>
|
||||
#include <QtQml/QQmlContext>
|
||||
|
||||
#include <gpu/Context.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Stream.h>
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
#include <gl/GLHelpers.h>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <PathUtils.h>
|
||||
#include <NumericalConstants.h>
|
||||
|
||||
#include <PerfStat.h>
|
||||
#include <PathUtils.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
#include <gpu/Pipeline.h>
|
||||
#include <gpu/Context.h>
|
||||
|
||||
#include "TestWindow.h"
|
||||
#include "TestTextures.h"
|
||||
|
||||
using TestBuilder = std::function<GpuTestBase*()>;
|
||||
using TestBuilders = std::list<TestBuilder>;
|
||||
|
||||
#define INTERACTIVE
|
||||
|
||||
class MyTestWindow : public TestWindow {
|
||||
using Parent = TestWindow;
|
||||
TestBuilders _testBuilders;
|
||||
GpuTestBase* _currentTest{ nullptr };
|
||||
size_t _currentTestId{ 0 };
|
||||
size_t _currentMaxTests{ 0 };
|
||||
glm::mat4 _camera;
|
||||
QTime _time;
|
||||
|
||||
void initGl() override {
|
||||
Parent::initGl();
|
||||
_time.start();
|
||||
updateCamera();
|
||||
_testBuilders = TestBuilders({
|
||||
[] { return new TexturesTest(); },
|
||||
});
|
||||
}
|
||||
|
||||
void updateCamera() {
|
||||
float t = _time.elapsed() * 1e-3f;
|
||||
glm::vec3 unitscale{ 1.0f };
|
||||
glm::vec3 up{ 0.0f, 1.0f, 0.0f };
|
||||
|
||||
float distance = 3.0f;
|
||||
glm::vec3 camera_position{ distance * sinf(t), 0.5f, distance * cosf(t) };
|
||||
|
||||
static const vec3 camera_focus(0);
|
||||
static const vec3 camera_up(0, 1, 0);
|
||||
_camera = glm::inverse(glm::lookAt(camera_position, camera_focus, up));
|
||||
|
||||
ViewFrustum frustum;
|
||||
frustum.setPosition(camera_position);
|
||||
frustum.setOrientation(glm::quat_cast(_camera));
|
||||
frustum.setProjection(_projectionMatrix);
|
||||
}
|
||||
|
||||
void renderFrame() override {
|
||||
updateCamera();
|
||||
|
||||
while ((!_currentTest || (_currentTestId >= _currentMaxTests)) && !_testBuilders.empty()) {
|
||||
if (_currentTest) {
|
||||
delete _currentTest;
|
||||
_currentTest = nullptr;
|
||||
}
|
||||
|
||||
_currentTest = _testBuilders.front()();
|
||||
_testBuilders.pop_front();
|
||||
|
||||
if (_currentTest) {
|
||||
auto statsObject = _currentTest->statsObject();
|
||||
QUrl url = _currentTest->statUrl();
|
||||
if (statsObject) {
|
||||
auto screens = qApp->screens();
|
||||
auto primaryScreen = qApp->primaryScreen();
|
||||
auto targetScreen = primaryScreen;
|
||||
for (const auto& screen : screens) {
|
||||
if (screen == primaryScreen) {
|
||||
continue;
|
||||
}
|
||||
targetScreen = screen;
|
||||
break;
|
||||
}
|
||||
|
||||
auto destPoint = targetScreen->availableGeometry().topLeft();
|
||||
QQuickView* view = new QQuickView();
|
||||
view->rootContext()->setContextProperty("Stats", statsObject);
|
||||
view->setSource(url);
|
||||
view->show();
|
||||
view->setPosition({ destPoint.x() + 100, destPoint.y() + 100 });
|
||||
}
|
||||
_currentMaxTests = _currentTest->getTestCount();
|
||||
_currentTestId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_currentTest && _testBuilders.empty()) {
|
||||
qApp->quit();
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests might need to wait for resources to download
|
||||
if (!_currentTest->isReady()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpu::doInBatch("main::renderFrame", _renderArgs->_context, [&](gpu::Batch& batch) {
|
||||
batch.setViewTransform(_camera);
|
||||
_renderArgs->_batch = &batch;
|
||||
_currentTest->renderTest(_currentTestId, *_renderArgs);
|
||||
_renderArgs->_batch = nullptr;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
setupHifiApplication("GPU Test");
|
||||
qputenv("HIFI_DEBUG_OPENGL", QByteArray("1"));
|
||||
QApplication app(argc, argv);
|
||||
MyTestWindow window;
|
||||
app.exec();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -27,9 +27,9 @@ set_target_properties("test-extensions" PROPERTIES FOLDER "Tests")
|
|||
# set (ALL_TEST_TARGETS "${ALL_TEST_TARGETS}" PARENT_SCOPE) # copies this back to parent scope
|
||||
#
|
||||
add_custom_target("all-tests"
|
||||
COMMAND ctest .
|
||||
DEPENDS "${ALL_TEST_TARGETS}")
|
||||
set_target_properties("all-tests" PROPERTIES FOLDER "hidden/test-targets")
|
||||
|
||||
set_target_properties("all-tests" PROPERTIES
|
||||
FOLDER "hidden/test-targets"
|
||||
EXCLUDE_FROM_DEFAULT_BUILD TRUE
|
||||
EXCLUDE_FROM_ALL TRUE)
|
||||
|
|
|
@ -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(quint64& startUsecs, quint64 maxIntervalUecs) {
|
||||
auto now = usecTimestampNow();
|
||||
auto interval = now - startUsecs;
|
||||
if (interval > maxIntervalUecs) {
|
||||
startUsecs = now;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool afterSecs(quint64& startUsecs, quint64 maxIntervalSecs) {
|
||||
return afterUsecs(startUsecs, maxIntervalSecs * USECS_PER_SECOND);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void doEvery(quint64& lastReportUsecs, quint64 secs, F lamdba) {
|
||||
if (afterSecs(lastReportUsecs, secs)) {
|
||||
lamdba();
|
||||
}
|
||||
}
|
||||
|
||||
inline void failAfter(quint64 startUsecs, quint64 secs, const char* message) {
|
||||
if (afterSecs(startUsecs, secs)) {
|
||||
QFAIL(message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ void AnimTests::initTestCase() {
|
|||
|
||||
void AnimTests::cleanupTestCase() {
|
||||
//DependencyManager::destroy<AnimationCache>();
|
||||
DependencyManager::get<ResourceManager>()->cleanup();
|
||||
}
|
||||
|
||||
void AnimTests::testClipInternalState() {
|
||||
|
|
17
tests/gpu/CMakeLists.txt
Normal file
17
tests/gpu/CMakeLists.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Declare dependencies
|
||||
macro (setup_testcase_dependencies)
|
||||
# link in the shared libraries
|
||||
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()
|
284
tests/gpu/src/TextureTest.cpp
Normal file
284
tests/gpu/src/TextureTest.cpp
Normal file
|
@ -0,0 +1,284 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2018/01/11
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "TextureTest.h"
|
||||
|
||||
#include <iostream>
|
||||
#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"
|
||||
|
||||
QTEST_MAIN(TextureTest)
|
||||
|
||||
#define LOAD_TEXTURE_COUNT 40
|
||||
|
||||
static const QString TEST_DATA("https://hifi-public.s3.amazonaws.com/austin/test_data/test_ktx.zip");
|
||||
static const QString TEST_DIR_NAME("{630b8f02-52af-4cdf-a896-24e472b94b28}");
|
||||
|
||||
std::string vertexShaderSource = R"SHADER(
|
||||
#line 14
|
||||
layout(location = 0) out vec2 outTexCoord0;
|
||||
|
||||
const vec4 VERTICES[] = vec4[](
|
||||
vec4(-1.0, -1.0, 0.0, 1.0),
|
||||
vec4( 1.0, -1.0, 0.0, 1.0),
|
||||
vec4(-1.0, 1.0, 0.0, 1.0),
|
||||
vec4( 1.0, 1.0, 0.0, 1.0)
|
||||
);
|
||||
|
||||
void main() {
|
||||
outTexCoord0 = VERTICES[gl_VertexID].xy;
|
||||
outTexCoord0 += 1.0;
|
||||
outTexCoord0 /= 2.0;
|
||||
gl_Position = VERTICES[gl_VertexID];
|
||||
}
|
||||
)SHADER";
|
||||
|
||||
std::string fragmentShaderSource = R"SHADER(
|
||||
#line 28
|
||||
|
||||
uniform sampler2D tex;
|
||||
|
||||
layout(location = 0) in vec2 inTexCoord0;
|
||||
layout(location = 0) out vec4 outFragColor;
|
||||
|
||||
void main() {
|
||||
outFragColor = texture(tex, inTexCoord0);
|
||||
outFragColor.a = 1.0;
|
||||
//outFragColor.rb = inTexCoord0;
|
||||
}
|
||||
|
||||
)SHADER";
|
||||
|
||||
QtMessageHandler originalHandler;
|
||||
|
||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||
#if defined(Q_OS_WIN)
|
||||
OutputDebugStringA(message.toStdString().c_str());
|
||||
OutputDebugStringA("\n");
|
||||
#endif
|
||||
originalHandler(type, context, message);
|
||||
}
|
||||
|
||||
void TextureTest::initTestCase() {
|
||||
originalHandler = qInstallMessageHandler(messageHandler);
|
||||
_resourcesPath = getTestResource("interface/resources");
|
||||
getDefaultOpenGLSurfaceFormat();
|
||||
_canvas.create();
|
||||
if (!_canvas.makeCurrent()) {
|
||||
qFatal("Unable to make test GL context current");
|
||||
}
|
||||
gl::initModuleGl();
|
||||
gpu::Context::init<gpu::gl::GLBackend>();
|
||||
_gpuContext = std::make_shared<gpu::Context>();
|
||||
|
||||
_resourcesPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/" + TEST_DIR_NAME;
|
||||
if (!QFileInfo(_resourcesPath).exists()) {
|
||||
QDir(_resourcesPath).mkpath(".");
|
||||
FileDownloader(TEST_DATA,
|
||||
[&](const QByteArray& data) {
|
||||
QTemporaryFile zipFile;
|
||||
if (zipFile.open()) {
|
||||
zipFile.write(data);
|
||||
zipFile.close();
|
||||
}
|
||||
JlCompress::extractDir(zipFile.fileName(), _resourcesPath);
|
||||
})
|
||||
.waitForDownload();
|
||||
}
|
||||
|
||||
_canvas.makeCurrent();
|
||||
{
|
||||
auto VS = gpu::Shader::createVertex(vertexShaderSource);
|
||||
auto PS = gpu::Shader::createPixel(fragmentShaderSource);
|
||||
auto program = gpu::Shader::createProgram(VS, PS);
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
// If the pipeline did not exist, make it
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_NONE);
|
||||
state->setDepthTest({});
|
||||
state->setBlendFunction({ false });
|
||||
_pipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
_framebuffer.reset(gpu::Framebuffer::create("cached", gpu::Element::COLOR_SRGBA_32, _size.x, _size.y));
|
||||
|
||||
// Find the test textures
|
||||
{
|
||||
QDir resourcesDir(_resourcesPath);
|
||||
auto entryList = resourcesDir.entryList({ "*.ktx" }, QDir::Filter::Files);
|
||||
_textureFiles.reserve(entryList.size());
|
||||
for (auto entry : entryList) {
|
||||
auto textureFile = resourcesDir.absoluteFilePath(entry).toStdString();
|
||||
_textureFiles.push_back(textureFile);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the test textures
|
||||
{
|
||||
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];
|
||||
auto texture = gpu::Texture::unserialize(textureFile);
|
||||
_textures.push_back(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextureTest::cleanupTestCase() {
|
||||
_framebuffer.reset();
|
||||
_pipeline.reset();
|
||||
_gpuContext->recycle();
|
||||
_gpuContext.reset();
|
||||
}
|
||||
|
||||
void TextureTest::beginFrame() {
|
||||
_gpuContext->recycle();
|
||||
_gpuContext->beginFrame();
|
||||
gpu::doInBatch("TestWindow::beginFrame", _gpuContext, [&](gpu::Batch& batch) {
|
||||
batch.setFramebuffer(_framebuffer);
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLORS, { 0.0f, 0.1f, 0.2f, 1.0f });
|
||||
batch.clearDepthFramebuffer(1e4);
|
||||
batch.setViewportTransform({ 0, 0, _size.x, _size.y });
|
||||
});
|
||||
}
|
||||
|
||||
void TextureTest::endFrame() {
|
||||
gpu::doInBatch("TestWindow::endFrame::finish", _gpuContext, [&](gpu::Batch& batch) { batch.resetStages(); });
|
||||
auto framePointer = _gpuContext->endFrame();
|
||||
_gpuContext->consumeFrameUpdates(framePointer);
|
||||
_gpuContext->executeFrame(framePointer);
|
||||
// Simulate swapbuffers with a finish
|
||||
glFinish();
|
||||
QThread::msleep(10);
|
||||
}
|
||||
|
||||
void TextureTest::renderFrame(const std::function<void(gpu::Batch&)>& renderLambda) {
|
||||
beginFrame();
|
||||
gpu::doInBatch("Test::body", _gpuContext, renderLambda);
|
||||
endFrame();
|
||||
}
|
||||
|
||||
void TextureTest::testTextureLoading() {
|
||||
QVERIFY(_textures.size() > 0);
|
||||
auto renderTexturesLamdba = [this](gpu::Batch& batch) {
|
||||
batch.setPipeline(_pipeline);
|
||||
for (const auto& texture : _textures) {
|
||||
batch.setResourceTexture(0, texture);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4, 0);
|
||||
}
|
||||
};
|
||||
|
||||
size_t expectedAllocation = 0;
|
||||
for (const auto& texture : _textures) {
|
||||
expectedAllocation += texture->evalTotalSize();
|
||||
}
|
||||
QVERIFY(_textures.size() > 0);
|
||||
|
||||
auto reportLambda = [=] {
|
||||
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 (expectedAllocation != allocatedMemory) {
|
||||
doEvery(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();
|
||||
// Cycle frames we're fully populated
|
||||
while (allocatedMemory != populatedMemory || 0 != gpu::Context::getTexturePendingGPUTransferMemSize()) {
|
||||
doEvery(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(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) {
|
||||
doEvery(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) {
|
||||
doEvery(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);
|
||||
|
||||
_textures.clear();
|
||||
// Cycle frames we're fully populated
|
||||
while (allocatedMemory != 0) {
|
||||
failAfter(start, 10, "Failed to clear texture memory after 10 seconds");
|
||||
renderFrame();
|
||||
allocatedMemory = gpu::Context::getTextureResourceGPUMemSize();
|
||||
populatedMemory = gpu::Context::getTextureResourcePopulatedGPUMemSize();
|
||||
}
|
||||
QCOMPARE(allocatedMemory, 0);
|
||||
QCOMPARE(populatedMemory, 0);
|
||||
qDebug() << "Done";
|
||||
|
||||
}
|
40
tests/gpu/src/TextureTest.h
Normal file
40
tests/gpu/src/TextureTest.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2018/05/08
|
||||
// Copyright 2013-2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
#include <QtCore/QTemporaryDir>
|
||||
|
||||
#include <gpu/Forward.h>
|
||||
#include <gl/OffscreenGLCanvas.h>
|
||||
|
||||
class TextureTest : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
void beginFrame();
|
||||
void endFrame();
|
||||
void renderFrame(const std::function<void(gpu::Batch&)>& = [](gpu::Batch&) {});
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
void testTextureLoading();
|
||||
|
||||
private:
|
||||
QString _resourcesPath;
|
||||
OffscreenGLCanvas _canvas;
|
||||
gpu::ContextPointer _gpuContext;
|
||||
gpu::PipelinePointer _pipeline;
|
||||
gpu::FramebufferPointer _framebuffer;
|
||||
gpu::TexturePointer _colorBuffer, _depthBuffer;
|
||||
const glm::uvec2 _size{ 640, 480 };
|
||||
std::vector<std::string> _textureFiles;
|
||||
std::vector<gpu::TexturePointer> _textures;
|
||||
};
|
|
@ -76,7 +76,9 @@ void KtxTests::testKtxEvalFunctions() {
|
|||
void KtxTests::testKtxSerialization() {
|
||||
const QString TEST_IMAGE = getRootPath() + "/scripts/developer/tests/cube_texture.png";
|
||||
QImage image(TEST_IMAGE);
|
||||
gpu::TexturePointer testTexture = image::TextureUsage::process2DTextureColorFromImage(image, TEST_IMAGE.toStdString(), true);
|
||||
std::atomic<bool> abortSignal;
|
||||
gpu::TexturePointer testTexture =
|
||||
image::TextureUsage::process2DTextureColorFromImage(std::move(image), TEST_IMAGE.toStdString(), true, abortSignal);
|
||||
auto ktxMemory = gpu::Texture::serialize(*testTexture);
|
||||
QVERIFY(ktxMemory.get());
|
||||
|
||||
|
|
|
@ -11,16 +11,23 @@
|
|||
|
||||
#include <QNetworkDiskCache>
|
||||
|
||||
#include "ResourceCache.h"
|
||||
#include "NetworkAccessManager.h"
|
||||
#include "DependencyManager.h"
|
||||
#include <ResourceCache.h>
|
||||
#include <LimitedNodeList.h>
|
||||
#include <NodeList.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <StatTracker.h>
|
||||
|
||||
QTEST_MAIN(ResourceTests)
|
||||
|
||||
void ResourceTests::initTestCase() {
|
||||
|
||||
auto resourceCacheSharedItems = DependencyManager::set<ResourceCacheSharedItems>();
|
||||
|
||||
//DependencyManager::set<AddressManager>();
|
||||
DependencyManager::set<StatTracker>();
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
DependencyManager::set<NodeList>(NodeType::Agent, INVALID_PORT);
|
||||
DependencyManager::set<ResourceCacheSharedItems>();
|
||||
DependencyManager::set<ResourceManager>();
|
||||
const qint64 MAXIMUM_CACHE_SIZE = 1024 * 1024 * 1024; // 1GB
|
||||
|
||||
// set up the file cache
|
||||
|
@ -34,6 +41,10 @@ void ResourceTests::initTestCase() {
|
|||
networkAccessManager.setCache(cache);
|
||||
}
|
||||
|
||||
void ResourceTests::cleanupTestCase() {
|
||||
DependencyManager::get<ResourceManager>()->cleanup();
|
||||
}
|
||||
|
||||
static QSharedPointer<Resource> resource;
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ private slots:
|
|||
void initTestCase();
|
||||
void downloadFirst();
|
||||
void downloadAgain();
|
||||
void cleanupTestCase();
|
||||
};
|
||||
|
||||
#endif // hifi_ResourceTests_h
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
|
||||
set(TARGET_NAME qt59)
|
||||
|
||||
if (WIN32)
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4049 /ignore:4217")
|
||||
endif()
|
||||
|
||||
setup_memory_debugger()
|
||||
|
||||
# This is not a testcase -- just set it up as a regular hifi project
|
||||
setup_hifi_project(Gui)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared networking)
|
||||
|
||||
if (WIN32)
|
||||
add_dependency_external_projects(wasapi)
|
||||
endif()
|
||||
|
||||
package_libraries_for_deployment()
|
|
@ -1,73 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2017/06/06
|
||||
// Copyright 2013-2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include <NodeList.h>
|
||||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
#include <MessagesClient.h>
|
||||
|
||||
#include <BuildInfo.h>
|
||||
|
||||
|
||||
class Qt59TestApp : public QCoreApplication {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Qt59TestApp(int argc, char* argv[]);
|
||||
~Qt59TestApp();
|
||||
|
||||
private:
|
||||
void finish(int exitCode);
|
||||
};
|
||||
|
||||
|
||||
|
||||
Qt59TestApp::Qt59TestApp(int argc, char* argv[]) :
|
||||
QCoreApplication(argc, argv)
|
||||
{
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
DependencyManager::set<AccountManager>([&] { return QString("Mozilla/5.0 (HighFidelityACClient)"); });
|
||||
DependencyManager::set<AddressManager>();
|
||||
DependencyManager::set<NodeList>(NodeType::Agent, 0);
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->startThread();
|
||||
auto messagesClient = DependencyManager::set<MessagesClient>();
|
||||
messagesClient->startThread();
|
||||
QTimer::singleShot(1000, [this] { finish(0); });
|
||||
}
|
||||
|
||||
Qt59TestApp::~Qt59TestApp() {
|
||||
}
|
||||
|
||||
|
||||
void Qt59TestApp::finish(int exitCode) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
// send the domain a disconnect packet, force stoppage of domain-server check-ins
|
||||
nodeList->getDomainHandler().disconnect();
|
||||
nodeList->setIsShuttingDown(true);
|
||||
nodeList->getPacketReceiver().setShouldDropPackets(true);
|
||||
|
||||
// remove the NodeList from the DependencyManager
|
||||
DependencyManager::destroy<NodeList>();
|
||||
QCoreApplication::exit(exitCode);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
setupHifiApplication("Qt59Test");
|
||||
|
||||
Qt59TestApp app(argc, argv);
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
#include "main.moc"
|
|
@ -1 +0,0 @@
|
|||
# This folder contains code for testing the QML UI using Qt Creator. It is not intended to be included in the CMake project
|
Loading…
Reference in a new issue