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

This commit is contained in:
samcake 2017-06-02 14:35:05 -07:00
commit 0a3c1712eb
21 changed files with 205 additions and 101 deletions

View file

@ -2413,15 +2413,16 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
// Check HMD use (may be technically available without being in use) // Check HMD use (may be technically available without being in use)
bool hasHMD = PluginUtils::isHMDAvailable(); bool hasHMD = PluginUtils::isHMDAvailable();
bool isUsingHMD = hasHMD && hasHandControllers && _displayPlugin->isHmd(); bool isUsingHMD = _displayPlugin->isHmd();
bool isUsingHMDAndHandControllers = hasHMD && hasHandControllers && isUsingHMD;
Setting::Handle<bool> tutorialComplete{ "tutorialComplete", false }; Setting::Handle<bool> tutorialComplete{ "tutorialComplete", false };
Setting::Handle<bool> firstRun{ Settings::firstRun, true }; Setting::Handle<bool> firstRun{ Settings::firstRun, true };
bool isTutorialComplete = tutorialComplete.get(); bool isTutorialComplete = tutorialComplete.get();
bool shouldGoToTutorial = isUsingHMD && hasTutorialContent && !isTutorialComplete; bool shouldGoToTutorial = isUsingHMDAndHandControllers && hasTutorialContent && !isTutorialComplete;
qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers << ", Using HMD: " << isUsingHMD; qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers << ", Using HMD: " << isUsingHMDAndHandControllers;
qCDebug(interfaceapp) << "Tutorial version:" << contentVersion << ", sufficient:" << hasTutorialContent << qCDebug(interfaceapp) << "Tutorial version:" << contentVersion << ", sufficient:" << hasTutorialContent <<
", complete:" << isTutorialComplete << ", should go:" << shouldGoToTutorial; ", complete:" << isTutorialComplete << ", should go:" << shouldGoToTutorial;
@ -2435,10 +2436,18 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
const QString TUTORIAL_PATH = "/tutorial_begin"; const QString TUTORIAL_PATH = "/tutorial_begin";
static const QString SENT_TO_TUTORIAL = "tutorial";
static const QString SENT_TO_PREVIOUS_LOCATION = "previous_location";
static const QString SENT_TO_ENTRY = "entry";
static const QString SENT_TO_SANDBOX = "sandbox";
QString sentTo;
if (shouldGoToTutorial) { if (shouldGoToTutorial) {
if (sandboxIsRunning) { if (sandboxIsRunning) {
qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home."; qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home.";
DependencyManager::get<AddressManager>()->goToLocalSandbox(TUTORIAL_PATH); DependencyManager::get<AddressManager>()->goToLocalSandbox(TUTORIAL_PATH);
sentTo = SENT_TO_TUTORIAL;
} else { } else {
qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry."; qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry.";
if (firstRun.get()) { if (firstRun.get()) {
@ -2446,8 +2455,10 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
} }
if (addressLookupString.isEmpty()) { if (addressLookupString.isEmpty()) {
DependencyManager::get<AddressManager>()->goToEntry(); DependencyManager::get<AddressManager>()->goToEntry();
sentTo = SENT_TO_ENTRY;
} else { } else {
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString); DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
sentTo = SENT_TO_PREVIOUS_LOCATION;
} }
} }
} else { } else {
@ -2460,23 +2471,40 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
// If this is a first run we short-circuit the address passed in // If this is a first run we short-circuit the address passed in
if (isFirstRun) { if (isFirstRun) {
if (isUsingHMD) { if (isUsingHMDAndHandControllers) {
if (sandboxIsRunning) { if (sandboxIsRunning) {
qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home."; qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home.";
DependencyManager::get<AddressManager>()->goToLocalSandbox(); DependencyManager::get<AddressManager>()->goToLocalSandbox();
sentTo = SENT_TO_SANDBOX;
} else { } else {
qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry."; qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry.";
DependencyManager::get<AddressManager>()->goToEntry(); DependencyManager::get<AddressManager>()->goToEntry();
sentTo = SENT_TO_ENTRY;
} }
} else { } else {
DependencyManager::get<AddressManager>()->goToEntry(); DependencyManager::get<AddressManager>()->goToEntry();
sentTo = SENT_TO_ENTRY;
} }
} else { } else {
qCDebug(interfaceapp) << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString); qCDebug(interfaceapp) << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString);
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString); DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
sentTo = SENT_TO_PREVIOUS_LOCATION;
} }
} }
UserActivityLogger::getInstance().logAction("startup_sent_to", {
{ "sent_to", sentTo },
{ "sandbox_is_running", sandboxIsRunning },
{ "has_hmd", hasHMD },
{ "has_hand_controllers", hasHandControllers },
{ "is_using_hmd", isUsingHMD },
{ "is_using_hmd_and_hand_controllers", isUsingHMDAndHandControllers },
{ "content_version", contentVersion },
{ "is_tutorial_complete", isTutorialComplete },
{ "has_tutorial_content", hasTutorialContent },
{ "should_go_to_tutorial", shouldGoToTutorial }
});
_connectionMonitor.init(); _connectionMonitor.init();
// After all of the constructor is completed, then set firstRun to false. // After all of the constructor is completed, then set firstRun to false.

