Merge branch 'master' of github.com:highfidelity/hifi into infinite-scroll

This commit is contained in:
howard-stearns 2018-05-22 12:35:21 -07:00
commit 2f1ce2a2fc
31 changed files with 528 additions and 381 deletions

View file

@ -179,6 +179,10 @@ endif()
add_subdirectory(tools) add_subdirectory(tools)
if (BUILD_TESTS) if (BUILD_TESTS)
# Turn on testing so that add_test works
# MUST be in the root cmake file for ctest to work
include(CTest)
enable_testing()
add_subdirectory(tests) add_subdirectory(tests)
add_subdirectory(tests-manual) add_subdirectory(tests-manual)
endif() endif()

View file

@ -25,6 +25,7 @@ public class UserStoryDomainProvider implements DomainProvider {
private static final String INCLUDE_ACTIONS_FOR_PLACES = "concurrency"; private static final String INCLUDE_ACTIONS_FOR_PLACES = "concurrency";
private static final String INCLUDE_ACTIONS_FOR_FULL_SEARCH = "concurrency,announcements,snapshot"; private static final String INCLUDE_ACTIONS_FOR_FULL_SEARCH = "concurrency,announcements,snapshot";
private static final String TAGS_TO_SEARCH = "mobile";
private static final int MAX_PAGES_TO_GET = 10; private static final int MAX_PAGES_TO_GET = 10;
private String mProtocol; private String mProtocol;
@ -78,6 +79,7 @@ public class UserStoryDomainProvider implements DomainProvider {
"open", "open",
true, true,
mProtocol, mProtocol,
TAGS_TO_SEARCH,
pageNumber); pageNumber);
Log.d("API-USER-STORY-DOMAINS", "Protocol [" + mProtocol + "] include_actions [" + INCLUDE_ACTIONS_FOR_PLACES + "]"); Log.d("API-USER-STORY-DOMAINS", "Protocol [" + mProtocol + "] include_actions [" + INCLUDE_ACTIONS_FOR_PLACES + "]");
userStories.enqueue(new retrofit2.Callback<UserStories>() { userStories.enqueue(new retrofit2.Callback<UserStories>() {
@ -152,45 +154,13 @@ public class UserStoryDomainProvider implements DomainProvider {
} }
} }
public void retrieveNot(DomainCallback domainCallback) {
// TODO Call multiple pages
Call<UserStories> userStories = mUserStoryDomainProviderService.getUserStories(
INCLUDE_ACTIONS_FOR_PLACES,
"open",
true,
mProtocol,
1);
Log.d("API-USER-STORY-DOMAINS", "Protocol [" + mProtocol + "] include_actions [" + INCLUDE_ACTIONS_FOR_PLACES + "]");
userStories.enqueue(new retrofit2.Callback<UserStories>() {
@Override
public void onResponse(Call<UserStories> call, Response<UserStories> response) {
UserStories userStories = response.body();
if (userStories == null) {
domainCallback.retrieveOk(new ArrayList<>(0));
}
List<DomainAdapter.Domain> domains = new ArrayList<>(userStories.total_entries);
userStories.user_stories.forEach(userStory -> {
domains.add(userStory.toDomain());
});
domainCallback.retrieveOk(domains);
}
@Override
public void onFailure(Call<UserStories> call, Throwable t) {
domainCallback.retrieveError(new Exception(t), t.getMessage());
}
});
}
public interface UserStoryDomainProviderService { public interface UserStoryDomainProviderService {
@GET("api/v1/user_stories") @GET("api/v1/user_stories")
Call<UserStories> getUserStories(@Query("include_actions") String includeActions, Call<UserStories> getUserStories(@Query("include_actions") String includeActions,
@Query("restriction") String restriction, @Query("restriction") String restriction,
@Query("require_online") boolean requireOnline, @Query("require_online") boolean requireOnline,
@Query("protocol") String protocol, @Query("protocol") String protocol,
@Query("tags") String tagsCommaSeparated,
@Query("page") int pageNumber); @Query("page") int pageNumber);
} }

View file

@ -33,6 +33,10 @@
#include "ModelBakingLoggingCategory.h" #include "ModelBakingLoggingCategory.h"
#include "TextureBaker.h" #include "TextureBaker.h"
#ifdef HIFI_DUMP_FBX
#include "FBXToJSON.h"
#endif
void FBXBaker::bake() { void FBXBaker::bake() {
qDebug() << "FBXBaker" << _modelURL << "bake starting"; qDebug() << "FBXBaker" << _modelURL << "bake starting";
@ -187,6 +191,21 @@ void FBXBaker::importScene() {
qCDebug(model_baking) << "Parsing" << _modelURL; qCDebug(model_baking) << "Parsing" << _modelURL;
_rootNode = reader._rootNode = reader.parseFBX(&fbxFile); _rootNode = reader._rootNode = reader.parseFBX(&fbxFile);
#ifdef HIFI_DUMP_FBX
{
FBXToJSON fbxToJSON;
fbxToJSON << _rootNode;
QFileInfo modelFile(_originalModelFilePath);
QString outFilename(_bakedOutputDir + "/" + modelFile.completeBaseName() + "_FBX.json");
QFile jsonFile(outFilename);
if (jsonFile.open(QIODevice::WriteOnly)) {
jsonFile.write(fbxToJSON.str().c_str(), fbxToJSON.str().length());
jsonFile.close();
}
}
#endif
_geometry = reader.extractFBXGeometry({}, _modelURL.toString()); _geometry = reader.extractFBXGeometry({}, _modelURL.toString());
_textureContentMap = reader._textureContent; _textureContentMap = reader._textureContent;
} }
@ -231,39 +250,40 @@ void FBXBaker::rewriteAndBakeSceneModels() {
} else if (hasWarnings()) { } else if (hasWarnings()) {
continue; continue;
} }
} } else {
objectChild.children.push_back(dracoMeshNode);
objectChild.children.push_back(dracoMeshNode); static const std::vector<QString> nodeNamesToDelete {
// Node data that is packed into the draco mesh
"Vertices",
"PolygonVertexIndex",
"LayerElementNormal",
"LayerElementColor",
"LayerElementUV",
"LayerElementMaterial",
"LayerElementTexture",
static const std::vector<QString> nodeNamesToDelete { // Node data that we don't support
// Node data that is packed into the draco mesh "Edges",
"Vertices", "LayerElementTangent",
"PolygonVertexIndex", "LayerElementBinormal",
"LayerElementNormal", "LayerElementSmoothing"
"LayerElementColor", };
"LayerElementUV", auto& children = objectChild.children;
"LayerElementMaterial", auto it = children.begin();
"LayerElementTexture", while (it != children.end()) {
auto begin = nodeNamesToDelete.begin();
// Node data that we don't support auto end = nodeNamesToDelete.end();
"Edges", if (find(begin, end, it->name) != end) {
"LayerElementTangent", it = children.erase(it);
"LayerElementBinormal", } else {
"LayerElementSmoothing" ++it;
}; }
auto& children = objectChild.children;
auto it = children.begin();
while (it != children.end()) {
auto begin = nodeNamesToDelete.begin();
auto end = nodeNamesToDelete.end();
if (find(begin, end, it->name) != end) {
it = children.erase(it);
} else {
++it;
} }
} }
} } // Geometry Object
}
} // foreach root child
} }
} }
} }

View file

@ -52,7 +52,6 @@ private:
void embedTextureMetaData(); void embedTextureMetaData();
void rewriteAndBakeSceneModels(); void rewriteAndBakeSceneModels();
void rewriteAndBakeSceneTextures(); void rewriteAndBakeSceneTextures();
void exportScene();
FBXGeometry* _geometry; FBXGeometry* _geometry;
QHash<QString, int> _textureNameMatchCount; QHash<QString, int> _textureNameMatchCount;

View file

@ -24,6 +24,10 @@
#include <draco/mesh/triangle_soup_mesh_builder.h> #include <draco/mesh/triangle_soup_mesh_builder.h>
#include <draco/compression/encode.h> #include <draco/compression/encode.h>
#ifdef HIFI_DUMP_FBX
#include "FBXToJSON.h"
#endif
#ifdef _WIN32 #ifdef _WIN32
#pragma warning( pop ) #pragma warning( pop )
#endif #endif
@ -605,5 +609,19 @@ void ModelBaker::exportScene() {
_outputFiles.push_back(_bakedModelFilePath); _outputFiles.push_back(_bakedModelFilePath);
#ifdef HIFI_DUMP_FBX
{
FBXToJSON fbxToJSON;
fbxToJSON << _rootNode;
QFileInfo modelFile(_bakedModelFilePath);
QString outFilename(modelFile.dir().absolutePath() + "/" + modelFile.completeBaseName() + "_FBX.json");
QFile jsonFile(outFilename);
if (jsonFile.open(QIODevice::WriteOnly)) {
jsonFile.write(fbxToJSON.str().c_str(), fbxToJSON.str().length());
jsonFile.close();
}
}
#endif
qCDebug(model_baking) << "Exported" << _modelURL << "with re-written paths to" << _bakedModelFilePath; qCDebug(model_baking) << "Exported" << _modelURL << "with re-written paths to" << _bakedModelFilePath;
} }

View file

@ -28,8 +28,10 @@
#include <graphics/Geometry.h> #include <graphics/Geometry.h>
#include <graphics/Material.h> #include <graphics/Material.h>
static const QByteArray FBX_BINARY_PROLOG = "Kaydara FBX Binary "; // See comment in FBXReader::parseFBX().
static const int FBX_HEADER_BYTES_BEFORE_VERSION = 23; static const int FBX_HEADER_BYTES_BEFORE_VERSION = 23;
static const QByteArray FBX_BINARY_PROLOG("Kaydara FBX Binary ");
static const QByteArray FBX_BINARY_PROLOG2("\0\x1a\0", 3);
static const quint32 FBX_VERSION_2015 = 7400; static const quint32 FBX_VERSION_2015 = 7400;
static const quint32 FBX_VERSION_2016 = 7500; static const quint32 FBX_VERSION_2016 = 7500;

