mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge pull request #12636 from samcake/workload
Workload: Applying the transaction model to the Space & Proxies
This commit is contained in:
commit
3a3bc62bd0
11 changed files with 621 additions and 60 deletions
|
@ -56,7 +56,7 @@ void GameSpaceToRender::run(const workload::WorkloadContextPointer& runContext,
|
|||
return;
|
||||
}
|
||||
|
||||
std::vector<workload::Space::Proxy> proxies(space->getNumAllocatedProxies());
|
||||
workload::Proxy::Vector proxies(space->getNumAllocatedProxies());
|
||||
space->copyProxyValues(proxies.data(), (uint32_t)proxies.size());
|
||||
|
||||
workload::Views views(space->getNumViews());
|
||||
|
@ -130,9 +130,9 @@ void GameWorkloadRenderItem::showViews(bool show) {
|
|||
}
|
||||
|
||||
|
||||
void GameWorkloadRenderItem::setAllProxies(const std::vector<workload::Space::Proxy>& proxies) {
|
||||
void GameWorkloadRenderItem::setAllProxies(const workload::Proxy::Vector& proxies) {
|
||||
_myOwnProxies = proxies;
|
||||
static const uint32_t sizeOfProxy = sizeof(workload::Space::Proxy);
|
||||
static const uint32_t sizeOfProxy = sizeof(workload::Proxy);
|
||||
if (!_allProxiesBuffer) {
|
||||
_allProxiesBuffer = std::make_shared<gpu::Buffer>(sizeOfProxy);
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ public:
|
|||
void showProxies(bool show);
|
||||
void showViews(bool show);
|
||||
|
||||
void setAllProxies(const std::vector<workload::Space::Proxy>& proxies);
|
||||
void setAllProxies(const workload::Proxy::Vector& proxies);
|
||||
void setAllViews(const workload::Views& views);
|
||||
|
||||
render::ItemKey getKey() const;
|
||||
|
@ -71,7 +71,7 @@ public:
|
|||
protected:
|
||||
render::Item::Bound _bound;
|
||||
|
||||
std::vector<workload::Space::Proxy> _myOwnProxies;
|
||||
workload::Proxy::Vector _myOwnProxies;
|
||||
gpu::BufferPointer _allProxiesBuffer;
|
||||
uint32_t _numAllProxies{ 0 };
|
||||
|
||||
|
|
|
@ -281,8 +281,11 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r
|
|||
}
|
||||
if (entity->getSpaceIndex() == -1) {
|
||||
std::unique_lock<std::mutex> lock(_spaceLock);
|
||||
workload::Space::Sphere sphere(entity->getWorldPosition(), entity->getBoundingRadius());
|
||||
int32_t spaceIndex = _space->createProxy(sphere);
|
||||
auto spaceIndex = _space->allocateID();
|
||||
workload::Sphere sphere(entity->getWorldPosition(), entity->getBoundingRadius());
|
||||
workload::Transaction transaction;
|
||||
transaction.reset(spaceIndex, sphere);
|
||||
_space->enqueueTransaction(transaction);
|
||||
entity->setSpaceIndex(spaceIndex);
|
||||
connect(entity.get(), &EntityItem::spaceUpdate, this, &EntityTreeRenderer::handleSpaceUpdate, Qt::QueuedConnection);
|
||||
}
|
||||
|
@ -427,17 +430,19 @@ void EntityTreeRenderer::update(bool simulate) {
|
|||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
}
|
||||
workload::Transaction spaceTransaction;
|
||||
{ // update proxies in the workload::Space
|
||||
std::unique_lock<std::mutex> lock(_spaceLock);
|
||||
_space->updateProxies(_spaceUpdates);
|
||||
spaceTransaction.update(_spaceUpdates);
|
||||
_spaceUpdates.clear();
|
||||
}
|
||||
{
|
||||
std::vector<int32_t> staleProxies;
|
||||
tree->swapStaleProxies(staleProxies);
|
||||
spaceTransaction.remove(staleProxies);
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_spaceLock);
|
||||
_space->deleteProxies(staleProxies);
|
||||
_space->enqueueTransaction(spaceTransaction);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -458,7 +463,7 @@ void EntityTreeRenderer::update(bool simulate) {
|
|||
|
||||
void EntityTreeRenderer::handleSpaceUpdate(std::pair<int32_t, glm::vec4> proxyUpdate) {
|
||||
std::unique_lock<std::mutex> lock(_spaceLock);
|
||||
_spaceUpdates.push_back(proxyUpdate);
|
||||
_spaceUpdates.emplace_back(proxyUpdate.first, proxyUpdate.second);
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar) {
|
||||
|
|
|
@ -270,7 +270,7 @@ private:
|
|||
|
||||
mutable std::mutex _spaceLock;
|
||||
workload::SpacePointer _space{ new workload::Space() };
|
||||
std::vector<workload::Space::ProxyUpdate> _spaceUpdates;
|
||||
workload::Transaction::Updates _spaceUpdates;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace workload {
|
|||
using JobModel = Task::ModelI<EngineBuilder, Inputs>;
|
||||
void build(JobModel& model, const Varying& in, Varying& out) {
|
||||
model.addJob<SetupViews>("setupViews", in);
|
||||
model.addJob<PerformSpaceTransaction>("updateSpace");
|
||||
const auto regionChanges = model.addJob<RegionTracker>("regionTracker");
|
||||
model.addJob<RegionState>("regionState", regionChanges);
|
||||
|
||||
|
@ -38,5 +39,15 @@ namespace workload {
|
|||
Engine::Engine(const WorkloadContextPointer& context) : Task("Engine", EngineBuilder::JobModel::create()),
|
||||
_context(context) {
|
||||
}
|
||||
|
||||
|
||||
void PerformSpaceTransaction::configure(const Config& config) {
|
||||
|
||||
}
|
||||
void PerformSpaceTransaction::run(const WorkloadContextPointer& context) {
|
||||
context->_space->enqueueFrame();
|
||||
context->_space->processTransactionQueue();
|
||||
}
|
||||
|
||||
} // namespace workload
|
||||
|
||||
|
|
|
@ -50,6 +50,24 @@ namespace workload {
|
|||
};
|
||||
using EnginePointer = std::shared_ptr<Engine>;
|
||||
|
||||
class PerformSpaceTransactionConfig : public Job::Config {
|
||||
Q_OBJECT
|
||||
public:
|
||||
signals :
|
||||
void dirty();
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
class PerformSpaceTransaction {
|
||||
public:
|
||||
using Config = PerformSpaceTransactionConfig;
|
||||
using JobModel = Job::Model<PerformSpaceTransaction, Config>;
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const WorkloadContextPointer& context);
|
||||
protected:
|
||||
};
|
||||
} // namespace workload
|
||||
|
||||
#endif // hifi_workload_Space_h
|
||||
|
|
35
libraries/workload/src/workload/Proxy.h
Normal file
35
libraries/workload/src/workload/Proxy.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// Proxy.h
|
||||
// libraries/workload/src/workload
|
||||
//
|
||||
// Created by Andrew Meadows 2018.01.30
|
||||
// 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_workload_Proxy_h
|
||||
#define hifi_workload_Proxy_h
|
||||
|
||||
#include "View.h"
|
||||
|
||||
namespace workload {
|
||||
|
||||
class Proxy {
|
||||
public:
|
||||
Proxy() : sphere(0.0f) {}
|
||||
Proxy(const Sphere& s) : sphere(s) {}
|
||||
|
||||
Sphere sphere;
|
||||
uint8_t region{ Region::INVALID };
|
||||
uint8_t prevRegion{ Region::INVALID };
|
||||
uint16_t _padding;
|
||||
uint32_t _paddings[3];
|
||||
|
||||
using Vector = std::vector<Proxy>;
|
||||
};
|
||||
|
||||
|
||||
} // namespace workload
|
||||
|
||||
#endif // hifi_workload_Proxy_h
|
|
@ -20,11 +20,80 @@
|
|||
|
||||
using namespace workload;
|
||||
|
||||
void Space::clear() {
|
||||
_proxies.clear();
|
||||
_freeIndices.clear();
|
||||
Space::Space() : Collection() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Space::processTransactionFrame(const Transaction& transaction) {
|
||||
std::unique_lock<std::mutex> lock(_proxiesMutex);
|
||||
// Here we should be able to check the value of last ProxyID allocated
|
||||
// and allocate new proxies accordingly
|
||||
ProxyID maxID = _IDAllocator.getNumAllocatedIndices();
|
||||
if (maxID > (Index) _proxies.size()) {
|
||||
_proxies.resize(maxID + 100); // allocate the maxId and more
|
||||
}
|
||||
// Now we know for sure that we have enough items in the array to
|
||||
// capture anything coming from the transaction
|
||||
|
||||
// resets and potential NEW items
|
||||
processResets(transaction._resetItems);
|
||||
|
||||
// Update the numItemsAtomic counter AFTER the reset changes went through
|
||||
// _numAllocatedItems.exchange(maxID);
|
||||
|
||||
// updates
|
||||
processUpdates(transaction._updatedItems);
|
||||
|
||||
// removes
|
||||
processRemoves(transaction._removedItems);
|
||||
|
||||
|
||||
// Update the numItemsAtomic counter AFTER the pending changes went through
|
||||
// _numAllocatedItems.exchange(maxID);
|
||||
}
|
||||
|
||||
void Space::processResets(const Transaction::Resets& transactions) {
|
||||
for (auto& reset : transactions) {
|
||||
// Access the true item
|
||||
auto ProxyID = std::get<0>(reset);
|
||||
auto& item = _proxies[ProxyID];
|
||||
|
||||
// Reset the item with a new payload
|
||||
item.sphere = (std::get<1>(reset));
|
||||
item.prevRegion = item.region = Region::UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
void Space::processRemoves(const Transaction::Removes& transactions) {
|
||||
for (auto removedID : transactions) {
|
||||
_IDAllocator.freeIndex(removedID);
|
||||
|
||||
// Access the true item
|
||||
auto& item = _proxies[removedID];
|
||||
|
||||
// Kill it
|
||||
item.prevRegion = item.region = Region::INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
void Space::processUpdates(const Transaction::Updates& transactions) {
|
||||
for (auto& update : transactions) {
|
||||
auto updateID = std::get<0>(update);
|
||||
if (updateID == INVALID_PROXY_ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Access the true item
|
||||
auto& item = _proxies[updateID];
|
||||
|
||||
// Update the item
|
||||
// item.update(std::get<1>(update));
|
||||
item.sphere = (std::get<1>(update));
|
||||
item.prevRegion = item.region = Region::UNKNOWN;
|
||||
}
|
||||
}
|
||||
/*
|
||||
int32_t Space::createProxy(const Space::Sphere& newSphere) {
|
||||
if (_freeIndices.empty()) {
|
||||
_proxies.emplace_back(Space::Proxy(newSphere));
|
||||
|
@ -37,32 +106,25 @@ int32_t Space::createProxy(const Space::Sphere& newSphere) {
|
|||
_proxies[index].prevRegion = Region::UNKNOWN;
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
}*/
|
||||
/*
|
||||
void Space::deleteProxies(const std::vector<int32_t>& deadIndices) {
|
||||
for (uint32_t i = 0; i < deadIndices.size(); ++i) {
|
||||
deleteProxy(deadIndices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Space::updateProxies(const std::vector<ProxyUpdate>& changedProxies) {
|
||||
*/
|
||||
/*void Space::updateProxies(const std::vector<ProxyUpdate>& changedProxies) {
|
||||
for (uint32_t i = 0; i < changedProxies.size(); ++i) {
|
||||
int32_t proxyId = changedProxies[i].first;
|
||||
if (proxyId > -1 && proxyId < (int32_t)_proxies.size()) {
|
||||
updateProxy(changedProxies[i].first, changedProxies[i].second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Space::setViews(const Views& views) {
|
||||
_views = views;
|
||||
}
|
||||
|
||||
void Space::copyViews(std::vector<View>& copy) const {
|
||||
copy = _views;
|
||||
}
|
||||
}*/
|
||||
|
||||
void Space::categorizeAndGetChanges(std::vector<Space::Change>& changes) {
|
||||
std::unique_lock<std::mutex> lock(_proxiesMutex);
|
||||
uint32_t numProxies = (uint32_t)_proxies.size();
|
||||
uint32_t numViews = (uint32_t)_views.size();
|
||||
for (uint32_t i = 0; i < numProxies; ++i) {
|
||||
|
@ -92,7 +154,7 @@ void Space::categorizeAndGetChanges(std::vector<Space::Change>& changes) {
|
|||
}
|
||||
|
||||
// private
|
||||
void Space::deleteProxy(int32_t proxyId) {
|
||||
/*void Space::deleteProxy(int32_t proxyId) {
|
||||
if (proxyId > -1 && proxyId < (int32_t)_proxies.size()) {
|
||||
if (proxyId == (int32_t)_proxies.size() - 1) {
|
||||
// remove proxy on back
|
||||
|
@ -110,9 +172,10 @@ void Space::deleteProxy(int32_t proxyId) {
|
|||
_freeIndices.push_back(proxyId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
uint32_t Space::copyProxyValues(Proxy* proxies, uint32_t numDestProxies) const {
|
||||
std::unique_lock<std::mutex> lock(_proxiesMutex);
|
||||
auto numCopied = std::min(numDestProxies, (uint32_t)_proxies.size());
|
||||
memcpy(proxies, _proxies.data(), numCopied * sizeof(Proxy));
|
||||
return numCopied;
|
||||
|
@ -120,9 +183,24 @@ uint32_t Space::copyProxyValues(Proxy* proxies, uint32_t numDestProxies) const {
|
|||
|
||||
|
||||
// private
|
||||
void Space::updateProxy(int32_t proxyId, const Space::Sphere& newSphere) {
|
||||
/*void Space::updateProxy(int32_t proxyId, const Space::Sphere& newSphere) {
|
||||
if (proxyId > -1 && proxyId < (int32_t)_proxies.size()) {
|
||||
_proxies[proxyId].sphere = newSphere;
|
||||
}
|
||||
}*/
|
||||
|
||||
void Space::clear() {
|
||||
std::unique_lock<std::mutex> lock(_proxiesMutex);
|
||||
_IDAllocator.clear();
|
||||
_proxies.clear();
|
||||
_views.clear();
|
||||
}
|
||||
|
||||
|
||||
void Space::setViews(const Views& views) {
|
||||
_views = views;
|
||||
}
|
||||
|
||||
void Space::copyViews(std::vector<View>& copy) const {
|
||||
copy = _views;
|
||||
}
|
||||
|
|
|
@ -19,29 +19,14 @@
|
|||
#include <vector>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "View.h"
|
||||
|
||||
#include "Transaction.h"
|
||||
|
||||
namespace workload {
|
||||
|
||||
using IndexVector = std::vector<int32_t>;
|
||||
|
||||
class Space {
|
||||
class Space : public Collection {
|
||||
public:
|
||||
using Sphere = glm::vec4; // <x,y,z> = center, w = radius
|
||||
using ProxyUpdate = std::pair<int32_t, Sphere>;
|
||||
|
||||
class Proxy {
|
||||
public:
|
||||
Proxy() : sphere(0.0f) {}
|
||||
Proxy(const Sphere& s) : sphere(s) {}
|
||||
Sphere sphere;
|
||||
uint8_t region { Region::UNKNOWN };
|
||||
uint8_t prevRegion { Region::UNKNOWN };
|
||||
uint16_t _padding;
|
||||
uint32_t _paddings[3];
|
||||
};
|
||||
|
||||
class Change {
|
||||
public:
|
||||
Change(int32_t i, uint32_t c, uint32_t p) : proxyId(i), region(c), prevRegion(p) {}
|
||||
|
@ -50,31 +35,40 @@ public:
|
|||
uint8_t prevRegion { 0 };
|
||||
};
|
||||
|
||||
Space() {}
|
||||
Space();
|
||||
|
||||
void clear();
|
||||
int32_t createProxy(const Sphere& sphere);
|
||||
void deleteProxies(const IndexVector& deadIndices);
|
||||
void updateProxies(const std::vector<ProxyUpdate>& changedProxies);
|
||||
void setViews(const std::vector<View>& views);
|
||||
void setViews(const Views& views);
|
||||
|
||||
uint32_t getNumViews() const { return (uint32_t)(_views.size()); }
|
||||
void copyViews(std::vector<View>& copy) const;
|
||||
|
||||
|
||||
uint32_t getNumObjects() const { return (uint32_t)(_proxies.size() - _freeIndices.size()); }
|
||||
uint32_t getNumAllocatedProxies() const { return (uint32_t)(_proxies.size()); }
|
||||
uint32_t getNumObjects() const { return _IDAllocator.getNumLiveIndices(); } // (uint32_t)(_proxies.size() - _freeIndices.size()); }
|
||||
uint32_t getNumAllocatedProxies() const { return (uint32_t)(_IDAllocator.getNumAllocatedIndices()); }
|
||||
|
||||
void categorizeAndGetChanges(std::vector<Change>& changes);
|
||||
uint32_t copyProxyValues(Proxy* proxies, uint32_t numDestProxies) const;
|
||||
|
||||
void clear();
|
||||
private:
|
||||
void deleteProxy(int32_t proxyId);
|
||||
void updateProxy(int32_t proxyId, const Sphere& sphere);
|
||||
|
||||
std::vector<Proxy> _proxies;
|
||||
void processTransactionFrame(const Transaction& transaction) override;
|
||||
void processResets(const Transaction::Resets& transactions);
|
||||
void processRemoves(const Transaction::Removes& transactions);
|
||||
void processUpdates(const Transaction::Updates& transactions);
|
||||
|
||||
// int32_t createProxy(const Sphere& sphere);
|
||||
// void deleteProxies(const IndexVector& deadIndices);
|
||||
// void updateProxies(const std::vector<ProxyUpdate>& changedProxies);
|
||||
|
||||
// void deleteProxy(int32_t proxyId);
|
||||
// void updateProxy(int32_t proxyId, const Sphere& sphere);
|
||||
|
||||
|
||||
// The database of proxies is protected for editing by a mutex
|
||||
mutable std::mutex _proxiesMutex;
|
||||
Proxy::Vector _proxies;
|
||||
|
||||
Views _views;
|
||||
IndexVector _freeIndices;
|
||||
};
|
||||
|
||||
using SpacePointer = std::shared_ptr<Space>;
|
||||
|
|
237
libraries/workload/src/workload/Transaction.cpp
Normal file
237
libraries/workload/src/workload/Transaction.cpp
Normal file
|
@ -0,0 +1,237 @@
|
|||
//
|
||||
// Transaction.cpp
|
||||
// libraries/workload/src/workload
|
||||
//
|
||||
// Created by Sam Gateau 2018.03.12
|
||||
// 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 "Transaction.h"
|
||||
|
||||
using namespace workload;
|
||||
|
||||
|
||||
void Transaction::reset(ProxyID id, const ProxyPayload& payload) {
|
||||
_resetItems.emplace_back(Reset{ id, payload });
|
||||
}
|
||||
|
||||
void Transaction::remove(ProxyID id) {
|
||||
_removedItems.emplace_back(id);
|
||||
}
|
||||
|
||||
void Transaction::update(ProxyID id, const ProxyPayload& payload) {
|
||||
_updatedItems.emplace_back(id, payload);
|
||||
}
|
||||
|
||||
void Transaction::reserve(const std::vector<Transaction>& transactionContainer) {
|
||||
size_t resetItemsCount = 0;
|
||||
size_t removedItemsCount = 0;
|
||||
size_t updatedItemsCount = 0;
|
||||
|
||||
for (const auto& transaction : transactionContainer) {
|
||||
resetItemsCount += transaction._resetItems.size();
|
||||
removedItemsCount += transaction._removedItems.size();
|
||||
updatedItemsCount += transaction._updatedItems.size();
|
||||
}
|
||||
|
||||
_resetItems.reserve(resetItemsCount);
|
||||
_removedItems.reserve(removedItemsCount);
|
||||
_updatedItems.reserve(updatedItemsCount);
|
||||
}
|
||||
|
||||
void Transaction::merge(const std::vector<Transaction>& transactionContainer) {
|
||||
reserve(transactionContainer);
|
||||
for (const auto& transaction : transactionContainer) {
|
||||
merge(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Transaction::merge(std::vector<Transaction>&& transactionContainer) {
|
||||
reserve(transactionContainer);
|
||||
auto begin = std::make_move_iterator(transactionContainer.begin());
|
||||
auto end = std::make_move_iterator(transactionContainer.end());
|
||||
for (auto itr = begin; itr != end; ++itr) {
|
||||
merge(*itr);
|
||||
}
|
||||
transactionContainer.clear();
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void moveElements(T& target, T& source) {
|
||||
target.insert(target.end(), std::make_move_iterator(source.begin()), std::make_move_iterator(source.end()));
|
||||
source.clear();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void copyElements(T& target, const T& source) {
|
||||
target.insert(target.end(), source.begin(), source.end());
|
||||
}
|
||||
|
||||
|
||||
void Transaction::reset(const Resets& resets) {
|
||||
copyElements(_resetItems, resets);
|
||||
}
|
||||
|
||||
void Transaction::remove(const Removes& removes) {
|
||||
copyElements(_removedItems, removes);
|
||||
}
|
||||
|
||||
void Transaction::update(const Updates& updates) {
|
||||
copyElements(_updatedItems, updates);
|
||||
}
|
||||
|
||||
void Transaction::merge(Transaction&& transaction) {
|
||||
moveElements(_resetItems, transaction._resetItems);
|
||||
moveElements(_removedItems, transaction._removedItems);
|
||||
moveElements(_updatedItems, transaction._updatedItems);
|
||||
}
|
||||
|
||||
void Transaction::merge(const Transaction& transaction) {
|
||||
copyElements(_resetItems, transaction._resetItems);
|
||||
copyElements(_removedItems, transaction._removedItems);
|
||||
copyElements(_updatedItems, transaction._updatedItems);
|
||||
}
|
||||
|
||||
void Transaction::clear() {
|
||||
_resetItems.clear();
|
||||
_removedItems.clear();
|
||||
_updatedItems.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Collection::Collection() {
|
||||
//_items.push_back(Item()); // add the ProxyID #0 to nothing
|
||||
}
|
||||
|
||||
Collection::~Collection() {
|
||||
}
|
||||
|
||||
ProxyID Collection::allocateID() {
|
||||
// Just increment and return the previous value initialized at 0
|
||||
return _IDAllocator.allocateIndex();
|
||||
}
|
||||
|
||||
bool Collection::isAllocatedID(const ProxyID& id) const {
|
||||
return _IDAllocator.checkIndex(id);
|
||||
}
|
||||
|
||||
/// Enqueue change batch to the Collection
|
||||
void Collection::enqueueTransaction(const Transaction& transaction) {
|
||||
std::unique_lock<std::mutex> lock(_transactionQueueMutex);
|
||||
_transactionQueue.emplace_back(transaction);
|
||||
}
|
||||
|
||||
void Collection::enqueueTransaction(Transaction&& transaction) {
|
||||
std::unique_lock<std::mutex> lock(_transactionQueueMutex);
|
||||
_transactionQueue.emplace_back(std::move(transaction));
|
||||
}
|
||||
|
||||
uint32_t Collection::enqueueFrame() {
|
||||
TransactionQueue localTransactionQueue;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_transactionQueueMutex);
|
||||
localTransactionQueue.swap(_transactionQueue);
|
||||
}
|
||||
|
||||
Transaction consolidatedTransaction;
|
||||
consolidatedTransaction.merge(std::move(localTransactionQueue));
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_transactionFramesMutex);
|
||||
_transactionFrames.push_back(consolidatedTransaction);
|
||||
}
|
||||
|
||||
return ++_transactionFrameNumber;
|
||||
}
|
||||
|
||||
|
||||
void Collection::processTransactionQueue() {
|
||||
static TransactionFrames queuedFrames;
|
||||
{
|
||||
// capture the queued frames and clear the queue
|
||||
std::unique_lock<std::mutex> lock(_transactionFramesMutex);
|
||||
queuedFrames.swap(_transactionFrames);
|
||||
}
|
||||
|
||||
// go through the queue of frames and process them
|
||||
for (auto& frame : queuedFrames) {
|
||||
processTransactionFrame(frame);
|
||||
}
|
||||
|
||||
queuedFrames.clear();
|
||||
}
|
||||
|
||||
//void Collection::processTransactionFrame(const Transaction& transaction) {
|
||||
/**
|
||||
std::unique_lock<std::mutex> lock(_itemsMutex);
|
||||
// Here we should be able to check the value of last ProxyID allocated
|
||||
// and allocate new items accordingly
|
||||
ProxyID maxID = _IDAllocator.getNumAllocatedIndices();
|
||||
if (maxID > _items.size()) {
|
||||
_items.resize(maxID + 100); // allocate the maxId and more
|
||||
}
|
||||
// Now we know for sure that we have enough items in the array to
|
||||
// capture anything coming from the transaction
|
||||
|
||||
// resets and potential NEW items
|
||||
resetItems(transaction._resetItems);
|
||||
|
||||
// Update the numItemsAtomic counter AFTER the reset changes went through
|
||||
_numAllocatedItems.exchange(maxID);
|
||||
|
||||
// updates
|
||||
updateItems(transaction._updatedItems);
|
||||
|
||||
// removes
|
||||
removeItems(transaction._removedItems);
|
||||
|
||||
// add transitions
|
||||
transitionItems(transaction._addedTransitions);
|
||||
reApplyTransitions(transaction._reAppliedTransitions);
|
||||
queryTransitionItems(transaction._queriedTransitions);
|
||||
|
||||
// Update the numItemsAtomic counter AFTER the pending changes went through
|
||||
_numAllocatedItems.exchange(maxID);
|
||||
}*/
|
||||
//}
|
||||
|
||||
//void Collection::resetItems(const Transaction::Resets& transactions) {
|
||||
/* for (auto& reset : transactions) {
|
||||
// Access the true item
|
||||
auto ProxyID = std::get<0>(reset);
|
||||
auto& item = _items[ProxyID];
|
||||
|
||||
// Reset the item with a new payload
|
||||
item.resetPayload(std::get<1>(reset));
|
||||
}*/
|
||||
//}
|
||||
|
||||
//void Collection::removeItems(const Transaction::Removes& transactions) {
|
||||
/* for (auto removedID : transactions) {
|
||||
// Access the true item
|
||||
auto& item = _items[removedID];
|
||||
|
||||
// Kill it
|
||||
item.kill();
|
||||
}*/
|
||||
//}
|
||||
|
||||
//void Collection::updateItems(const Transaction::Updates& transactions) {
|
||||
/* for (auto& update : transactions) {
|
||||
auto updateID = std::get<0>(update);
|
||||
if (updateID == Item::INVALID_ITEM_ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Access the true item
|
||||
auto& item = _items[updateID];
|
||||
|
||||
// Update the item
|
||||
item.update(std::get<1>(update));
|
||||
}*/
|
||||
//}
|
183
libraries/workload/src/workload/Transaction.h
Normal file
183
libraries/workload/src/workload/Transaction.h
Normal file
|
@ -0,0 +1,183 @@
|
|||
//
|
||||
// Transaction.h
|
||||
// libraries/workload/src/workload
|
||||
//
|
||||
// Created by Sam Gateau 2018.03.12
|
||||
// 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_workload_Transaction_h
|
||||
#define hifi_workload_Transaction_h
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "Proxy.h"
|
||||
|
||||
|
||||
namespace workload {
|
||||
|
||||
namespace indexed_container {
|
||||
|
||||
using Index = int32_t;
|
||||
const Index MAXIMUM_INDEX{ 1 << 30 };
|
||||
const Index INVALID_INDEX{ -1 };
|
||||
using Indices = std::vector< Index >;
|
||||
|
||||
template <Index MaxNumElements = MAXIMUM_INDEX>
|
||||
class Allocator {
|
||||
public:
|
||||
Allocator() {}
|
||||
Indices _freeIndices;
|
||||
Index _nextNewIndex{ 0 };
|
||||
|
||||
bool checkIndex(Index index) const { return ((index >= 0) && (index < _nextNewIndex)); }
|
||||
Index getNumLiveIndices() const { return _nextNewIndex - (Index)_freeIndices.size(); }
|
||||
Index getNumFreeIndices() const { return (Index)_freeIndices.size(); }
|
||||
Index getNumAllocatedIndices() const { return _nextNewIndex; }
|
||||
|
||||
Index allocateIndex() {
|
||||
if (_freeIndices.empty()) {
|
||||
Index index = _nextNewIndex;
|
||||
if (index >= MaxNumElements) {
|
||||
// abort! we are trying to go overboard with the total number of allocated elements
|
||||
assert(false);
|
||||
// This should never happen because Bricks are allocated along with the cells and there
|
||||
// is already a cap on the cells allocation
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
_nextNewIndex++;
|
||||
return index;
|
||||
} else {
|
||||
Index index = _freeIndices.back();
|
||||
_freeIndices.pop_back();
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
void freeIndex(Index index) {
|
||||
if (checkIndex(index)) {
|
||||
_freeIndices.push_back(index);
|
||||
//std::sort(_freeIndices.begin(), _freeIndices.end());
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_freeIndices.clear();
|
||||
_nextNewIndex = 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
using Index = indexed_container::Index;
|
||||
using IndexVector = indexed_container::Indices;
|
||||
|
||||
using ProxyID = Index;
|
||||
const ProxyID INVALID_PROXY_ID{ indexed_container ::INVALID_INDEX };
|
||||
|
||||
// Transaction is the mechanism to make any change to the Space.
|
||||
// Whenever a new proxy need to be reset,
|
||||
// or when an proxy changes its position or its size
|
||||
// or when an proxy is destroyed
|
||||
// These changes must be expressed through the corresponding command from the Transaction
|
||||
// The Transaction is then queued on the Space so all the pending transactions can be consolidated and processed at the time
|
||||
// of updating the space at the Frame boundary.
|
||||
//
|
||||
class Transaction {
|
||||
friend class Space;
|
||||
public:
|
||||
using ProxyPayload = Sphere;
|
||||
|
||||
using Reset = std::tuple<ProxyID, ProxyPayload>;
|
||||
using Remove = ProxyID;
|
||||
using Update = std::tuple<ProxyID, ProxyPayload>;
|
||||
|
||||
using Resets = std::vector<Reset>;
|
||||
using Removes = std::vector<Remove>;
|
||||
using Updates = std::vector<Update>;
|
||||
|
||||
Transaction() {}
|
||||
~Transaction() {}
|
||||
|
||||
// Proxy transactions
|
||||
void reset(ProxyID id, const ProxyPayload& sphere);
|
||||
void reset(const Resets& resets);
|
||||
void remove(ProxyID id);
|
||||
void remove(const Removes& removes);
|
||||
bool hasRemovals() const { return !_removedItems.empty(); }
|
||||
|
||||
void update(ProxyID id, const ProxyPayload& sphere);
|
||||
void update(const Updates& updates);
|
||||
|
||||
void reserve(const std::vector<Transaction>& transactionContainer);
|
||||
void merge(const std::vector<Transaction>& transactionContainer);
|
||||
void merge(std::vector<Transaction>&& transactionContainer);
|
||||
void merge(const Transaction& transaction);
|
||||
void merge(Transaction&& transaction);
|
||||
void clear();
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
Resets _resetItems;
|
||||
Removes _removedItems;
|
||||
Updates _updatedItems;
|
||||
};
|
||||
typedef std::vector<Transaction> TransactionQueue;
|
||||
|
||||
class Collection {
|
||||
public:
|
||||
Collection();
|
||||
~Collection();
|
||||
|
||||
// This call is thread safe, can be called from anywhere to allocate a new ID
|
||||
ProxyID allocateID();
|
||||
|
||||
// Check that the ID is valid and allocated for this space, this a threadsafe call
|
||||
bool isAllocatedID(const ProxyID& id) const;
|
||||
|
||||
// THis is the total number of allocated proxies, this a threadsafe call
|
||||
Index getNumAllocatedProxies() const { return _IDAllocator.getNumAllocatedIndices(); }
|
||||
|
||||
// Enqueue transaction to the space
|
||||
void enqueueTransaction(const Transaction& transaction);
|
||||
|
||||
// Enqueue transaction to the space
|
||||
void enqueueTransaction(Transaction&& transaction);
|
||||
|
||||
// Enqueue end of frame transactions boundary
|
||||
uint32_t enqueueFrame();
|
||||
|
||||
// Process the pending transactions queued
|
||||
virtual void processTransactionQueue();
|
||||
|
||||
protected:
|
||||
|
||||
// Thread safe elements that can be accessed from anywhere
|
||||
indexed_container::Allocator<> _IDAllocator;
|
||||
|
||||
//std::atomic<unsigned int> _IDAllocator{ 1 }; // first valid itemID will be One
|
||||
//std::atomic<unsigned int> _numAllocatedItems{ 1 }; // num of allocated items, matching the _items.size()
|
||||
std::mutex _transactionQueueMutex;
|
||||
TransactionQueue _transactionQueue;
|
||||
|
||||
|
||||
std::mutex _transactionFramesMutex;
|
||||
using TransactionFrames = std::vector<Transaction>;
|
||||
TransactionFrames _transactionFrames;
|
||||
uint32_t _transactionFrameNumber{ 0 };
|
||||
|
||||
// Process one transaction frame
|
||||
virtual void processTransactionFrame(const Transaction& transaction) = 0;
|
||||
};
|
||||
|
||||
} // namespace workload
|
||||
|
||||
#endif // hifi_workload_Transaction_h
|
Loading…
Reference in a new issue