View file

@ -407,6 +407,12 @@ Menu::Menu() {
#endif #endif
{
auto action = addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::RenderClearKtxCache);
connect(action, &QAction::triggered, []{
Setting::Handle<int>(KTXCache::SETTING_VERSION_NAME, KTXCache::INVALID_VERSION).set(KTXCache::INVALID_VERSION);
});
}
// Developer > Render > LOD Tools // Developer > Render > LOD Tools
addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, 0, addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, 0,

View file

@ -145,6 +145,7 @@ namespace MenuOption {
const QString Quit = "Quit"; const QString Quit = "Quit";
const QString ReloadAllScripts = "Reload All Scripts"; const QString ReloadAllScripts = "Reload All Scripts";
const QString ReloadContent = "Reload Content (Clears all caches)"; const QString ReloadContent = "Reload Content (Clears all caches)";
const QString RenderClearKtxCache = "Clear KTX Cache (requires restart)";
const QString RenderMaxTextureMemory = "Maximum Texture Memory"; const QString RenderMaxTextureMemory = "Maximum Texture Memory";
const QString RenderMaxTextureAutomatic = "Automatic Texture Memory"; const QString RenderMaxTextureAutomatic = "Automatic Texture Memory";
const QString RenderMaxTexture4MB = "4 MB"; const QString RenderMaxTexture4MB = "4 MB";

View file

@ -681,7 +681,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
// and pretend that we own it (we assume we'll recover it soon) // and pretend that we own it (we assume we'll recover it soon)
// However, for now, when the server uses a newer time than what we sent, listen to what we're told. // However, for now, when the server uses a newer time than what we sent, listen to what we're told.
if (overwriteLocalData) weOwnSimulation = false; if (overwriteLocalData) {
weOwnSimulation = false;
}
} else if (_simulationOwner.set(newSimOwner)) { } else if (_simulationOwner.set(newSimOwner)) {
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID); markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
somethingChanged = true; somethingChanged = true;
@ -1293,27 +1295,15 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c
properties._accelerationChanged = true; properties._accelerationChanged = true;
} }
void EntityItem::pokeSimulationOwnership() { void EntityItem::flagForOwnershipBid(uint8_t priority) {
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_POKE); markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY);
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
if (_simulationOwner.matchesValidID(nodeList->getSessionUUID())) { if (_simulationOwner.matchesValidID(nodeList->getSessionUUID())) {
// we already own it // we already own it
_simulationOwner.promotePriority(SCRIPT_POKE_SIMULATION_PRIORITY); _simulationOwner.promotePriority(priority);
} else { } else {
// we don't own it yet // we don't own it yet
_simulationOwner.setPendingPriority(SCRIPT_POKE_SIMULATION_PRIORITY, usecTimestampNow()); _simulationOwner.setPendingPriority(priority, usecTimestampNow());
}
}
void EntityItem::grabSimulationOwnership() {
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB);
auto nodeList = DependencyManager::get<NodeList>();
if (_simulationOwner.matchesValidID(nodeList->getSessionUUID())) {
// we already own it
_simulationOwner.promotePriority(SCRIPT_GRAB_SIMULATION_PRIORITY);
} else {
// we don't own it yet
_simulationOwner.setPendingPriority(SCRIPT_GRAB_SIMULATION_PRIORITY, usecTimestampNow());
} }
} }

View file

@ -321,6 +321,7 @@ public:
void updateSimulationOwner(const SimulationOwner& owner); void updateSimulationOwner(const SimulationOwner& owner);
void clearSimulationOwnership(); void clearSimulationOwnership();
void setPendingOwnershipPriority(quint8 priority, const quint64& timestamp); void setPendingOwnershipPriority(quint8 priority, const quint64& timestamp);
uint8_t getPendingOwnershipPriority() const { return _simulationOwner.getPendingPriority(); }
void rememberHasSimulationOwnershipBid() const; void rememberHasSimulationOwnershipBid() const;
QString getMarketplaceID() const; QString getMarketplaceID() const;
@ -394,8 +395,7 @@ public:
void getAllTerseUpdateProperties(EntityItemProperties& properties) const; void getAllTerseUpdateProperties(EntityItemProperties& properties) const;
void pokeSimulationOwnership(); void flagForOwnershipBid(uint8_t priority);
void grabSimulationOwnership();
void flagForMotionStateChange() { _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } void flagForMotionStateChange() { _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; }
QString actionsToDebugString(); QString actionsToDebugString();

View file

