Merge branch 'master' of https://github.com/highfidelity/hifi into one

This commit is contained in:
samcake 2018-05-21 15:52:42 -07:00
commit 2dc28a504c
26 changed files with 466 additions and 315 deletions

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 { static const std::vector<QString> nodeNamesToDelete {
// Node data that is packed into the draco mesh // Node data that is packed into the draco mesh
"Vertices", "Vertices",
"PolygonVertexIndex", "PolygonVertexIndex",
"LayerElementNormal", "LayerElementNormal",
"LayerElementColor", "LayerElementColor",
"LayerElementUV", "LayerElementUV",
"LayerElementMaterial", "LayerElementMaterial",
"LayerElementTexture", "LayerElementTexture",
// Node data that we don't support // Node data that we don't support
"Edges", "Edges",
"LayerElementTangent", "LayerElementTangent",
"LayerElementBinormal", "LayerElementBinormal",
"LayerElementSmoothing" "LayerElementSmoothing"
}; };
auto& children = objectChild.children; auto& children = objectChild.children;
auto it = children.begin(); auto it = children.begin();
while (it != children.end()) { while (it != children.end()) {
auto begin = nodeNamesToDelete.begin(); auto begin = nodeNamesToDelete.begin();
auto end = nodeNamesToDelete.end(); auto end = nodeNamesToDelete.end();
if (find(begin, end, it->name) != end) { if (find(begin, end, it->name) != end) {
it = children.erase(it); it = children.erase(it);
} else { } else {
++it; ++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,9 +52,10 @@ 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,
void manageMemory() override; void manageMemory() override;
void shutdown() override; void shutdown() override;
@ -92,11 +92,11 @@ protected:
private: private:
std::atomic<bool> _shutdown{ false }; std::atomic<bool> _shutdown{ false };
// Contains a priority sorted list of weak texture pointers that have been determined to be eligible for additional allocation // Contains a priority sorted list of weak texture pointers that have been determined to be eligible for additional allocation
// While the memory state is 'undersubscribed', items will be removed from this list and processed, allocating additional memory // While the memory state is 'undersubscribed', items will be removed from this list and processed, allocating additional memory
// per frame // per frame
WorkQueue _promoteQueue; WorkQueue _promoteQueue;
// This queue contains jobs that will buffer data from the texture backing store (ideally a memory mapped KTX file) // This queue contains jobs that will buffer data from the texture backing store (ideally a memory mapped KTX file)
// to a CPU memory buffer. This queue is populated on the main GPU thread, and drained on a dedicated thread. // to a CPU memory buffer. This queue is populated on the main GPU thread, and drained on a dedicated thread.
// When an item on the _activeBufferQueue is completed it is put into the _activeTransferQueue // When an item on the _activeBufferQueue is completed it is put into the _activeTransferQueue
ActiveTransferQueue _activeBufferQueue; ActiveTransferQueue _activeBufferQueue;
// This queue contains jobs that will upload data from a CPU buffer into a GPU. This queue is populated on the background // This queue contains jobs that will upload data from a CPU buffer into a GPU. This queue is populated on the background
@ -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,13 +161,12 @@ 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
resetFrameTextureCreated(); resetFrameTextureCreated();
// Determine the current memory management state. It will be either idle (no work to do), // Determine the current memory management state. It will be either idle (no work to do),
// undersubscribed (need to do more allocation) or transfer (need to upload content from the // undersubscribed (need to do more allocation) or transfer (need to upload content from the
// backing store to the GPU // backing store to the GPU
updateMemoryPressure(); updateMemoryPressure();
if (MemoryPressureState::Undersubscribed == _memoryPressureState) { if (MemoryPressureState::Undersubscribed == _memoryPressureState) {
@ -176,7 +178,7 @@ void GLTextureTransferEngineDefault::manageMemory() {
} }
} }
// Each frame we will check if our memory pressure state has changed. // Each frame we will check if our memory pressure state has changed.
void GLTextureTransferEngineDefault::updateMemoryPressure() { void GLTextureTransferEngineDefault::updateMemoryPressure() {
PROFILE_RANGE(render_gpu_gl, __FUNCTION__); PROFILE_RANGE(render_gpu_gl, __FUNCTION__);
@ -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,11 +271,10 @@ 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.
// //
// This will queue jobs until _queuedBufferSize can't be increased without exceeding // This will queue jobs until _queuedBufferSize can't be increased without exceeding
// GLVariableAllocationTexture::MAX_BUFFER_SIZE or there is no more work to be done // GLVariableAllocationTexture::MAX_BUFFER_SIZE or there is no more work to be done
populateActiveBufferQueue(); populateActiveBufferQueue();
@ -294,15 +294,19 @@ 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();
} }
} }
// If we have no more work in any of the structures, reset the memory state to idle to // If we have no more work in any of the structures, reset the memory state to idle to
// force reconstruction of the _pendingTransfersMap if necessary // force reconstruction of the _pendingTransfersMap if necessary
{ {
Lock lock(_bufferMutex); Lock lock(_bufferMutex);
@ -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();
@ -384,7 +388,7 @@ bool GLTextureTransferEngineDefault::processActiveBufferQueue() {
for (const auto& activeJob : activeBufferQueue) { for (const auto& activeJob : activeBufferQueue) {
const auto& texture = activeJob.first; const auto& texture = activeJob.first;
const auto& transferJob = activeJob.second; const auto& transferJob = activeJob.second;
// Some jobs don't require buffering, but they pass through this queue to ensure that we don't re-order // Some jobs don't require buffering, but they pass through this queue to ensure that we don't re-order
// the buffering & transfer operations. All jobs in the queue must be processed in order. // the buffering & transfer operations. All jobs in the queue must be processed in order.
if (!transferJob->bufferingRequired()) { if (!transferJob->bufferingRequired()) {
continue; continue;
@ -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) {
@ -487,7 +463,7 @@ void Batch::runLambda(std::function<void()> f) {
void Batch::startNamedCall(const std::string& name) { void Batch::startNamedCall(const std::string& name) {
ADD_COMMAND(startNamedCall); ADD_COMMAND(startNamedCall);
_params.emplace_back(_names.cache(name)); _params.emplace_back(_names.cache(name));
_currentNamedCall = name; _currentNamedCall = name;
} }
@ -556,7 +532,7 @@ void Batch::captureDrawCallInfoImpl() {
TransformObject object; TransformObject object;
_currentModel.getMatrix(object._model); _currentModel.getMatrix(object._model);
// FIXME - we don't want to be using glm::inverse() here but it fixes the flickering issue we are // FIXME - we don't want to be using glm::inverse() here but it fixes the flickering issue we are
// seeing with planky blocks in toybox. Our implementation of getInverseMatrix() is buggy in cases // seeing with planky blocks in toybox. Our implementation of getInverseMatrix() is buggy in cases
// of non-uniform scale. We need to fix that. In the mean time, glm::inverse() works. // of non-uniform scale. We need to fix that. In the mean time, glm::inverse() works.
//_model.getInverseMatrix(_object._modelInverse); //_model.getInverseMatrix(_object._modelInverse);
@ -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

@ -43,17 +43,16 @@ public:
int _DSNumTriangles = 0; int _DSNumTriangles = 0;
int _PSNumSetPipelines = 0; int _PSNumSetPipelines = 0;
ContextStats() {} ContextStats() {}
ContextStats(const ContextStats& stats) = default; ContextStats(const ContextStats& stats) = default;
void evalDelta(const ContextStats& begin, const ContextStats& end); void evalDelta(const ContextStats& begin, const ContextStats& end);
}; };
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,40 +157,43 @@ 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
void recycle() const; void recycle() const;
// MUST only be called on the rendering thread // MUST only be called on the rendering thread
// //
// Execute a batch immediately, rather than as part of a frame // Execute a batch immediately, rather than as part of a frame
void executeBatch(Batch& batch) const; void executeBatch(Batch& batch) const;
// MUST only be called on the rendering thread // MUST only be called on the rendering thread
// //
// Executes a frame, applying any updates contained in the frame batches to the rendering // Executes a frame, applying any updates contained in the frame batches to the rendering
// thread shadow copies. Either executeFrame or consumeFrameUpdates MUST be called on every frame // thread shadow copies. Either executeFrame or consumeFrameUpdates MUST be called on every frame
// generated, IN THE ORDER they were generated. // generated, IN THE ORDER they were generated.
void executeFrame(const FramePointer& frame) const; void executeFrame(const FramePointer& frame) const;
// MUST only be called on the rendering thread. // MUST only be called on the rendering thread.
// //
// Consuming a frame applies any updates queued from the recording thread and applies them to the // Consuming a frame applies any updates queued from the recording thread and applies them to the
// shadow copy used by the rendering thread. // shadow copy used by the rendering thread.
// //
// EVERY frame generated MUST be consumed, regardless of whether the frame is actually executed, // EVERY frame generated MUST be consumed, regardless of whether the frame is actually executed,
// or the buffer shadow copies can become unsynced from the recording thread copies. // or the buffer shadow copies can become unsynced from the recording thread copies.
// //
// Consuming a frame is idempotent, as the frame encapsulates the updates and clears them out as // Consuming a frame is idempotent, as the frame encapsulates the updates and clears them out as
// it applies them, so calling it more than once on a given frame will have no effect after the // it applies them, so calling it more than once on a given frame will have no effect after the
// first time // first time
// //
// //
// This is automatically called by executeFrame, so you only need to call it if you // This is automatically called by executeFrame, so you only need to call it if you
// have frames you aren't going to otherwise execute, for instance when a display plugin is // have frames you aren't going to otherwise execute, for instance when a display plugin is
// being disabled, or in the null display plugin where no rendering actually occurs // being disabled, or in the null display plugin where no rendering actually occurs
void consumeFrameUpdates(const FramePointer& frame) const; void consumeFrameUpdates(const FramePointer& frame) const;
@ -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;
@ -237,7 +236,7 @@ public:
static Size getTextureGPUMemSize(); static Size getTextureGPUMemSize();
static Size getTextureResidentGPUMemSize(); static Size getTextureResidentGPUMemSize();
static Size getTextureFramebufferGPUMemSize(); static Size getTextureFramebufferGPUMemSize();
static Size getTextureResourceGPUMemSize(); static Size getTextureResourceGPUMemSize();
static Size getTextureExternalGPUMemSize(); static Size getTextureExternalGPUMemSize();
static uint32_t getTexturePendingGPUTransferCount(); static uint32_t getTexturePendingGPUTransferCount();
@ -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;
@ -261,7 +262,7 @@ protected:
// This function can only be called by "static Shader::makeProgram()" // This function can only be called by "static Shader::makeProgram()"
// makeProgramShader(...) make a program shader ready to be used in a Batch. // makeProgramShader(...) make a program shader ready to be used in a Batch.
// It compiles the sub shaders, link them and defines the Slots and their bindings. // It compiles the sub shaders, link them and defines the Slots and their bindings.
// If the shader passed is not a program, nothing happens. // If the shader passed is not a program, nothing happens.
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler); static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler);
static CreateBackend _createBackendCallback; static CreateBackend _createBackendCallback;
@ -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;
gpu::doInBatch(nullptr, args->_context, [&](gpu::Batch& batch) {
batch.enableStereo(false);
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) {
// bind the one gpu::Pipeline we need
batch.setPipeline(getDrawClusterContentPipeline());
batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, deferredTransform->getFrameTransformBuffer());
if (linearDepthTarget) {
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.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, nullptr);
batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr); batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr);
} }
});
if (doDrawContent) {
// bind the one gpu::Pipeline we need
batch.setPipeline(getDrawClusterContentPipeline());
batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, deferredTransform->getFrameTransformBuffer());
if (linearDepthTarget) { gpu::doInBatch(nullptr, args->_context, [&](gpu::Batch& batch) {
batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, linearDepthTarget->getLinearDepthTexture()); 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);
batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, nullptr); drawGridAndCleanBatch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, nullptr);
batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_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);
gpu::Batch drawGridAndCleanBatch; drawGridAndCleanBatch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, nullptr);
drawGridAndCleanBatch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, nullptr);
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);
} }