build StaticMeshShapes outside of mainloop

This commit is contained in:
Andrew Meadows 2019-04-17 14:48:24 -07:00
parent 7fb7e503f9
commit fbd4db5505
4 changed files with 94 additions and 11 deletions

View file

@ -481,3 +481,8 @@ void ShapeFactory::deleteShape(const btCollisionShape* shape) {
}
delete nonConstShape;
}
void ShapeFactory::Worker::run() {
shape = ShapeFactory::createShapeFromInfo(shapeInfo);
emit submitWork(this);
}

View file

@ -14,6 +14,8 @@
#include <btBulletDynamicsCommon.h>
#include <glm/glm.hpp>
#include <QObject>
#include <QtCore/QRunnable>
#include <ShapeInfo.h>
@ -22,6 +24,17 @@
namespace ShapeFactory {
const btCollisionShape* createShapeFromInfo(const ShapeInfo& info);
void deleteShape(const btCollisionShape* shape);
class Worker : public QObject, public QRunnable {
Q_OBJECT
public:
Worker(const ShapeInfo& info) : shapeInfo(info), shape(nullptr) {}
void run() override;
ShapeInfo shapeInfo;
const btCollisionShape* shape;
signals:
void submitWork(Worker*);
};
};
#endif // hifi_ShapeFactory_h

View file

@ -12,10 +12,8 @@
#include "ShapeManager.h"
#include <glm/gtx/norm.hpp>
#include <QThreadPool>
#include <QDebug>
#include "ShapeFactory.h"
const int MAX_RING_SIZE = 256;
@ -42,13 +40,36 @@ const btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
shapeRef->refCount++;
return shapeRef->shape;
}
const btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
if (shape) {
ShapeReference newRef;
newRef.refCount = 1;
newRef.shape = shape;
newRef.key = info.getHash();
_shapeMap.insert(hashKey, newRef);
const btCollisionShape* shape = nullptr;
if (info.getType() == SHAPE_TYPE_STATIC_MESH) {
uint64_t hash = info.getHash();
const auto itr = std::find(_pendingMeshShapes.begin(), _pendingMeshShapes.end(), hash);
if (itr == _pendingMeshShapes.end()) {
// start a worker
_pendingMeshShapes.push_back(hash);
// try to recycle old deadWorker
ShapeFactory::Worker* worker = _deadWorker;
if (!worker) {
worker = new ShapeFactory::Worker(info);
} else {
worker->shapeInfo = info;
_deadWorker = nullptr;
}
// we will delete worker manually later
worker->setAutoDelete(false);
QObject::connect(worker, &ShapeFactory::Worker::submitWork, this, &ShapeManager::acceptWork);
QThreadPool::globalInstance()->start(worker);
}
// else we're still waiting for the shape to be created on another thread
} else {
shape = ShapeFactory::createShapeFromInfo(info);
if (shape) {
ShapeReference newRef;
newRef.refCount = 1;
newRef.shape = shape;
newRef.key = info.getHash();
_shapeMap.insert(hashKey, newRef);
}
}
return shape;
}
@ -153,3 +174,39 @@ bool ShapeManager::hasShape(const btCollisionShape* shape) const {
}
return false;
}
// slot: called when ShapeFactory::Worker is done building shape
void ShapeManager::acceptWork(ShapeFactory::Worker* worker) {
auto itr = std::find(_pendingMeshShapes.begin(), _pendingMeshShapes.end(), worker->shapeInfo.getHash());
if (itr == _pendingMeshShapes.end()) {
// we've received a shape but don't remember asking for it
// (should not fall in here, but if we do: delete the unwanted shape)
if (worker->shape) {
ShapeFactory::deleteShape(worker->shape);
}
} else {
// clear pending status
*itr = _pendingMeshShapes.back();
_pendingMeshShapes.pop_back();
// cache the new shape
if (worker->shape) {
ShapeReference newRef;
newRef.refCount = 1;
newRef.shape = worker->shape;
newRef.key = worker->shapeInfo.getHash();
HashKey hashKey(newRef.key);
_shapeMap.insert(hashKey, newRef);
}
}
disconnect(worker, &ShapeFactory::Worker::submitWork, this, &ShapeManager::acceptWork);
if (_deadWorker) {
// delete the previous deadWorker manually
delete _deadWorker;
}
// save this dead worker for later
worker->shapeInfo.clear();
worker->shape = nullptr;
_deadWorker = worker;
}

View file

@ -14,11 +14,13 @@
#include <vector>
#include <QObject>
#include <btBulletDynamicsCommon.h>
#include <LinearMath/btHashMap.h>
#include <ShapeInfo.h>
#include "ShapeFactory.h"
#include "HashKey.h"
// The ShapeManager handles the ref-counting on shared shapes:
@ -44,7 +46,8 @@
// entries that still have zero ref-count.
class ShapeManager {
class ShapeManager : public QObject {
Q_OBJECT
public:
ShapeManager();
@ -65,6 +68,9 @@ public:
int getNumReferences(const btCollisionShape* shape) const;
bool hasShape(const btCollisionShape* shape) const;
protected slots:
void acceptWork(ShapeFactory::Worker* worker);
private:
bool releaseShapeByKey(uint64_t key);
@ -79,6 +85,8 @@ private:
// btHashMap is required because it supports memory alignment of the btCollisionShapes
btHashMap<HashKey, ShapeReference> _shapeMap;
std::vector<uint64_t> _garbageRing;
std::vector<uint64_t> _pendingMeshShapes;
ShapeFactory::Worker* _deadWorker { nullptr };
uint32_t _ringIndex { 0 };
};