@ -230,6 +230,8 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
} }
entity->setLastBroadcast(usecTimestampNow()); entity->setLastBroadcast(usecTimestampNow());
// since we're creating this object we will immediately volunteer to own its simulation
entity->flagForOwnershipBid(VOLUNTEER_SIMULATION_PRIORITY);
propertiesWithSimID.setLastEdited(entity->getLastEdited()); propertiesWithSimID.setLastEdited(entity->getLastEdited());
} else { } else {
qCDebug(entities) << "script failed to add new Entity to local Octree"; qCDebug(entities) << "script failed to add new Entity to local Octree";
@ -440,7 +442,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
} else { } else {
// we make a bid for simulation ownership // we make a bid for simulation ownership
properties.setSimulationOwner(myNodeID, SCRIPT_POKE_SIMULATION_PRIORITY); properties.setSimulationOwner(myNodeID, SCRIPT_POKE_SIMULATION_PRIORITY);
entity->pokeSimulationOwnership(); entity->flagForOwnershipBid(SCRIPT_POKE_SIMULATION_PRIORITY);
entity->rememberHasSimulationOwnershipBid(); entity->rememberHasSimulationOwnershipBid();
} }
} }
@ -1194,7 +1196,7 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString,
} }
action->setIsMine(true); action->setIsMine(true);
success = entity->addAction(simulation, action); success = entity->addAction(simulation, action);
entity->grabSimulationOwnership(); entity->flagForOwnershipBid(SCRIPT_GRAB_SIMULATION_PRIORITY);
return false; // Physics will cause a packet to be sent, so don't send from here. return false; // Physics will cause a packet to be sent, so don't send from here.
}); });
if (success) { if (success) {
@ -1210,7 +1212,7 @@ bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid&
return actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { return actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) {
bool success = entity->updateAction(simulation, actionID, arguments); bool success = entity->updateAction(simulation, actionID, arguments);
if (success) { if (success) {
entity->grabSimulationOwnership(); entity->flagForOwnershipBid(SCRIPT_GRAB_SIMULATION_PRIORITY);
} }
return success; return success;
}); });
@ -1224,7 +1226,7 @@ bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid&
success = entity->removeAction(simulation, actionID); success = entity->removeAction(simulation, actionID);
if (success) { if (success) {
// reduce from grab to poke // reduce from grab to poke
entity->pokeSimulationOwnership(); entity->flagForOwnershipBid(SCRIPT_POKE_SIMULATION_PRIORITY);
} }
return false; // Physics will cause a packet to be sent, so don't send from here. return false; // Physics will cause a packet to be sent, so don't send from here.
}); });

View file

@ -26,12 +26,10 @@ namespace Simulation {
const uint32_t DIRTY_MATERIAL = 0x00400; const uint32_t DIRTY_MATERIAL = 0x00400;
const uint32_t DIRTY_PHYSICS_ACTIVATION = 0x0800; // should activate object in physics engine const uint32_t DIRTY_PHYSICS_ACTIVATION = 0x0800; // should activate object in physics engine
const uint32_t DIRTY_SIMULATOR_ID = 0x1000; // the simulatorID has changed const uint32_t DIRTY_SIMULATOR_ID = 0x1000; // the simulatorID has changed
const uint32_t DIRTY_SIMULATION_OWNERSHIP_FOR_POKE = 0x2000; // bid for simulation ownership at "poke" const uint32_t DIRTY_SIMULATION_OWNERSHIP_PRIORITY = 0x2000; // our own bid priority has changed
const uint32_t DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB = 0x4000; // bid for simulation ownership at "grab"
const uint32_t DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION; const uint32_t DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION;
const uint32_t DIRTY_VELOCITIES = DIRTY_LINEAR_VELOCITY | DIRTY_ANGULAR_VELOCITY; const uint32_t DIRTY_VELOCITIES = DIRTY_LINEAR_VELOCITY | DIRTY_ANGULAR_VELOCITY;
const uint32_t DIRTY_SIMULATION_OWNERSHIP_PRIORITY = DIRTY_SIMULATION_OWNERSHIP_FOR_POKE | DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB;
}; };
#endif // hifi_SimulationFlags_h #endif // hifi_SimulationFlags_h

View file