View file

@ -1603,7 +1603,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
// NOTE: shapeVertices are in joint-frame // NOTE: shapeVertices are in joint-frame
std::vector<ShapeVertices> shapeVertices; std::vector<ShapeVertices> shapeVertices;
shapeVertices.resize(geometry.joints.size()); shapeVertices.resize(std::max(1, geometry.joints.size()) );
// find our special joints // find our special joints
geometry.leftEyeJointIndex = modelIDs.indexOf(jointEyeLeftID); geometry.leftEyeJointIndex = modelIDs.indexOf(jointEyeLeftID);

View file

@ -214,10 +214,7 @@ FBXNode parseBinaryFBXNode(QDataStream& in, int& position, bool has64BitPosition
while (endOffset > position) { while (endOffset > position) {
FBXNode child = parseBinaryFBXNode(in, position, has64BitPositions); FBXNode child = parseBinaryFBXNode(in, position, has64BitPositions);
if (child.name.isNull()) { if (!child.name.isNull()) {
return node;
} else {
node.children.append(child); node.children.append(child);
} }
} }

View file

@ -0,0 +1,114 @@
//
// FBXToJSON.cpp
// libraries/fbx/src
//
// Created by Simon Walton on 5/4/2018.
// Copyright 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
//
#include "FBXToJSON.h"
#include "FBX.h"
using std::string;
template<typename T>
inline FBXToJSON& FBXToJSON::operator<<(const QVector<T>& arrayProp) {
*this << "[";
char comma = ' ';
for (auto& prop : arrayProp) {
*(std::ostringstream*)this << comma << prop;
comma = ',';
}
*this << "] ";
if (arrayProp.size() > 4) {
*this << "// " << arrayProp.size() << " items";
}
*this << '\n';
return *this;
}
FBXToJSON& FBXToJSON::operator<<(const FBXNode& fbxNode) {
string nodeName(fbxNode.name);
if (nodeName.empty()) {
nodeName = "node";
} else {
nodeName = stringEscape(nodeName);
}
*this << string(_indentLevel * 4, ' ') << '"' << nodeName << "\": {\n";
++_indentLevel;
int p = 0;
const char* eol = "";
for (auto& prop : fbxNode.properties) {
*this << eol << string(_indentLevel * 4, ' ') << "\"p" << p++ << "\": ";
switch (prop.userType()) {
case QMetaType::Short:
case QMetaType::Bool:
case QMetaType::Int:
case QMetaType::LongLong:
case QMetaType::Double:
case QMetaType::Float:
*this << prop.toString().toStdString();
break;
case QMetaType::QString:
case QMetaType::QByteArray:
*this << '"' << stringEscape(prop.toByteArray().toStdString()) << '"';
break;
default:
if (prop.canConvert<QVector<float>>()) {
*this << prop.value<QVector<float>>();
} else if (prop.canConvert<QVector<double>>()) {
*this << prop.value<QVector<double>>();
} else if (prop.canConvert<QVector<bool>>()) {
*this << prop.value<QVector<bool>>();
} else if (prop.canConvert<QVector<qint32>>()) {
*this << prop.value<QVector<qint32>>();
} else if (prop.canConvert<QVector<qint64>>()) {
*this << prop.value<QVector<qint64>>();
} else {
*this << "<unimplemented value>";
}
break;
}
eol = ",\n";
}
for (auto& child : fbxNode.children) {
*this << eol;
*this << child;
eol = ",\n";
}
*this << "\n" << string(_indentLevel * 4, ' ') << "}";
--_indentLevel;
return *this;
}
string FBXToJSON::stringEscape(const string& in) {
string out;
out.reserve(in.length());
for (unsigned char inChar: in) {
if (inChar == '"') {
out.append(R"(\")");
}
else if (inChar == '\\') {
out.append(R"(\\)");
}
else if (inChar < 0x20 || inChar == 0x7f) {
char h[5];
sprintf(h, "\\x%02x", inChar);
out.append(h);
}
else out.append(1, inChar);
}
return out;
}

View file

@ -0,0 +1,32 @@
//
// FBXToJSON.h
// libraries/fbx/src
//
// Created by Simon Walton on 5/4/2018.
// Copyright 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
//
#ifndef hifi_FBXToJSON_h
#define hifi_FBXToJSON_h
#include <sstream>
#include <string>
// Forward declarations.
class FBXNode;
template<typename T> class QVector;
class FBXToJSON : public std::ostringstream {
public:
FBXToJSON& operator<<(const FBXNode& fbxNode);
private:
template<typename T> FBXToJSON& operator<<(const QVector<T>& arrayProp);
static std::string stringEscape(const std::string& in);
int _indentLevel { 0 };
};
#endif // hifi_FBXToJSON_h

View file

@ -62,8 +62,7 @@ QByteArray FBXWriter::encodeFBX(const FBXNode& root) {
out.setVersion(QDataStream::Qt_4_5); out.setVersion(QDataStream::Qt_4_5);
out.writeRawData(FBX_BINARY_PROLOG, FBX_BINARY_PROLOG.size()); out.writeRawData(FBX_BINARY_PROLOG, FBX_BINARY_PROLOG.size());
auto bytes = QByteArray(FBX_HEADER_BYTES_BEFORE_VERSION - FBX_BINARY_PROLOG.size(), '\0'); out.writeRawData(FBX_BINARY_PROLOG2, FBX_BINARY_PROLOG2.size());
out.writeRawData(bytes, bytes.size());
#ifdef USE_FBX_2016_FORMAT #ifdef USE_FBX_2016_FORMAT
out << FBX_VERSION_2016; out << FBX_VERSION_2016;

View file

@ -159,9 +159,13 @@ GLExternalTexture::~GLExternalTexture() {
} }
GLVariableAllocationSupport::GLVariableAllocationSupport() { GLVariableAllocationSupport::GLVariableAllocationSupport() {
Backend::textureResourceCount.increment();
} }
GLVariableAllocationSupport::~GLVariableAllocationSupport() { GLVariableAllocationSupport::~GLVariableAllocationSupport() {
Backend::textureResourceCount.decrement();
Backend::textureResourceGPUMemSize.update(_size, 0);
Backend::textureResourcePopulatedGPUMemSize.update(_populatedSize, 0);
} }
void GLVariableAllocationSupport::incrementPopulatedSize(Size delta) const { void GLVariableAllocationSupport::incrementPopulatedSize(Size delta) const {
@ -235,7 +239,6 @@ TransferJob::TransferJob(const Texture& texture,
_transferLambda = [=](const TexturePointer& texture) { _transferLambda = [=](const TexturePointer& texture) {
if (_mipData) { if (_mipData) {
auto gltexture = Backend::getGPUObject<GLTexture>(*texture); auto gltexture = Backend::getGPUObject<GLTexture>(*texture);
;
gltexture->copyMipFaceLinesFromTexture(targetMip, face, transferDimensions, lineOffset, internalFormat, format, gltexture->copyMipFaceLinesFromTexture(targetMip, face, transferDimensions, lineOffset, internalFormat, format,
type, _mipData->size(), _mipData->readData()); type, _mipData->size(), _mipData->readData());
_mipData.reset(); _mipData.reset();
@ -246,8 +249,8 @@ TransferJob::TransferJob(const Texture& texture,
}; };
} }
TransferJob::TransferJob(const std::function<void()>& transferLambda) : TransferJob::TransferJob(uint16_t sourceMip, const std::function<void()>& transferLambda) :
_bufferingRequired(false), _transferLambda([=](const TexturePointer&) { transferLambda(); }) {} _sourceMip(sourceMip), _bufferingRequired(false), _transferLambda([=](const TexturePointer&) { transferLambda(); }) {}
TransferJob::~TransferJob() { TransferJob::~TransferJob() {
Backend::texturePendingGPUTransferMemSize.update(_transferSize, 0); Backend::texturePendingGPUTransferMemSize.update(_transferSize, 0);

View file

@ -70,14 +70,16 @@ private:
Texture::PixelsPointer _mipData; Texture::PixelsPointer _mipData;
size_t _transferOffset{ 0 }; size_t _transferOffset{ 0 };
size_t _transferSize{ 0 }; size_t _transferSize{ 0 };
uint16_t _sourceMip{ 0 };
bool _bufferingRequired{ true }; bool _bufferingRequired{ true };
Lambda _transferLambda{ [](const TexturePointer&) {} }; Lambda _transferLambda{ [](const TexturePointer&) {} };
Lambda _bufferingLambda{ [](const TexturePointer&) {} }; Lambda _bufferingLambda{ [](const TexturePointer&) {} };
public: public:
TransferJob(const TransferJob& other) = delete; TransferJob(const TransferJob& other) = delete;
TransferJob(const std::function<void()>& transferLambda); TransferJob(uint16_t sourceMip, const std::function<void()>& transferLambda);
TransferJob(const Texture& texture, uint16_t sourceMip, uint16_t targetMip, uint8_t face, uint32_t lines = 0, uint32_t lineOffset = 0); TransferJob(const Texture& texture, uint16_t sourceMip, uint16_t targetMip, uint8_t face, uint32_t lines = 0, uint32_t lineOffset = 0);
~TransferJob(); ~TransferJob();
const uint16_t& sourceMip() const { return _sourceMip; }
const size_t& size() const { return _transferSize; } const size_t& size() const { return _transferSize; }
bool bufferingRequired() const { return _bufferingRequired; } bool bufferingRequired() const { return _bufferingRequired; }
void buffer(const TexturePointer& texture) { _bufferingLambda(texture); } void buffer(const TexturePointer& texture) { _bufferingLambda(texture); }
@ -96,6 +98,7 @@ public:
virtual void populateTransferQueue(TransferQueue& pendingTransfers) = 0; virtual void populateTransferQueue(TransferQueue& pendingTransfers) = 0;
void sanityCheck() const; void sanityCheck() const;
uint16 populatedMip() const { return _populatedMip; }
bool canPromote() const { return _allocatedMip > _minAllocatedMip; } bool canPromote() const { return _allocatedMip > _minAllocatedMip; }
bool canDemote() const { return _allocatedMip < _maxAllocatedMip; } bool canDemote() const { return _allocatedMip < _maxAllocatedMip; }
bool hasPendingTransfers() const { return _populatedMip > _allocatedMip; } bool hasPendingTransfers() const { return _populatedMip > _allocatedMip; }
@ -109,7 +112,6 @@ public:
static const size_t MAX_BUFFER_SIZE; static const size_t MAX_BUFFER_SIZE;
protected: protected:
// THe amount of memory currently allocated // THe amount of memory currently allocated
Size _size { 0 }; Size _size { 0 };

View file

@ -43,7 +43,6 @@ using QueuePair = std::pair<TextureWeakPointer, float>;
// Uses a weak pointer to the texture to avoid keeping it in scope if the client stops using it // Uses a weak pointer to the texture to avoid keeping it in scope if the client stops using it
using WorkQueue = std::priority_queue<QueuePair, std::vector<QueuePair>, LessPairSecond<QueuePair>>; using WorkQueue = std::priority_queue<QueuePair, std::vector<QueuePair>, LessPairSecond<QueuePair>>;
using ImmediateQueuePair = std::pair<TexturePointer, float>; using ImmediateQueuePair = std::pair<TexturePointer, float>;
// Contains a priority sorted list of textures on which work is to be done in the current frame // Contains a priority sorted list of textures on which work is to be done in the current frame
using ImmediateWorkQueue = std::priority_queue<ImmediateQueuePair, std::vector<ImmediateQueuePair>, LessPairSecond<ImmediateQueuePair>>; using ImmediateWorkQueue = std::priority_queue<ImmediateQueuePair, std::vector<ImmediateQueuePair>, LessPairSecond<ImmediateQueuePair>>;
@ -53,6 +52,7 @@ using TransferMap = std::map<TextureWeakPointer, TransferQueue, std::owner_less<
class GLTextureTransferEngineDefault : public GLTextureTransferEngine { class GLTextureTransferEngineDefault : public GLTextureTransferEngine {
using Parent = GLTextureTransferEngine; using Parent = GLTextureTransferEngine;
public: public:
// Called once per frame by the GLBackend to manage texture memory // Called once per frame by the GLBackend to manage texture memory
// Will deallocate textures if oversubscribed, // Will deallocate textures if oversubscribed,
@ -129,16 +129,19 @@ void GLBackend::killTextureManagementStage() {
} }
std::vector<TexturePointer> GLTextureTransferEngine::getAllTextures() { std::vector<TexturePointer> GLTextureTransferEngine::getAllTextures() {
std::remove_if(_registeredTextures.begin(), _registeredTextures.end(), [&](const std::weak_ptr<Texture>& weak) -> bool {
return weak.expired();
});
std::vector<TexturePointer> result; std::vector<TexturePointer> result;
result.reserve(_registeredTextures.size()); result.reserve(_registeredTextures.size());
std::remove_if(_registeredTextures.begin(), _registeredTextures.end(), [&](const std::weak_ptr<Texture>& weak)->bool { for (const auto& weak : _registeredTextures) {
auto strong = weak.lock(); auto strong = weak.lock();
bool strongResult = strong.operator bool(); if (!strong) {
if (strongResult) { continue;
result.push_back(strong);
} }
return strongResult; result.push_back(strong);
}); }
return result; return result;
} }
@ -158,7 +161,6 @@ void GLTextureTransferEngineDefault::shutdown() {
#endif #endif
} }
void GLTextureTransferEngineDefault::manageMemory() { void GLTextureTransferEngineDefault::manageMemory() {
PROFILE_RANGE(render_gpu_gl, __FUNCTION__); PROFILE_RANGE(render_gpu_gl, __FUNCTION__);
// reset the count used to limit the number of textures created per frame // reset the count used to limit the number of textures created per frame
@ -225,7 +227,6 @@ void GLTextureTransferEngineDefault::updateMemoryPressure() {
return; return;
} }
auto newState = MemoryPressureState::Idle; auto newState = MemoryPressureState::Idle;
if (pressure < UNDERSUBSCRIBED_PRESSURE_VALUE && (unallocated != 0 && canPromote)) { if (pressure < UNDERSUBSCRIBED_PRESSURE_VALUE && (unallocated != 0 && canPromote)) {
newState = MemoryPressureState::Undersubscribed; newState = MemoryPressureState::Undersubscribed;
@ -270,7 +271,6 @@ void GLTextureTransferEngineDefault::processTransferQueues() {
} }
#endif #endif
// From the pendingTransferMap, queue jobs into the _activeBufferQueue // From the pendingTransferMap, queue jobs into the _activeBufferQueue
// Doing so will lock the weak texture pointer so that it can't be destroyed // Doing so will lock the weak texture pointer so that it can't be destroyed
// while the background thread is working. // while the background thread is working.
@ -294,8 +294,12 @@ void GLTextureTransferEngineDefault::processTransferQueues() {
while (!activeTransferQueue.empty()) { while (!activeTransferQueue.empty()) {
const auto& activeTransferJob = activeTransferQueue.front(); const auto& activeTransferJob = activeTransferQueue.front();
const auto& texturePointer = activeTransferJob.first; const auto& texturePointer = activeTransferJob.first;
GLTexture* gltexture = Backend::getGPUObject<GLTexture>(*texturePointer);
GLVariableAllocationSupport* vargltexture = dynamic_cast<GLVariableAllocationSupport*>(gltexture);
const auto& tranferJob = activeTransferJob.second; const auto& tranferJob = activeTransferJob.second;
tranferJob->transfer(texturePointer); if (tranferJob->sourceMip() < vargltexture->populatedMip()) {
tranferJob->transfer(texturePointer);
}
// The pop_front MUST be the last call since all of these varaibles in scope are // The pop_front MUST be the last call since all of these varaibles in scope are
// references that will be invalid after the pop // references that will be invalid after the pop
activeTransferQueue.pop_front(); activeTransferQueue.pop_front();
@ -322,7 +326,7 @@ void GLTextureTransferEngineDefault::populateActiveBufferQueue() {
ActiveTransferQueue newBufferJobs; ActiveTransferQueue newBufferJobs;
size_t newTransferSize{ 0 }; size_t newTransferSize{ 0 };
for (auto itr = _pendingTransfersMap.begin(); itr != _pendingTransfersMap.end(); ) { for (auto itr = _pendingTransfersMap.begin(); itr != _pendingTransfersMap.end();) {
const auto& weakTexture = itr->first; const auto& weakTexture = itr->first;
const auto texture = weakTexture.lock(); const auto texture = weakTexture.lock();
@ -488,14 +492,14 @@ void GLTextureTransferEngineDefault::processDemotes(size_t reliefRequired, const
// FIXME hack for stats display // FIXME hack for stats display
QString getTextureMemoryPressureModeString() { QString getTextureMemoryPressureModeString() {
switch (_memoryPressureState) { switch (_memoryPressureState) {
case MemoryPressureState::Undersubscribed: case MemoryPressureState::Undersubscribed:
return "Undersubscribed"; return "Undersubscribed";
case MemoryPressureState::Transfer: case MemoryPressureState::Transfer:
return "Transfer"; return "Transfer";
case MemoryPressureState::Idle: case MemoryPressureState::Idle:
return "Idle"; return "Idle";
} }
Q_UNREACHABLE(); Q_UNREACHABLE();
return "Unknown"; return "Unknown";

View file

@ -279,8 +279,6 @@ using GL41VariableAllocationTexture = GL41Backend::GL41VariableAllocationTexture
GL41VariableAllocationTexture::GL41VariableAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL41VariableAllocationTexture::GL41VariableAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) :
GL41Texture(backend, texture) GL41Texture(backend, texture)
{ {
Backend::textureResourceCount.increment();
auto mipLevels = texture.getNumMips(); auto mipLevels = texture.getNumMips();
_allocatedMip = mipLevels; _allocatedMip = mipLevels;
_maxAllocatedMip = _populatedMip = mipLevels; _maxAllocatedMip = _populatedMip = mipLevels;
@ -303,9 +301,6 @@ GL41VariableAllocationTexture::GL41VariableAllocationTexture(const std::weak_ptr
} }
GL41VariableAllocationTexture::~GL41VariableAllocationTexture() { GL41VariableAllocationTexture::~GL41VariableAllocationTexture() {
Backend::textureResourceCount.decrement();
Backend::textureResourceGPUMemSize.update(_size, 0);
Backend::textureResourcePopulatedGPUMemSize.update(_populatedSize, 0);
} }
void GL41VariableAllocationTexture::allocateStorage(uint16 allocatedMip) { void GL41VariableAllocationTexture::allocateStorage(uint16 allocatedMip) {
@ -605,7 +600,7 @@ void GL41VariableAllocationTexture::populateTransferQueue(TransferQueue& pending
} }
// queue up the sampler and populated mip change for after the transfer has completed // queue up the sampler and populated mip change for after the transfer has completed
pendingTransfers.emplace(new TransferJob([=] { pendingTransfers.emplace(new TransferJob(sourceMip, [=] {
_populatedMip = sourceMip; _populatedMip = sourceMip;
incrementPopulatedSize(_gpuObject.evalMipSize(sourceMip)); incrementPopulatedSize(_gpuObject.evalMipSize(sourceMip));
sanityCheck(); sanityCheck();

View file

@ -31,13 +31,9 @@ using GL45Texture = GL45Backend::GL45Texture;
using GL45VariableAllocationTexture = GL45Backend::GL45VariableAllocationTexture; using GL45VariableAllocationTexture = GL45Backend::GL45VariableAllocationTexture;
GL45VariableAllocationTexture::GL45VariableAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL45Texture(backend, texture) { GL45VariableAllocationTexture::GL45VariableAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL45Texture(backend, texture) {
Backend::textureResourceCount.increment();
} }
GL45VariableAllocationTexture::~GL45VariableAllocationTexture() { GL45VariableAllocationTexture::~GL45VariableAllocationTexture() {
Backend::textureResourceCount.decrement();
Backend::textureResourceGPUMemSize.update(_size, 0);
Backend::textureResourcePopulatedGPUMemSize.update(_populatedSize, 0);
} }
#if GPU_BINDLESS_TEXTURES #if GPU_BINDLESS_TEXTURES
@ -286,7 +282,7 @@ void GL45ResourceTexture::populateTransferQueue(TransferQueue& pendingTransfers)
} }
// queue up the sampler and populated mip change for after the transfer has completed // queue up the sampler and populated mip change for after the transfer has completed
pendingTransfers.emplace(new TransferJob([=] { pendingTransfers.emplace(new TransferJob(sourceMip, [=] {
_populatedMip = sourceMip; _populatedMip = sourceMip;
incrementPopulatedSize(_gpuObject.evalMipSize(sourceMip)); incrementPopulatedSize(_gpuObject.evalMipSize(sourceMip));
sanityCheck(); sanityCheck();

View file

@ -341,8 +341,6 @@ using GLESVariableAllocationTexture = GLESBackend::GLESVariableAllocationTexture
GLESVariableAllocationTexture::GLESVariableAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GLESVariableAllocationTexture::GLESVariableAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) :
GLESTexture(backend, texture) GLESTexture(backend, texture)
{ {
Backend::textureResourceCount.increment();
auto mipLevels = texture.getNumMips(); auto mipLevels = texture.getNumMips();
_allocatedMip = mipLevels; _allocatedMip = mipLevels;
_maxAllocatedMip = _populatedMip = mipLevels; _maxAllocatedMip = _populatedMip = mipLevels;
@ -366,9 +364,6 @@ GLESVariableAllocationTexture::GLESVariableAllocationTexture(const std::weak_ptr
} }
GLESVariableAllocationTexture::~GLESVariableAllocationTexture() { GLESVariableAllocationTexture::~GLESVariableAllocationTexture() {
Backend::textureResourceCount.decrement();
Backend::textureResourceGPUMemSize.update(_size, 0);
Backend::textureResourcePopulatedGPUMemSize.update(_populatedSize, 0);
} }
void GLESVariableAllocationTexture::allocateStorage(uint16 allocatedMip) { void GLESVariableAllocationTexture::allocateStorage(uint16 allocatedMip) {
@ -669,7 +664,7 @@ void GLESVariableAllocationTexture::populateTransferQueue(TransferJob::Queue& qu
} }
// queue up the sampler and populated mip change for after the transfer has completed // queue up the sampler and populated mip change for after the transfer has completed
queue.emplace(new TransferJob([=] { queue.emplace(new TransferJob(sourceMip, [=] {
_populatedMip = sourceMip; _populatedMip = sourceMip;
incrementPopulatedSize(_gpuObject.evalMipSize(sourceMip)); incrementPopulatedSize(_gpuObject.evalMipSize(sourceMip));
sanityCheck(); sanityCheck();

View file

@ -19,8 +19,7 @@
#if defined(NSIGHT_FOUND) #if defined(NSIGHT_FOUND)
#include "nvToolsExt.h" #include "nvToolsExt.h"
ProfileRangeBatch::ProfileRangeBatch(gpu::Batch& batch, const char* name) : _batch(batch) {
ProfileRangeBatch::ProfileRangeBatch(gpu::Batch& batch, const char *name) : _batch(batch) {
_batch.pushProfileRange(name); _batch.pushProfileRange(name);
} }
@ -38,19 +37,15 @@ static const int MAX_NUM_UNIFORM_BUFFERS = 14;
static const int MAX_NUM_RESOURCE_BUFFERS = 16; static const int MAX_NUM_RESOURCE_BUFFERS = 16;
static const int MAX_NUM_RESOURCE_TEXTURES = 16; static const int MAX_NUM_RESOURCE_TEXTURES = 16;
size_t Batch::_commandsMax { BATCH_PREALLOCATE_MIN }; size_t Batch::_commandsMax{ BATCH_PREALLOCATE_MIN };
size_t Batch::_commandOffsetsMax { BATCH_PREALLOCATE_MIN }; size_t Batch::_commandOffsetsMax{ BATCH_PREALLOCATE_MIN };
size_t Batch::_paramsMax { BATCH_PREALLOCATE_MIN }; size_t Batch::_paramsMax{ BATCH_PREALLOCATE_MIN };
size_t Batch::_dataMax { BATCH_PREALLOCATE_MIN }; size_t Batch::_dataMax{ BATCH_PREALLOCATE_MIN };
size_t Batch::_objectsMax { BATCH_PREALLOCATE_MIN }; size_t Batch::_objectsMax{ BATCH_PREALLOCATE_MIN };
size_t Batch::_drawCallInfosMax { BATCH_PREALLOCATE_MIN }; size_t Batch::_drawCallInfosMax{ BATCH_PREALLOCATE_MIN };
Batch::Batch(const char* name) { Batch::Batch(const char* name) {
#ifdef DEBUG _name = name;
if (name) {
_name = name;
}
#endif
_commands.reserve(_commandsMax); _commands.reserve(_commandsMax);
_commandOffsets.reserve(_commandOffsetsMax); _commandOffsets.reserve(_commandOffsetsMax);
_params.reserve(_paramsMax); _params.reserve(_paramsMax);
@ -59,38 +54,6 @@ Batch::Batch(const char* name) {
_drawCallInfos.reserve(_drawCallInfosMax); _drawCallInfos.reserve(_drawCallInfosMax);
} }
Batch::Batch(const Batch& batch_) {
Batch& batch = *const_cast<Batch*>(&batch_);
#ifdef DEBUG
_name = batch_._name;
#endif
_commands.swap(batch._commands);
_commandOffsets.swap(batch._commandOffsets);
_params.swap(batch._params);
_data.swap(batch._data);
_invalidModel = batch._invalidModel;
_currentModel = batch._currentModel;
_objects.swap(batch._objects);
_currentNamedCall = batch._currentNamedCall;
_buffers._items.swap(batch._buffers._items);
_textures._items.swap(batch._textures._items);
_textureTables._items.swap(batch._textureTables._items);
_streamFormats._items.swap(batch._streamFormats._items);
_transforms._items.swap(batch._transforms._items);
_pipelines._items.swap(batch._pipelines._items);
_framebuffers._items.swap(batch._framebuffers._items);
_swapChains._items.swap(batch._swapChains._items);
_drawCallInfos.swap(batch._drawCallInfos);
_queries._items.swap(batch._queries._items);
_lambdas._items.swap(batch._lambdas._items);
_profileRanges._items.swap(batch._profileRanges._items);
_names._items.swap(batch._names._items);
_namedData.swap(batch._namedData);
_enableStereo = batch._enableStereo;
_enableSkybox = batch._enableSkybox;
}
Batch::~Batch() { Batch::~Batch() {
_commandsMax = std::max(_commands.size(), _commandsMax); _commandsMax = std::max(_commands.size(), _commandsMax);
_commandOffsetsMax = std::max(_commandOffsets.size(), _commandOffsetsMax); _commandOffsetsMax = std::max(_commandOffsets.size(), _commandOffsetsMax);
@ -100,6 +63,10 @@ Batch::~Batch() {
_drawCallInfosMax = std::max(_drawCallInfos.size(), _drawCallInfosMax); _drawCallInfosMax = std::max(_drawCallInfos.size(), _drawCallInfosMax);
} }
void Batch::setName(const char* name) {
_name = name;
}
void Batch::clear() { void Batch::clear() {
_commandsMax = std::max(_commands.size(), _commandsMax); _commandsMax = std::max(_commands.size(), _commandsMax);
_commandOffsetsMax = std::max(_commandOffsets.size(), _commandOffsetsMax); _commandOffsetsMax = std::max(_commandOffsets.size(), _commandOffsetsMax);
@ -110,18 +77,30 @@ void Batch::clear() {
_commands.clear(); _commands.clear();
_commandOffsets.clear(); _commandOffsets.clear();
_params.clear();
_data.clear(); _data.clear();
_drawCallInfos.clear();
_buffers.clear(); _buffers.clear();
_framebuffers.clear();
_lambdas.clear();
_names.clear();
_namedData.clear();
_objects.clear();
_params.clear();
_pipelines.clear();
_profileRanges.clear();
_queries.clear();
_swapChains.clear();
_streamFormats.clear();
_textures.clear(); _textures.clear();
_textureTables.clear(); _textureTables.clear();
_streamFormats.clear();
_transforms.clear(); _transforms.clear();
_pipelines.clear();
_framebuffers.clear(); _name = nullptr;
_swapChains.clear(); _invalidModel = true;
_objects.clear(); _currentModel = Transform();
_drawCallInfos.clear(); _projectionJitter = glm::vec2(0.0f);
_enableStereo = true;
_enableSkybox = false;
} }
size_t Batch::cacheData(size_t size, const void* data) { size_t Batch::cacheData(size_t size, const void* data) {
@ -177,7 +156,6 @@ void Batch::drawIndexedInstanced(uint32 numInstances, Primitive primitiveType, u
captureDrawCallInfo(); captureDrawCallInfo();
} }
void Batch::multiDrawIndirect(uint32 numCommands, Primitive primitiveType) { void Batch::multiDrawIndirect(uint32 numCommands, Primitive primitiveType) {
ADD_COMMAND(multiDrawIndirect); ADD_COMMAND(multiDrawIndirect);
_params.emplace_back(numCommands); _params.emplace_back(numCommands);
@ -244,7 +222,6 @@ void Batch::setIndirectBuffer(const BufferPointer& buffer, Offset offset, Offset
_params.emplace_back(stride); _params.emplace_back(stride);
} }
void Batch::setModelTransform(const Transform& model) { void Batch::setModelTransform(const Transform& model) {
ADD_COMMAND(setModelTransform); ADD_COMMAND(setModelTransform);
@ -266,19 +243,19 @@ void Batch::setProjectionTransform(const Mat4& proj) {
} }
void Batch::setProjectionJitter(float jx, float jy) { void Batch::setProjectionJitter(float jx, float jy) {
_projectionJitter.x = jx; _projectionJitter.x = jx;
_projectionJitter.y = jy; _projectionJitter.y = jy;
pushProjectionJitter(jx, jy); pushProjectionJitter(jx, jy);
} }
void Batch::pushProjectionJitter(float jx, float jy) { void Batch::pushProjectionJitter(float jx, float jy) {
ADD_COMMAND(setProjectionJitter); ADD_COMMAND(setProjectionJitter);
_params.emplace_back(jx); _params.emplace_back(jx);
_params.emplace_back(jy); _params.emplace_back(jy);
} }
void Batch::popProjectionJitter() { void Batch::popProjectionJitter() {
pushProjectionJitter(_projectionJitter.x, _projectionJitter.y); pushProjectionJitter(_projectionJitter.x, _projectionJitter.y);
} }
void Batch::setViewportTransform(const Vec4i& viewport) { void Batch::setViewportTransform(const Vec4i& viewport) {
@ -374,7 +351,6 @@ void Batch::setFramebuffer(const FramebufferPointer& framebuffer) {
ADD_COMMAND(setFramebuffer); ADD_COMMAND(setFramebuffer);
_params.emplace_back(_framebuffers.cache(framebuffer)); _params.emplace_back(_framebuffers.cache(framebuffer));
} }
void Batch::setFramebufferSwapChain(const FramebufferSwapChainPointer& framebuffer, unsigned int swapChainIndex) { void Batch::setFramebufferSwapChain(const FramebufferSwapChainPointer& framebuffer, unsigned int swapChainIndex) {
@ -582,9 +558,9 @@ void Batch::captureDrawCallInfo() {
} }
void Batch::captureNamedDrawCallInfo(std::string name) { void Batch::captureNamedDrawCallInfo(std::string name) {
std::swap(_currentNamedCall, name); // Set and save _currentNamedCall std::swap(_currentNamedCall, name); // Set and save _currentNamedCall
captureDrawCallInfoImpl(); captureDrawCallInfoImpl();
std::swap(_currentNamedCall, name); // Restore _currentNamedCall std::swap(_currentNamedCall, name); // Restore _currentNamedCall
} }
// Debugging // Debugging

View file

@ -92,9 +92,12 @@ public:
void captureNamedDrawCallInfo(std::string name); void captureNamedDrawCallInfo(std::string name);
Batch(const char* name = nullptr); Batch(const char* name = nullptr);
Batch(const Batch& batch); // Disallow copy construction and assignement of batches
Batch(const Batch& batch) = delete;
Batch& operator=(const Batch& batch) = delete;
~Batch(); ~Batch();
void setName(const char* name);
void clear(); void clear();
// Batches may need to override the context level stereo settings // Batches may need to override the context level stereo settings
@ -506,10 +509,7 @@ public:
bool _enableSkybox { false }; bool _enableSkybox { false };
protected: protected:
const char* _name;
#ifdef DEBUG
std::string _name;
#endif
friend class Context; friend class Context;
friend class Frame; friend class Frame;

View file

@ -47,6 +47,10 @@ Context::Context(const Context& context) {
} }
Context::~Context() { Context::~Context() {
for (auto batch : _batchPool) {
delete batch;
}
_batchPool.clear();
} }
const std::string& Context::getBackendVersion() const { const std::string& Context::getBackendVersion() const {
@ -65,7 +69,7 @@ void Context::beginFrame(const glm::mat4& renderView, const glm::mat4& renderPos
} }
} }
void Context::appendFrameBatch(Batch& batch) { void Context::appendFrameBatch(const BatchPointer& batch) {
if (!_frameActive) { if (!_frameActive) {
qWarning() << "Batch executed outside of frame boundaries"; qWarning() << "Batch executed outside of frame boundaries";
return; return;
@ -115,7 +119,7 @@ void Context::executeFrame(const FramePointer& frame) const {
// Execute the frame rendering commands // Execute the frame rendering commands
for (auto& batch : frame->batches) { for (auto& batch : frame->batches) {
_backend->render(batch); _backend->render(*batch);
} }
Batch endBatch("Context::executeFrame::end"); Batch endBatch("Context::executeFrame::end");
@ -323,6 +327,7 @@ Size Context::getTextureExternalGPUMemSize() {
uint32_t Context::getTexturePendingGPUTransferCount() { uint32_t Context::getTexturePendingGPUTransferCount() {
return Backend::texturePendingGPUTransferCount.getValue(); return Backend::texturePendingGPUTransferCount.getValue();
} }
Size Context::getTexturePendingGPUTransferMemSize() { Size Context::getTexturePendingGPUTransferMemSize() {
return Backend::texturePendingGPUTransferMemSize.getValue(); return Backend::texturePendingGPUTransferMemSize.getValue();
} }
@ -334,3 +339,34 @@ Size Context::getTextureResourcePopulatedGPUMemSize() {
Size Context::getTextureResourceIdealGPUMemSize() { Size Context::getTextureResourceIdealGPUMemSize() {
return Backend::textureResourceIdealGPUMemSize.getValue(); return Backend::textureResourceIdealGPUMemSize.getValue();
} }
BatchPointer Context::acquireBatch(const char* name) {
Batch* rawBatch = nullptr;
{
Lock lock(_batchPoolMutex);
if (!_batchPool.empty()) {
rawBatch = _batchPool.front();
_batchPool.pop_front();
}
}
if (!rawBatch) {
rawBatch = new Batch();
}
rawBatch->setName(name);
return BatchPointer(rawBatch, [this](Batch* batch) { releaseBatch(batch); });
}
void Context::releaseBatch(Batch* batch) {
batch->clear();
Lock lock(_batchPoolMutex);
_batchPool.push_back(batch);
}
void gpu::doInBatch(const char* name,
const std::shared_ptr<gpu::Context>& context,
const std::function<void(Batch& batch)>& f) {
auto batch = context->acquireBatch(name);
f(*batch);
context->appendFrameBatch(batch);
}

View file

@ -52,8 +52,7 @@ public:
class Backend { class Backend {
public: public:
virtual~ Backend() {}; virtual ~Backend(){};
virtual const std::string& getVersion() const = 0; virtual const std::string& getVersion() const = 0;
@ -78,12 +77,11 @@ public:
TransformCamera getEyeCamera(int eye, const StereoState& stereo, const Transform& xformView, Vec2 normalizedJitter) const; TransformCamera getEyeCamera(int eye, const StereoState& stereo, const Transform& xformView, Vec2 normalizedJitter) const;
}; };
template <typename T, typename U>
template<typename T, typename U>
static void setGPUObject(const U& object, T* gpuObject) { static void setGPUObject(const U& object, T* gpuObject) {
object.gpuObject.setGPUObject(gpuObject); object.gpuObject.setGPUObject(gpuObject);
} }
template<typename T, typename U> template <typename T, typename U>
static T* getGPUObject(const U& object) { static T* getGPUObject(const U& object) {
return reinterpret_cast<T*>(object.gpuObject.getGPUObject()); return reinterpret_cast<T*>(object.gpuObject.getGPUObject());
} }
@ -95,26 +93,25 @@ public:
// These should only be accessed by Backend implementation to report the buffer and texture allocations, // These should only be accessed by Backend implementation to report the buffer and texture allocations,
// they are NOT public objects // they are NOT public objects
static ContextMetricSize freeGPUMemSize; static ContextMetricSize freeGPUMemSize;
static ContextMetricCount bufferCount; static ContextMetricCount bufferCount;
static ContextMetricSize bufferGPUMemSize; static ContextMetricSize bufferGPUMemSize;
static ContextMetricCount textureResidentCount; static ContextMetricCount textureResidentCount;
static ContextMetricCount textureFramebufferCount; static ContextMetricCount textureFramebufferCount;
static ContextMetricCount textureResourceCount; static ContextMetricCount textureResourceCount;
static ContextMetricCount textureExternalCount; static ContextMetricCount textureExternalCount;
static ContextMetricSize textureResidentGPUMemSize; static ContextMetricSize textureResidentGPUMemSize;
static ContextMetricSize textureFramebufferGPUMemSize; static ContextMetricSize textureFramebufferGPUMemSize;
static ContextMetricSize textureResourceGPUMemSize; static ContextMetricSize textureResourceGPUMemSize;
static ContextMetricSize textureExternalGPUMemSize; static ContextMetricSize textureExternalGPUMemSize;
static ContextMetricCount texturePendingGPUTransferCount; static ContextMetricCount texturePendingGPUTransferCount;
static ContextMetricSize texturePendingGPUTransferMemSize; static ContextMetricSize texturePendingGPUTransferMemSize;
static ContextMetricSize textureResourcePopulatedGPUMemSize; static ContextMetricSize textureResourcePopulatedGPUMemSize;
static ContextMetricSize textureResourceIdealGPUMemSize; static ContextMetricSize textureResourceIdealGPUMemSize;
protected: protected:
virtual bool isStereo() { virtual bool isStereo() {
@ -144,7 +141,6 @@ public:
typedef BackendPointer (*CreateBackend)(); typedef BackendPointer (*CreateBackend)();
typedef bool (*MakeProgram)(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler); typedef bool (*MakeProgram)(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler);
// This one call must happen before any context is created or used (Shader::MakeProgram) in order to setup the Backend and any singleton data needed // This one call must happen before any context is created or used (Shader::MakeProgram) in order to setup the Backend and any singleton data needed
template <class T> template <class T>
static void init() { static void init() {
@ -161,9 +157,12 @@ public:
const std::string& getBackendVersion() const; const std::string& getBackendVersion() const;
void beginFrame(const glm::mat4& renderView = glm::mat4(), const glm::mat4& renderPose = glm::mat4()); void beginFrame(const glm::mat4& renderView = glm::mat4(), const glm::mat4& renderPose = glm::mat4());
void appendFrameBatch(Batch& batch); void appendFrameBatch(const BatchPointer& batch);
FramePointer endFrame(); FramePointer endFrame();
BatchPointer acquireBatch(const char* name = nullptr);
void releaseBatch(Batch* batch);
// MUST only be called on the rendering thread // MUST only be called on the rendering thread
// //
// Handle any pending operations to clean up (recycle / deallocate) resources no longer in use // Handle any pending operations to clean up (recycle / deallocate) resources no longer in use
@ -212,7 +211,7 @@ public:
// It s here for convenience to easily capture a snapshot // It s here for convenience to easily capture a snapshot
void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage); void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage);
// Repporting stats of the context // Repporting stats of the context
void resetStats() const; void resetStats() const;
void getStats(ContextStats& stats) const; void getStats(ContextStats& stats) const;
@ -250,10 +249,12 @@ protected:
Context(const Context& context); Context(const Context& context);
std::shared_ptr<Backend> _backend; std::shared_ptr<Backend> _backend;
bool _frameActive { false }; std::mutex _batchPoolMutex;
std::list<Batch*> _batchPool;
bool _frameActive{ false };
FramePointer _currentFrame; FramePointer _currentFrame;
RangeTimerPointer _frameRangeTimer; RangeTimerPointer _frameRangeTimer;
StereoState _stereo; StereoState _stereo;
// Sampled at the end of every frame, the stats of all the counters // Sampled at the end of every frame, the stats of all the counters
mutable ContextStats _frameStats; mutable ContextStats _frameStats;
@ -273,14 +274,8 @@ protected:
}; };
typedef std::shared_ptr<Context> ContextPointer; typedef std::shared_ptr<Context> ContextPointer;
template<typename F> void doInBatch(const char* name, const std::shared_ptr<gpu::Context>& context, const std::function<void(Batch& batch)>& f);
void doInBatch(const char* name, std::shared_ptr<gpu::Context> context, F f) {
gpu::Batch batch(name);
f(batch);
context->appendFrameBatch(batch);
}
};
}; // namespace gpu
#endif #endif

View file

@ -21,6 +21,7 @@ namespace gpu {
using Lock = std::unique_lock<Mutex>; using Lock = std::unique_lock<Mutex>;
class Batch; class Batch;
using BatchPointer = std::shared_ptr<Batch>;
class Backend; class Backend;
using BackendPointer = std::shared_ptr<Backend>; using BackendPointer = std::shared_ptr<Backend>;
class Context; class Context;

View file

@ -28,8 +28,8 @@ Frame::~Frame() {
} }
void Frame::finish() { void Frame::finish() {
for (Batch& batch : batches) { for (const auto& batch : batches) {
batch.finishFrame(bufferUpdates); batch->finishFrame(bufferUpdates);
} }
} }

View file

@ -22,7 +22,7 @@ namespace gpu {
public: public:
Frame(); Frame();
virtual ~Frame(); virtual ~Frame();
using Batches = std::vector<Batch>; using Batches = std::vector<BatchPointer>;
using FramebufferRecycler = std::function<void(const FramebufferPointer&)>; using FramebufferRecycler = std::function<void(const FramebufferPointer&)>;
using OverlayRecycler = std::function<void(const TexturePointer&)>; using OverlayRecycler = std::function<void(const TexturePointer&)>;

View file

@ -767,10 +767,10 @@ bool AddressManager::handleUsername(const QString& lookupString) {
} }
bool AddressManager::setHost(const QString& host, LookupTrigger trigger, quint16 port) { bool AddressManager::setHost(const QString& host, LookupTrigger trigger, quint16 port) {
if (host != _domainURL.host() || port != _domainURL.port()) { bool hostHasChanged = QString::compare(host, _domainURL.host(), Qt::CaseInsensitive);
if (hostHasChanged || port != _domainURL.port()) {
addCurrentAddressToHistory(trigger); addCurrentAddressToHistory(trigger);
bool emitHostChanged = host != _domainURL.host();
_domainURL = QUrl(); _domainURL = QUrl();
_domainURL.setScheme(URL_SCHEME_HIFI); _domainURL.setScheme(URL_SCHEME_HIFI);
_domainURL.setHost(host); _domainURL.setHost(host);
@ -781,7 +781,7 @@ bool AddressManager::setHost(const QString& host, LookupTrigger trigger, quint16
// any host change should clear the shareable place name // any host change should clear the shareable place name
_shareablePlaceName.clear(); _shareablePlaceName.clear();
if (emitHostChanged) { if (hostHasChanged) {
emit hostChanged(host); emit hostChanged(host);
} }

View file

@ -738,21 +738,20 @@ void RenderDeferred::run(const RenderContextPointer& renderContext, const Inputs
} }
auto previousBatch = args->_batch; auto previousBatch = args->_batch;
gpu::Batch batch; gpu::doInBatch(nullptr, args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch; args->_batch = &batch;
_gpuTimer->begin(batch); _gpuTimer->begin(batch);
setupJob.run(renderContext, deferredTransform, deferredFramebuffer, lightingModel, haze, surfaceGeometryFramebuffer, ssaoFramebuffer, subsurfaceScatteringResource); setupJob.run(renderContext, deferredTransform, deferredFramebuffer, lightingModel, haze, surfaceGeometryFramebuffer, ssaoFramebuffer, subsurfaceScatteringResource);
lightsJob.run(renderContext, deferredTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer, lightClusters); lightsJob.run(renderContext, deferredTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer, lightClusters);
cleanupJob.run(renderContext); cleanupJob.run(renderContext);
_gpuTimer->end(batch); _gpuTimer->end(batch);
args->_context->appendFrameBatch(batch); });
args->_batch = previousBatch; args->_batch = previousBatch;
auto config = std::static_pointer_cast<Config>(renderContext->jobConfig); auto config = std::static_pointer_cast<Config>(renderContext->jobConfig);
config->setGPUBatchRunTime(_gpuTimer->getGPUAverage(), _gpuTimer->getBatchAverage()); config->setGPUBatchRunTime(_gpuTimer->getGPUAverage(), _gpuTimer->getBatchAverage());
} }

View file

@ -707,85 +707,83 @@ void DebugLightClusters::run(const render::RenderContextPointer& renderContext,
auto args = renderContext->args; auto args = renderContext->args;
gpu::Batch batch;
batch.enableStereo(false); gpu::doInBatch(nullptr, args->_context, [&](gpu::Batch& batch) {
batch.enableStereo(false);
// Assign the camera transform
batch.setViewportTransform(args->_viewport);
glm::mat4 projMat;
Transform viewMat;
args->getViewFrustum().evalProjectionMatrix(projMat);
args->getViewFrustum().evalViewTransform(viewMat);
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat, true);
// Assign the camera transform // Then the actual ClusterGrid attributes
batch.setViewportTransform(args->_viewport); batch.setModelTransform(Transform());
glm::mat4 projMat;
Transform viewMat;
args->getViewFrustum().evalProjectionMatrix(projMat);
args->getViewFrustum().evalViewTransform(viewMat);
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat, true);
// Bind the Light CLuster data strucutre
// Then the actual ClusterGrid attributes batch.setUniformBuffer(LIGHT_GPU_SLOT, lightClusters->_lightStage->getLightArrayBuffer());
batch.setModelTransform(Transform()); batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustumGridBuffer);
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer);
// Bind the Light CLuster data strucutre batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, lightClusters->_clusterContentBuffer);
batch.setUniformBuffer(LIGHT_GPU_SLOT, lightClusters->_lightStage->getLightArrayBuffer());
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustumGridBuffer);
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer);
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, lightClusters->_clusterContentBuffer);
if (doDrawClusterFromDepth) { if (doDrawClusterFromDepth) {
batch.setPipeline(getDrawClusterFromDepthPipeline()); batch.setPipeline(getDrawClusterFromDepthPipeline());
batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, deferredTransform->getFrameTransformBuffer()); batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, deferredTransform->getFrameTransformBuffer());
if (linearDepthTarget) { if (linearDepthTarget) {
batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, linearDepthTarget->getLinearDepthTexture()); batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, linearDepthTarget->getLinearDepthTexture());
}
batch.draw(gpu::TRIANGLE_STRIP, 4, 0);
batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, nullptr);
batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr);
} }
batch.draw(gpu::TRIANGLE_STRIP, 4, 0); if (doDrawContent) {
batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, nullptr); // bind the one gpu::Pipeline we need
batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr); batch.setPipeline(getDrawClusterContentPipeline());
} batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, deferredTransform->getFrameTransformBuffer());
if (doDrawContent) { if (linearDepthTarget) {
batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, linearDepthTarget->getLinearDepthTexture());
}
// bind the one gpu::Pipeline we need batch.draw(gpu::TRIANGLE_STRIP, 4, 0);
batch.setPipeline(getDrawClusterContentPipeline());
batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, deferredTransform->getFrameTransformBuffer());
if (linearDepthTarget) { batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, nullptr);
batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, linearDepthTarget->getLinearDepthTexture()); batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr);
}
});
gpu::doInBatch(nullptr, args->_context, [&](gpu::Batch& batch) {
auto& drawGridAndCleanBatch = batch;
if (doDrawGrid) {
// bind the one gpu::Pipeline we need
drawGridAndCleanBatch.setPipeline(getDrawClusterGridPipeline());
auto dims = lightClusters->_frustumGridBuffer->dims;
glm::ivec3 summedDims(dims.x * dims.y * dims.z, dims.x * dims.y, dims.x);
drawGridAndCleanBatch.drawInstanced(summedDims.x, gpu::LINES, 24, 0);
} }
batch.draw(gpu::TRIANGLE_STRIP, 4, 0); drawGridAndCleanBatch.setUniformBuffer(LIGHT_GPU_SLOT, nullptr);
drawGridAndCleanBatch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, nullptr);
drawGridAndCleanBatch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, nullptr);
drawGridAndCleanBatch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, nullptr);
batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, nullptr); drawGridAndCleanBatch.setResourceTexture(DEFERRED_BUFFER_COLOR_UNIT, nullptr);
batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr); drawGridAndCleanBatch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, nullptr);
} drawGridAndCleanBatch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, nullptr);
drawGridAndCleanBatch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, nullptr);
});
gpu::Batch drawGridAndCleanBatch;
if (doDrawGrid) {
// bind the one gpu::Pipeline we need
drawGridAndCleanBatch.setPipeline(getDrawClusterGridPipeline());
auto dims = lightClusters->_frustumGridBuffer->dims;
glm::ivec3 summedDims(dims.x*dims.y * dims.z, dims.x*dims.y, dims.x);
drawGridAndCleanBatch.drawInstanced(summedDims.x, gpu::LINES, 24, 0);
}
drawGridAndCleanBatch.setUniformBuffer(LIGHT_GPU_SLOT, nullptr);
drawGridAndCleanBatch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, nullptr);
drawGridAndCleanBatch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, nullptr);
drawGridAndCleanBatch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, nullptr);
drawGridAndCleanBatch.setResourceTexture(DEFERRED_BUFFER_COLOR_UNIT, nullptr);
drawGridAndCleanBatch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, nullptr);
drawGridAndCleanBatch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, nullptr);
drawGridAndCleanBatch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, nullptr);
args->_context->appendFrameBatch(batch);
args->_context->appendFrameBatch(drawGridAndCleanBatch);
} }

View file

@ -1,7 +1,3 @@
# Turn on testing (so that add_test works)
enable_testing()
# add the test directories # add the test directories
file(GLOB TEST_SUBDIRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/*") file(GLOB TEST_SUBDIRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/*")
list(REMOVE_ITEM TEST_SUBDIRS "CMakeFiles" "mocha") list(REMOVE_ITEM TEST_SUBDIRS "CMakeFiles" "mocha")

View file

@ -16,6 +16,7 @@
#include <QtCore/QFileInfo> #include <QtCore/QFileInfo>
#include <functional> #include <functional>
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include <SharedUtil.h>
#include "GLMTestUtils.h" #include "GLMTestUtils.h"
// Implements several extensions to QtTest. // Implements several extensions to QtTest.
@ -37,7 +38,6 @@
// from scratch using QTest::qFail, for example). // from scratch using QTest::qFail, for example).
// //
float getErrorDifference(const float& a, const float& b) { float getErrorDifference(const float& a, const float& b) {
return fabsf(a - b); return fabsf(a - b);
} }
@ -69,7 +69,7 @@ QString QTest_generateCompareFailureMessage (
QString pad2 = QString(")").rightJustified(pad2_, ' '); QString pad2 = QString(")").rightJustified(pad2_, ' ');
QString msg; QString msg;
QTextStream stream (&msg); QTextStream stream(&msg);
stream << failMessage << "\n\t" stream << failMessage << "\n\t"
"Actual: (" << actual_expr << pad1 << ": " << actual << "\n\t" "Actual: (" << actual_expr << pad1 << ": " << actual << "\n\t"
"Expected: (" << expected_expr << pad2 << ": " << expected << "\n\t"; "Expected: (" << expected_expr << pad2 << ": " << expected << "\n\t";
@ -100,7 +100,7 @@ QString QTest_generateCompareFailureMessage (
QString pad2 = QString("): ").rightJustified(pad2_, ' '); QString pad2 = QString("): ").rightJustified(pad2_, ' ');
QString msg; QString msg;
QTextStream stream (&msg); QTextStream stream(&msg);
stream << failMessage << "\n\t" stream << failMessage << "\n\t"
"Actual: (" << actual_expr << pad1 << actual << "\n\t" "Actual: (" << actual_expr << pad1 << actual << "\n\t"
"Expected: (" << expected_expr << pad2 << expected; "Expected: (" << expected_expr << pad2 << expected;
@ -134,10 +134,10 @@ void QTest_failWithCustomMessage (
// QFAIL_WITH_MESSAGE("Message " << thing << ";"); // QFAIL_WITH_MESSAGE("Message " << thing << ";");
// } // }
// //
#define QFAIL_WITH_MESSAGE(...) \ #define QFAIL_WITH_MESSAGE(...) \
do { \ do { \
QTest_failWithCustomMessage([&](QTextStream& stream) { stream << __VA_ARGS__; }, __LINE__, __FILE__); \ QTest_failWithCustomMessage([&](QTextStream& stream) { stream << __VA_ARGS__; }, __LINE__, __FILE__); \
return; \ return; \
} while(0) } while(0)
// Calls qFail using QTest_generateCompareFailureMessage. // Calls qFail using QTest_generateCompareFailureMessage.
@ -181,7 +181,7 @@ bool QTest_compareWithAbsError(
actual, expected, actual_expr, expected_expr, line, file, actual, expected, actual_expr, expected_expr, line, file,
[&] (QTextStream& stream) -> QTextStream& { [&] (QTextStream& stream) -> QTextStream& {
return stream << "Err tolerance: " << getErrorDifference((actual), (expected)) << " > " << epsilon; return stream << "Err tolerance: " << getErrorDifference((actual), (expected)) << " > " << epsilon;
}); });
return false; return false;
} }
return true; return true;
@ -200,10 +200,10 @@ bool QTest_compareWithAbsError(
// return stream << "glm::vec3 { " << v.x << ", " << v.y << ", " << v.z << " }" // return stream << "glm::vec3 { " << v.x << ", " << v.y << ", " << v.z << " }"
// } // }
// //
#define QCOMPARE_WITH_ABS_ERROR(actual, expected, epsilon) \ #define QCOMPARE_WITH_ABS_ERROR(actual, expected, epsilon) \
do { \ do { \
if (!QTest_compareWithAbsError((actual), (expected), #actual, #expected, __LINE__, __FILE__, epsilon)) \ if (!QTest_compareWithAbsError((actual), (expected), #actual, #expected, __LINE__, __FILE__, epsilon)) \
return; \ return; \
} while(0) } while(0)
// Implements QCOMPARE using an explicit, externally defined test function. // Implements QCOMPARE using an explicit, externally defined test function.
@ -212,12 +212,12 @@ do { \
// //
// testFunc(const T & actual, const T & expected) -> bool: true (test succeeds) | false (test fails) // testFunc(const T & actual, const T & expected) -> bool: true (test succeeds) | false (test fails)
// //
#define QCOMPARE_WITH_FUNCTION(actual, expected, testFunc) \ #define QCOMPARE_WITH_FUNCTION(actual, expected, testFunc) \
do { \ do { \
if (!(testFunc((actual), (expected)))) { \ if (!(testFunc((actual), (expected)))) { \
QTest_failWithMessage("Compared values are not the same", (actual), (expected), #actual, #expected, __LINE__, __FILE__); \ QTest_failWithMessage("Compared values are not the same", (actual), (expected), #actual, #expected, __LINE__, __FILE__); \
return; \ return; \
} \ } \
} while (0) } while (0)
// Implements QCOMPARE using an explicit, externally defined test function. // Implements QCOMPARE using an explicit, externally defined test function.
@ -230,41 +230,40 @@ do { \
// }); // });
// (fails if foo is not as fooish as expectedFoo) // (fails if foo is not as fooish as expectedFoo)
// //
#define QCOMPARE_WITH_LAMBDA(actual, expected, testClosure) \ #define QCOMPARE_WITH_LAMBDA(actual, expected, testClosure) \
do { \ do { \
if (!(testClosure())) { \ if (!(testClosure())) { \
QTest_failWithMessage("Compared values are not the same", (actual), (expected), #actual, #expected, __LINE__, __FILE__); \ QTest_failWithMessage("Compared values are not the same", (actual), (expected), #actual, #expected, __LINE__, __FILE__); \
return; \ return; \
} \ } \
} while (0) } while (0)
// Same as QCOMPARE_WITH_FUNCTION, but with a custom fail message // Same as QCOMPARE_WITH_FUNCTION, but with a custom fail message
#define QCOMPARE_WITH_FUNCTION_AND_MESSAGE(actual, expected, testfunc, failMessage) \ #define QCOMPARE_WITH_FUNCTION_AND_MESSAGE(actual, expected, testfunc, failMessage) \
do { \ do { \
if (!(testFunc((actual), (expected)))) { \ if (!(testFunc((actual), (expected)))) { \
QTest_failWithMessage((failMessage), (actual), (expected), #actual, #expected, __LINE__, __FILE__); \ QTest_failWithMessage((failMessage), (actual), (expected), #actual, #expected, __LINE__, __FILE__); \
return; \ return; \
} \ } \
} while (0) } while (0)
// Same as QCOMPARE_WITH_FUNCTION, but with a custom fail message // Same as QCOMPARE_WITH_FUNCTION, but with a custom fail message
#define QCOMPARE_WITH_LAMBDA_AND_MESSAGE(actual, expected, testClosure, failMessage) \ #define QCOMPARE_WITH_LAMBDA_AND_MESSAGE(actual, expected, testClosure, failMessage) \
do { \ do { \
if (!(testClosure())) { \ if (!(testClosure())) { \
QTest_failWithMessage((failMessage), (actual), (expected), #actual, #expected, __LINE__, __FILE__); \ QTest_failWithMessage((failMessage), (actual), (expected), #actual, #expected, __LINE__, __FILE__); \
return; \ return; \
} \ } \
} while (0) } while (0)
#endif #endif
#define QCOMPARE_WITH_EXPR(actual, expected, testExpr) \ #define QCOMPARE_WITH_EXPR(actual, expected, testExpr) \
do { \ do { \
if (!(testExpr)) { \ if (!(testExpr)) { \
QTest_failWithMessage("Compared values are not the same", (actual), (expected), #actual, #expected, __LINE__, __FILE__); \ QTest_failWithMessage("Compared values are not the same", (actual), (expected), #actual, #expected, __LINE__, __FILE__); \
} \ } \
} while(0) } while (0)
struct ByteData { struct ByteData {
ByteData (const char* data, size_t length) ByteData (const char* data, size_t length)
@ -273,25 +272,24 @@ struct ByteData {
size_t length; size_t length;
}; };
QTextStream & operator << (QTextStream& stream, const ByteData & wrapper) { QTextStream& operator<<(QTextStream& stream, const ByteData& wrapper) {
// Print bytes as hex // Print bytes as hex
stream << QByteArray::fromRawData(wrapper.data, (int)wrapper.length).toHex(); stream << QByteArray::fromRawData(wrapper.data, (int)wrapper.length).toHex();
return stream; return stream;
} }
bool compareData (const char* data, const char* expectedData, size_t length) { bool compareData(const char* data, const char* expectedData, size_t length) {
return memcmp(data, expectedData, length) == 0; return memcmp(data, expectedData, length) == 0;
} }
#define COMPARE_DATA(actual, expected, length) \ #define COMPARE_DATA(actual, expected, length) \
QCOMPARE_WITH_EXPR((ByteData ( actual, length )), (ByteData ( expected, length )), compareData(actual, expected, length)) QCOMPARE_WITH_EXPR((ByteData(actual, length)), (ByteData(expected, length)), compareData(actual, expected, length))
// Produces a relative error test for float usable QCOMPARE_WITH_LAMBDA. // Produces a relative error test for float usable QCOMPARE_WITH_LAMBDA.
inline auto errorTest (float actual, float expected, float acceptableRelativeError) inline auto errorTest (float actual, float expected, float acceptableRelativeError)
-> std::function<bool ()> { -> std::function<bool ()> {
return [actual, expected, acceptableRelativeError] () { return [actual, expected, acceptableRelativeError]() {
if (fabsf(expected) <= acceptableRelativeError) { if (fabsf(expected) <= acceptableRelativeError) {
return fabsf(actual - expected) < fabsf(acceptableRelativeError); return fabsf(actual - expected) < fabsf(acceptableRelativeError);
} }
@ -302,12 +300,10 @@ inline auto errorTest (float actual, float expected, float acceptableRelativeErr
#define QCOMPARE_WITH_RELATIVE_ERROR(actual, expected, relativeError) \ #define QCOMPARE_WITH_RELATIVE_ERROR(actual, expected, relativeError) \
QCOMPARE_WITH_LAMBDA(actual, expected, errorTest(actual, expected, relativeError)) QCOMPARE_WITH_LAMBDA(actual, expected, errorTest(actual, expected, relativeError))
inline QString getTestResource(const QString& relativePath) { inline QString getTestResource(const QString& relativePath) {
static QDir dir; static QDir dir;
static std::once_flag once; static std::once_flag once;
std::call_once(once, []{ std::call_once(once, [] {
QFileInfo fileInfo(__FILE__); QFileInfo fileInfo(__FILE__);
auto parentDir = fileInfo.absoluteDir(); auto parentDir = fileInfo.absoluteDir();
auto rootDir = parentDir.absoluteFilePath(".."); auto rootDir = parentDir.absoluteFilePath("..");

View file

@ -24,7 +24,7 @@
QTEST_MAIN(AnimTests) QTEST_MAIN(AnimTests)
const float EPSILON = 0.001f; const float TEST_EPSILON = 0.001f;
void AnimTests::initTestCase() { void AnimTests::initTestCase() {
DependencyManager::registerInheritance<LimitedNodeList, NodeList>(); DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
@ -86,12 +86,12 @@ void AnimTests::testClipEvaulate() {
AnimNode::Triggers triggers; AnimNode::Triggers triggers;
clip.evaluate(vars, context, framesToSec(10.0f), triggers); clip.evaluate(vars, context, framesToSec(10.0f), triggers);
QCOMPARE_WITH_ABS_ERROR(clip._frame, 12.0f, EPSILON); QCOMPARE_WITH_ABS_ERROR(clip._frame, 12.0f, TEST_EPSILON);
// does it loop? // does it loop?
triggers.clear(); triggers.clear();
clip.evaluate(vars, context, framesToSec(12.0f), triggers); clip.evaluate(vars, context, framesToSec(12.0f), triggers);
QCOMPARE_WITH_ABS_ERROR(clip._frame, 3.0f, EPSILON); // Note: frame 3 and not 4, because extra frame between start and end. QCOMPARE_WITH_ABS_ERROR(clip._frame, 3.0f, TEST_EPSILON); // Note: frame 3 and not 4, because extra frame between start and end.
// did we receive a loop trigger? // did we receive a loop trigger?
QVERIFY(std::find(triggers.begin(), triggers.end(), "myClipNodeOnLoop") != triggers.end()); QVERIFY(std::find(triggers.begin(), triggers.end(), "myClipNodeOnLoop") != triggers.end());
@ -100,7 +100,7 @@ void AnimTests::testClipEvaulate() {
triggers.clear(); triggers.clear();
clip.setLoopFlagVar("FalseVar"); clip.setLoopFlagVar("FalseVar");
clip.evaluate(vars, context, framesToSec(20.0f), triggers); clip.evaluate(vars, context, framesToSec(20.0f), triggers);
QCOMPARE_WITH_ABS_ERROR(clip._frame, 22.0f, EPSILON); QCOMPARE_WITH_ABS_ERROR(clip._frame, 22.0f, TEST_EPSILON);
// did we receive a done trigger? // did we receive a done trigger?
QVERIFY(std::find(triggers.begin(), triggers.end(), "myClipNodeOnDone") != triggers.end()); QVERIFY(std::find(triggers.begin(), triggers.end(), "myClipNodeOnDone") != triggers.end());
@ -402,7 +402,7 @@ void AnimTests::testAnimPose() {
glm::vec3(10.0f, 5.0f, -7.5f) glm::vec3(10.0f, 5.0f, -7.5f)
}; };
const float EPSILON = 0.001f; const float TEST_EPSILON = 0.001f;
for (auto& scale : scaleVec) { for (auto& scale : scaleVec) {
for (auto& rot : rotVec) { for (auto& rot : rotVec) {
@ -417,7 +417,7 @@ void AnimTests::testAnimPose() {
AnimPose pose(scale, rot, trans); AnimPose pose(scale, rot, trans);
glm::mat4 poseMat = pose; glm::mat4 poseMat = pose;
QCOMPARE_WITH_ABS_ERROR(rawMat, poseMat, EPSILON); QCOMPARE_WITH_ABS_ERROR(rawMat, poseMat, TEST_EPSILON);
} }
} }
} }
@ -437,7 +437,7 @@ void AnimTests::testAnimPose() {
// now build a new matrix from those parts. // now build a new matrix from those parts.
glm::mat4 poseMat = pose; glm::mat4 poseMat = pose;
QCOMPARE_WITH_ABS_ERROR(rawMat, poseMat, EPSILON); QCOMPARE_WITH_ABS_ERROR(rawMat, poseMat, TEST_EPSILON);
} }
} }
} }

View file

@ -29,7 +29,7 @@ const quat rot90 = glm::angleAxis((float)M_PI / 2.0f, yAxis);
QTEST_MAIN(TransformTests) QTEST_MAIN(TransformTests)
const float EPSILON = 0.001f; const float TEST_EPSILON = 0.001f;
void TransformTests::getMatrix() { void TransformTests::getMatrix() {
@ -55,7 +55,7 @@ void TransformTests::getMatrix() {
mat4 result_b; mat4 result_b;
xform.getMatrix(result_b); xform.getMatrix(result_b);
QCOMPARE_WITH_ABS_ERROR(result_a, result_b, EPSILON); QCOMPARE_WITH_ABS_ERROR(result_a, result_b, TEST_EPSILON);
} }
void TransformTests::getInverseMatrix() { void TransformTests::getInverseMatrix() {
@ -92,7 +92,7 @@ void TransformTests::getInverseMatrix() {
auto yb = transformPoint(result_b, yAxis); auto yb = transformPoint(result_b, yAxis);
auto zb = transformPoint(result_b, zAxis); auto zb = transformPoint(result_b, zAxis);
QCOMPARE_WITH_ABS_ERROR(xa, xb, EPSILON); QCOMPARE_WITH_ABS_ERROR(xa, xb, TEST_EPSILON);
QCOMPARE_WITH_ABS_ERROR(ya, yb, EPSILON); QCOMPARE_WITH_ABS_ERROR(ya, yb, TEST_EPSILON);
QCOMPARE_WITH_ABS_ERROR(za, zb, EPSILON); QCOMPARE_WITH_ABS_ERROR(za, zb, TEST_EPSILON);
} }