@ -26,9 +26,9 @@ const int SimulationOwner::NUM_BYTES_ENCODED = NUM_BYTES_RFC4122_UUID + 1;
SimulationOwner::SimulationOwner() : SimulationOwner::SimulationOwner() :
_id(), _id(),
_expiry(0), _expiry(0),
_pendingTimestamp(0), _pendingBidTimestamp(0),
_priority(0), _priority(0),
_pendingPriority(0), _pendingBidPriority(0),
_pendingState(PENDING_STATE_NOTHING) _pendingState(PENDING_STATE_NOTHING)
{ {
} }
@ -36,9 +36,9 @@ SimulationOwner::SimulationOwner() :
SimulationOwner::SimulationOwner(const QUuid& id, quint8 priority) : SimulationOwner::SimulationOwner(const QUuid& id, quint8 priority) :
_id(id), _id(id),
_expiry(0), _expiry(0),
_pendingTimestamp(0), _pendingBidTimestamp(0),
_priority(priority), _priority(priority),
_pendingPriority(0) _pendingBidPriority(0)
{ {
} }
@ -61,9 +61,9 @@ bool SimulationOwner::fromByteArray(const QByteArray& data) {
void SimulationOwner::clear() { void SimulationOwner::clear() {
_id = QUuid(); _id = QUuid();
_expiry = 0; _expiry = 0;
_pendingTimestamp = 0; _pendingBidTimestamp = 0;
_priority = 0; _priority = 0;
_pendingPriority = 0; _pendingBidPriority = 0;
_pendingState = PENDING_STATE_NOTHING; _pendingState = PENDING_STATE_NOTHING;
} }
@ -102,9 +102,9 @@ bool SimulationOwner::set(const SimulationOwner& owner) {
} }
void SimulationOwner::setPendingPriority(quint8 priority, const quint64& timestamp) { void SimulationOwner::setPendingPriority(quint8 priority, const quint64& timestamp) {
_pendingPriority = priority; _pendingBidPriority = priority;
_pendingTimestamp = timestamp; _pendingBidTimestamp = timestamp;
_pendingState = (_pendingPriority == 0) ? PENDING_STATE_RELEASE : PENDING_STATE_TAKE; _pendingState = (_pendingBidPriority == 0) ? PENDING_STATE_RELEASE : PENDING_STATE_TAKE;
} }
void SimulationOwner::updateExpiry() { void SimulationOwner::updateExpiry() {
@ -113,11 +113,11 @@ void SimulationOwner::updateExpiry() {
} }
bool SimulationOwner::pendingRelease(const quint64& timestamp) { bool SimulationOwner::pendingRelease(const quint64& timestamp) {
return _pendingPriority == 0 && _pendingState == PENDING_STATE_RELEASE && _pendingTimestamp >= timestamp; return _pendingBidPriority == 0 && _pendingState == PENDING_STATE_RELEASE && _pendingBidTimestamp >= timestamp;
} }
bool SimulationOwner::pendingTake(const quint64& timestamp) { bool SimulationOwner::pendingTake(const quint64& timestamp) {
return _pendingPriority > 0 && _pendingState == PENDING_STATE_TAKE && _pendingTimestamp >= timestamp; return _pendingBidPriority > 0 && _pendingState == PENDING_STATE_TAKE && _pendingBidTimestamp >= timestamp;
} }
void SimulationOwner::clearCurrentOwner() { void SimulationOwner::clearCurrentOwner() {

View file

@ -66,6 +66,7 @@ public:
bool hasExpired() const { return usecTimestampNow() > _expiry; } bool hasExpired() const { return usecTimestampNow() > _expiry; }
uint8_t getPendingPriority() const { return _pendingBidPriority; }
bool pendingRelease(const quint64& timestamp); // return true if valid pending RELEASE bool pendingRelease(const quint64& timestamp); // return true if valid pending RELEASE
bool pendingTake(const quint64& timestamp); // return true if valid pending TAKE bool pendingTake(const quint64& timestamp); // return true if valid pending TAKE
void clearCurrentOwner(); void clearCurrentOwner();
@ -84,9 +85,9 @@ public:
private: private:
QUuid _id; // owner QUuid _id; // owner
quint64 _expiry; // time when ownership can transition at equal priority quint64 _expiry; // time when ownership can transition at equal priority
quint64 _pendingTimestamp; // time when pending update was set quint64 _pendingBidTimestamp; // time when pending bid was set
quint8 _priority; // priority of current owner quint8 _priority; // priority of current owner
quint8 _pendingPriority; // priority of pendingTake quint8 _pendingBidPriority; // priority at which we'd like to own it
quint8 _pendingState; // NOTHING, TAKE, or RELEASE quint8 _pendingState; // NOTHING, TAKE, or RELEASE
}; };

View file

@ -11,14 +11,28 @@
#include "KTXCache.h" #include "KTXCache.h"
#include <SettingHandle.h>
#include <ktx/KTX.h> #include <ktx/KTX.h>
using File = cache::File; using File = cache::File;
using FilePointer = cache::FilePointer; using FilePointer = cache::FilePointer;
// Whenever a change is made to the serialized format for the KTX cache that isn't backward compatible,
// this value should be incremented. This will force the KTX cache to be wiped
const int KTXCache::CURRENT_VERSION = 0x01;
const int KTXCache::INVALID_VERSION = 0x00;
const char* KTXCache::SETTING_VERSION_NAME = "hifi.ktx.cache_version";
KTXCache::KTXCache(const std::string& dir, const std::string& ext) : KTXCache::KTXCache(const std::string& dir, const std::string& ext) :
FileCache(dir, ext) { FileCache(dir, ext) {
initialize(); initialize();
Setting::Handle<int> cacheVersionHandle(SETTING_VERSION_NAME, INVALID_VERSION);
auto cacheVersion = cacheVersionHandle.get();
if (cacheVersion != CURRENT_VERSION) {
wipe();
cacheVersionHandle.set(CURRENT_VERSION);
}
} }
KTXFilePointer KTXCache::writeFile(const char* data, Metadata&& metadata) { KTXFilePointer KTXCache::writeFile(const char* data, Metadata&& metadata) {

View file

@ -27,6 +27,12 @@ class KTXCache : public cache::FileCache {
Q_OBJECT Q_OBJECT
public: public:
// Whenever a change is made to the serialized format for the KTX cache that isn't backward compatible,
// this value should be incremented. This will force the KTX cache to be wiped
static const int CURRENT_VERSION;
static const int INVALID_VERSION;
static const char* SETTING_VERSION_NAME;
KTXCache(const std::string& dir, const std::string& ext); KTXCache(const std::string& dir, const std::string& ext);
KTXFilePointer writeFile(const char* data, Metadata&& metadata); KTXFilePointer writeFile(const char* data, Metadata&& metadata);

View file

@ -236,6 +236,28 @@ namespace cache {
}; };
} }
void FileCache::eject(const FilePointer& file) {
file->_cache = nullptr;
const auto& length = file->getLength();
const auto& key = file->getKey();
{
Lock lock(_filesMutex);
if (0 != _files.erase(key)) {
_numTotalFiles -= 1;
_totalFilesSize -= length;
}
}
{
Lock unusedLock(_unusedFilesMutex);
if (0 != _unusedFiles.erase(file)) {
_numUnusedFiles -= 1;
_unusedFilesSize -= length;
}
}
}
void FileCache::clean() { void FileCache::clean() {
size_t overbudgetAmount = getOverbudgetAmount(); size_t overbudgetAmount = getOverbudgetAmount();
@ -250,28 +272,23 @@ void FileCache::clean() {
for (const auto& file : _unusedFiles) { for (const auto& file : _unusedFiles) {
queue.push(file); queue.push(file);
} }
while (!queue.empty() && overbudgetAmount > 0) { while (!queue.empty() && overbudgetAmount > 0) {
auto file = queue.top(); auto file = queue.top();
queue.pop(); queue.pop();
eject(file);
auto length = file->getLength(); auto length = file->getLength();
unusedLock.unlock();
{
file->_cache = nullptr;
Lock lock(_filesMutex);
_files.erase(file->getKey());
}
unusedLock.lock();
_unusedFiles.erase(file);
_numTotalFiles -= 1;
_numUnusedFiles -= 1;
_totalFilesSize -= length;
_unusedFilesSize -= length;
overbudgetAmount -= std::min(length, overbudgetAmount); overbudgetAmount -= std::min(length, overbudgetAmount);
} }
} }
void FileCache::wipe() {
Lock unusedFilesLock(_unusedFilesMutex);
while (!_unusedFiles.empty()) {
eject(*_unusedFiles.begin());
}
}
void FileCache::clear() { void FileCache::clear() {
// Eliminate any overbudget files // Eliminate any overbudget files
clean(); clean();

View file

@ -46,6 +46,9 @@ public:
FileCache(const std::string& dirname, const std::string& ext, QObject* parent = nullptr); FileCache(const std::string& dirname, const std::string& ext, QObject* parent = nullptr);
virtual ~FileCache(); virtual ~FileCache();
// Remove all unlocked items from the cache
void wipe();
size_t getNumTotalFiles() const { return _numTotalFiles; } size_t getNumTotalFiles() const { return _numTotalFiles; }
size_t getNumCachedFiles() const { return _numUnusedFiles; } size_t getNumCachedFiles() const { return _numUnusedFiles; }
size_t getSizeTotalFiles() const { return _totalFilesSize; } size_t getSizeTotalFiles() const { return _totalFilesSize; }
@ -95,6 +98,9 @@ public:
private: private:
using Mutex = std::recursive_mutex; using Mutex = std::recursive_mutex;
using Lock = std::unique_lock<Mutex>; using Lock = std::unique_lock<Mutex>;
using Map = std::unordered_map<Key, std::weak_ptr<File>>;
using Set = std::unordered_set<FilePointer>;
using KeySet = std::unordered_set<Key>;
friend class File; friend class File;
@ -105,6 +111,8 @@ private:
void removeUnusedFile(const FilePointer& file); void removeUnusedFile(const FilePointer& file);
void clean(); void clean();
void clear(); void clear();
// Remove a file from the cache
void eject(const FilePointer& file);
size_t getOverbudgetAmount() const; size_t getOverbudgetAmount() const;
@ -122,10 +130,10 @@ private:
std::string _dirpath; std::string _dirpath;
bool _initialized { false }; bool _initialized { false };
std::unordered_map<Key, std::weak_ptr<File>> _files; Map _files;
Mutex _filesMutex; Mutex _filesMutex;
std::unordered_set<FilePointer> _unusedFiles; Set _unusedFiles;
Mutex _unusedFilesMutex; Mutex _unusedFilesMutex;
}; };
@ -136,8 +144,8 @@ public:
using Key = FileCache::Key; using Key = FileCache::Key;
using Metadata = FileCache::Metadata; using Metadata = FileCache::Metadata;
Key getKey() const { return _key; } const Key& getKey() const { return _key; }
size_t getLength() const { return _length; } const size_t& getLength() const { return _length; }
std::string getFilepath() const { return _filepath; } std::string getFilepath() const { return _filepath; }
virtual ~File(); virtual ~File();

View file

@ -65,8 +65,7 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer
_lastStep(0), _lastStep(0),
_loopsWithoutOwner(0), _loopsWithoutOwner(0),
_accelerationNearlyGravityCount(0), _accelerationNearlyGravityCount(0),
_numInactiveUpdates(1), _numInactiveUpdates(1)
_outgoingPriority(0)
{ {
_type = MOTIONSTATE_TYPE_ENTITY; _type = MOTIONSTATE_TYPE_ENTITY;
assert(_entity); assert(_entity);
@ -75,6 +74,8 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer
// we need the side-effects of EntityMotionState::setShape() so we call it explicitly here // we need the side-effects of EntityMotionState::setShape() so we call it explicitly here
// rather than pass the legit shape pointer to the ObjectMotionState ctor above. // rather than pass the legit shape pointer to the ObjectMotionState ctor above.
setShape(shape); setShape(shape);
_outgoingPriority = _entity->getPendingOwnershipPriority();
} }
EntityMotionState::~EntityMotionState() { EntityMotionState::~EntityMotionState() {
@ -84,7 +85,7 @@ EntityMotionState::~EntityMotionState() {
void EntityMotionState::updateServerPhysicsVariables() { void EntityMotionState::updateServerPhysicsVariables() {
assert(entityTreeIsLocked()); assert(entityTreeIsLocked());
if (_entity->getSimulatorID() == Physics::getSessionUUID()) { if (isLocallyOwned()) {
// don't slam these values if we are the simulation owner // don't slam these values if we are the simulation owner
return; return;
} }
@ -136,23 +137,23 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) {
_nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS;
} }
_loopsWithoutOwner = 0; _loopsWithoutOwner = 0;
} else if (_entity->getSimulatorID() == Physics::getSessionUUID()) { _numInactiveUpdates = 0;
} else if (isLocallyOwned()) {
// we just inherited ownership, make sure our desired priority matches what we have // we just inherited ownership, make sure our desired priority matches what we have
upgradeOutgoingPriority(_entity->getSimulationPriority()); upgradeOutgoingPriority(_entity->getSimulationPriority());
} else { } else {
_outgoingPriority = 0; _outgoingPriority = 0;
_nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS;
_numInactiveUpdates = 0;
} }
} }
if (flags & Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY) { if (flags & Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY) {
// The DIRTY_SIMULATOR_OWNERSHIP_PRIORITY bits really mean "we should bid for ownership because // The DIRTY_SIMULATOR_OWNERSHIP_PRIORITY bit means one of the following:
// a local script has been changing physics properties, or we should adjust our own ownership priority". // (1) we own it but may need to change the priority OR...
// The desired priority is determined by which bits were set. // (2) we don't own it but should bid (because a local script has been changing physics properties)
if (flags & Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB) { uint8_t newPriority = isLocallyOwned() ? _entity->getSimulationOwner().getPriority() : _entity->getSimulationOwner().getPendingPriority();
_outgoingPriority = SCRIPT_GRAB_SIMULATION_PRIORITY; _outgoingPriority = glm::max(_outgoingPriority, newPriority);
} else {
_outgoingPriority = SCRIPT_POKE_SIMULATION_PRIORITY;
}
// reset bid expiry so that we bid ASAP // reset bid expiry so that we bid ASAP
_nextOwnershipBid = 0; _nextOwnershipBid = 0;
} }
@ -317,7 +318,7 @@ bool EntityMotionState::isCandidateForOwnership() const {
assert(_entity); assert(_entity);
assert(entityTreeIsLocked()); assert(entityTreeIsLocked());
return _outgoingPriority != 0 return _outgoingPriority != 0
|| Physics::getSessionUUID() == _entity->getSimulatorID() || isLocallyOwned()
|| _entity->dynamicDataNeedsTransmit(); || _entity->dynamicDataNeedsTransmit();
} }
@ -491,7 +492,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
return true; return true;
} }
if (_entity->getSimulatorID() != Physics::getSessionUUID()) { if (!isLocallyOwned()) {
// we don't own the simulation // we don't own the simulation
// NOTE: we do not volunteer to own kinematic or static objects // NOTE: we do not volunteer to own kinematic or static objects
@ -599,7 +600,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
properties.clearSimulationOwner(); properties.clearSimulationOwner();
_outgoingPriority = 0; _outgoingPriority = 0;
_entity->setPendingOwnershipPriority(_outgoingPriority, now); _entity->setPendingOwnershipPriority(_outgoingPriority, now);
} else if (Physics::getSessionUUID() != _entity->getSimulatorID()) { } else if (!isLocallyOwned()) {
// we don't own the simulation for this entity yet, but we're sending a bid for it // we don't own the simulation for this entity yet, but we're sending a bid for it
quint8 bidPriority = glm::max<uint8_t>(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY); quint8 bidPriority = glm::max<uint8_t>(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY);
properties.setSimulationOwner(Physics::getSessionUUID(), bidPriority); properties.setSimulationOwner(Physics::getSessionUUID(), bidPriority);
@ -788,6 +789,10 @@ void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& ma
_entity->computeCollisionGroupAndFinalMask(group, mask); _entity->computeCollisionGroupAndFinalMask(group, mask);
} }
bool EntityMotionState::isLocallyOwned() const {
return _entity->getSimulatorID() == Physics::getSessionUUID();
}
bool EntityMotionState::shouldBeLocallyOwned() const { bool EntityMotionState::shouldBeLocallyOwned() const {
return (_outgoingPriority > VOLUNTEER_SIMULATION_PRIORITY && _outgoingPriority > _entity->getSimulationPriority()) || return (_outgoingPriority > VOLUNTEER_SIMULATION_PRIORITY && _outgoingPriority > _entity->getSimulationPriority()) ||
_entity->getSimulatorID() == Physics::getSessionUUID(); _entity->getSimulatorID() == Physics::getSessionUUID();

View file

@ -79,6 +79,7 @@ public:
virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const override; virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const override;
bool isLocallyOwned() const override;
bool shouldBeLocallyOwned() const override; bool shouldBeLocallyOwned() const override;
friend class PhysicalEntitySimulation; friend class PhysicalEntitySimulation;

View file

@ -146,6 +146,7 @@ public:
void dirtyInternalKinematicChanges() { _hasInternalKinematicChanges = true; } void dirtyInternalKinematicChanges() { _hasInternalKinematicChanges = true; }
void clearInternalKinematicChanges() { _hasInternalKinematicChanges = false; } void clearInternalKinematicChanges() { _hasInternalKinematicChanges = false; }
virtual bool isLocallyOwned() const { return false; }
virtual bool shouldBeLocallyOwned() const { return false; } virtual bool shouldBeLocallyOwned() const { return false; }
friend class PhysicsEngine; friend class PhysicsEngine;

View file

@ -129,6 +129,9 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) {
} }
body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
body->updateInertiaTensor(); body->updateInertiaTensor();
if (motionState->isLocallyOwned()) {
_activeStaticBodies.insert(body);
}
break; break;
} }
} }
@ -174,19 +177,9 @@ void PhysicsEngine::removeObjects(const VectorOfMotionStates& objects) {
// frame (because the framerate is faster than our physics simulation rate). When this happens we must scan // frame (because the framerate is faster than our physics simulation rate). When this happens we must scan
// _activeStaticBodies for objects that were recently deleted so we don't try to access a dangling pointer. // _activeStaticBodies for objects that were recently deleted so we don't try to access a dangling pointer.
for (auto object : objects) { for (auto object : objects) {
btRigidBody* body = object->getRigidBody(); std::set<btRigidBody*>::iterator itr = _activeStaticBodies.find(object->getRigidBody());
if (itr != _activeStaticBodies.end()) {
std::vector<btRigidBody*>::reverse_iterator itr = _activeStaticBodies.rbegin(); _activeStaticBodies.erase(itr);
while (itr != _activeStaticBodies.rend()) {
if (body == *itr) {
if (*itr != *(_activeStaticBodies.rbegin())) {
// swap with rbegin
*itr = *(_activeStaticBodies.rbegin());
}
_activeStaticBodies.pop_back();
break;
}
++itr;
} }
} }
} }
@ -245,14 +238,16 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob
object->clearIncomingDirtyFlags(); object->clearIncomingDirtyFlags();
} }
if (object->getMotionType() == MOTION_TYPE_STATIC && object->isActive()) { if (object->getMotionType() == MOTION_TYPE_STATIC && object->isActive()) {
_activeStaticBodies.push_back(object->getRigidBody()); _activeStaticBodies.insert(object->getRigidBody());
} }
} }
// active static bodies have changed (in an Easy way) and need their Aabbs updated // active static bodies have changed (in an Easy way) and need their Aabbs updated
// but we've configured Bullet to NOT update them automatically (for improved performance) // but we've configured Bullet to NOT update them automatically (for improved performance)
// so we must do it ourselves // so we must do it ourselves
for (size_t i = 0; i < _activeStaticBodies.size(); ++i) { std::set<btRigidBody*>::const_iterator itr = _activeStaticBodies.begin();
_dynamicsWorld->updateSingleAabb(_activeStaticBodies[i]); while (itr != _activeStaticBodies.end()) {
_dynamicsWorld->updateSingleAabb(*itr);
++itr;
} }
return stillNeedChange; return stillNeedChange;
} }
@ -496,13 +491,23 @@ const CollisionEvents& PhysicsEngine::getCollisionEvents() {
const VectorOfMotionStates& PhysicsEngine::getChangedMotionStates() { const VectorOfMotionStates& PhysicsEngine::getChangedMotionStates() {
BT_PROFILE("copyOutgoingChanges"); BT_PROFILE("copyOutgoingChanges");
_dynamicsWorld->synchronizeMotionStates();
// Bullet will not deactivate static objects (it doesn't expect them to be active) // Bullet will not deactivate static objects (it doesn't expect them to be active)
// so we must deactivate them ourselves // so we must deactivate them ourselves
for (size_t i = 0; i < _activeStaticBodies.size(); ++i) { std::set<btRigidBody*>::const_iterator itr = _activeStaticBodies.begin();
_activeStaticBodies[i]->forceActivationState(ISLAND_SLEEPING); while (itr != _activeStaticBodies.end()) {
btRigidBody* body = *itr;
body->forceActivationState(ISLAND_SLEEPING);
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(body->getUserPointer());
if (motionState) {
_dynamicsWorld->addChangedMotionState(motionState);
}
++itr;
} }
_activeStaticBodies.clear(); _activeStaticBodies.clear();
_dynamicsWorld->synchronizeMotionStates();
_hasOutgoingChanges = false; _hasOutgoingChanges = false;
return _dynamicsWorld->getChangedMotionStates(); return _dynamicsWorld->getChangedMotionStates();
} }

View file

@ -13,6 +13,7 @@
#define hifi_PhysicsEngine_h #define hifi_PhysicsEngine_h
#include <stdint.h> #include <stdint.h>
#include <set>
#include <vector> #include <vector>
#include <QUuid> #include <QUuid>
@ -114,7 +115,7 @@ private:
CollisionEvents _collisionEvents; CollisionEvents _collisionEvents;
QHash<QUuid, EntityDynamicPointer> _objectDynamics; QHash<QUuid, EntityDynamicPointer> _objectDynamics;
QHash<btRigidBody*, QSet<QUuid>> _objectDynamicsByBody; QHash<btRigidBody*, QSet<QUuid>> _objectDynamicsByBody;
std::vector<btRigidBody*> _activeStaticBodies; std::set<btRigidBody*> _activeStaticBodies;
glm::vec3 _originOffset; glm::vec3 _originOffset;

View file

@ -51,6 +51,8 @@ public:
const VectorOfMotionStates& getChangedMotionStates() const { return _changedMotionStates; } const VectorOfMotionStates& getChangedMotionStates() const { return _changedMotionStates; }
const VectorOfMotionStates& getDeactivatedMotionStates() const { return _deactivatedStates; } const VectorOfMotionStates& getDeactivatedMotionStates() const { return _deactivatedStates; }
void addChangedMotionState(ObjectMotionState* motionState) { _changedMotionStates.push_back(motionState); }
private: private:
// call this instead of non-virtual btDiscreteDynamicsWorld::synchronizeSingleMotionState() // call this instead of non-virtual btDiscreteDynamicsWorld::synchronizeSingleMotionState()
void synchronizeMotionState(btRigidBody* body); void synchronizeMotionState(btRigidBody* body);

View file

@ -113,18 +113,21 @@ void FileCacheTests::testUnusedFiles() {
QVERIFY(!file.get()); QVERIFY(!file.get());
} }
QThread::msleep(1000);
// Test files 90 to 99 are present // Test files 90 to 99 are present
for (int i = 90; i < 100; ++i) { for (int i = 90; i < 100; ++i) {
std::string key = getFileKey(i); std::string key = getFileKey(i);
auto file = cache->getFile(key); auto file = cache->getFile(key);
QVERIFY(file.get()); QVERIFY(file.get());
inUseFiles.push_back(file); inUseFiles.push_back(file);
// Each access touches the file, so we need to sleep here to ensure that the files are
// spaced out in numeric order, otherwise later tests can't reliably determine the order if (i == 94) {
// for cache ejection // Each access touches the file, so we need to sleep here to ensure that the the last 5 files
// have later times for cache ejection priority, otherwise the test runs too fast to reliably
// differentiate
QThread::msleep(1000); QThread::msleep(1000);
} }
}
QCOMPARE(cache->getNumCachedFiles(), (size_t)0); QCOMPARE(cache->getNumCachedFiles(), (size_t)0);
QCOMPARE(cache->getNumTotalFiles(), (size_t)10); QCOMPARE(cache->getNumTotalFiles(), (size_t)10);
inUseFiles.clear(); inUseFiles.clear();
@ -165,6 +168,20 @@ void FileCacheTests::testFreeSpacePreservation() {
} }
} }
void FileCacheTests::testWipe() {
// Reset the cache
auto cache = makeFileCache(_testDir.path());
QCOMPARE(cache->getNumCachedFiles(), (size_t)5);
QCOMPARE(cache->getNumTotalFiles(), (size_t)5);
cache->wipe();
QCOMPARE(cache->getNumCachedFiles(), (size_t)0);
QCOMPARE(cache->getNumTotalFiles(), (size_t)0);
QVERIFY(getCacheDirectorySize() > 0);
forceDeletes();
QCOMPARE(getCacheDirectorySize(), (size_t)0);
}
void FileCacheTests::cleanupTestCase() { void FileCacheTests::cleanupTestCase() {
} }

View file

@ -20,6 +20,7 @@ private slots:
void testUnusedFiles(); void testUnusedFiles();
void testFreeSpacePreservation(); void testFreeSpacePreservation();
void cleanupTestCase(); void cleanupTestCase();
void testWipe();
private: private:
size_t getFreeSpace() const; size_t getFreeSpace() const;