mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 07:58:59 +02:00
fix Model mew/delete and thread issues
This commit is contained in:
parent
c83cb6386a
commit
c66ef90ca0
4 changed files with 117 additions and 42 deletions
|
@ -67,6 +67,7 @@ void EntityTreeRenderer::update() {
|
||||||
|
|
||||||
void EntityTreeRenderer::render(RenderMode renderMode) {
|
void EntityTreeRenderer::render(RenderMode renderMode) {
|
||||||
OctreeRenderer::render(renderMode);
|
OctreeRenderer::render(renderMode);
|
||||||
|
deleteReleasedModels(); // seems like as good as any other place to do some memory cleanup
|
||||||
}
|
}
|
||||||
|
|
||||||
const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(const EntityItem* entityItem) {
|
const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(const EntityItem* entityItem) {
|
||||||
|
@ -76,7 +77,7 @@ const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(const EntityItem* en
|
||||||
const RenderableModelEntityItem* constModelEntityItem = dynamic_cast<const RenderableModelEntityItem*>(entityItem);
|
const RenderableModelEntityItem* constModelEntityItem = dynamic_cast<const RenderableModelEntityItem*>(entityItem);
|
||||||
RenderableModelEntityItem* modelEntityItem = const_cast<RenderableModelEntityItem*>(constModelEntityItem);
|
RenderableModelEntityItem* modelEntityItem = const_cast<RenderableModelEntityItem*>(constModelEntityItem);
|
||||||
assert(modelEntityItem); // we need this!!!
|
assert(modelEntityItem); // we need this!!!
|
||||||
Model* model = modelEntityItem->getModel();
|
Model* model = modelEntityItem->getModel(this);
|
||||||
if (model) {
|
if (model) {
|
||||||
result = &model->getGeometry()->getFBXGeometry();
|
result = &model->getGeometry()->getFBXGeometry();
|
||||||
}
|
}
|
||||||
|
@ -91,7 +92,7 @@ const Model* EntityTreeRenderer::getModelForEntityItem(const EntityItem* entityI
|
||||||
RenderableModelEntityItem* modelEntityItem = const_cast<RenderableModelEntityItem*>(constModelEntityItem);
|
RenderableModelEntityItem* modelEntityItem = const_cast<RenderableModelEntityItem*>(constModelEntityItem);
|
||||||
assert(modelEntityItem); // we need this!!!
|
assert(modelEntityItem); // we need this!!!
|
||||||
|
|
||||||
result = modelEntityItem->getModel();
|
result = modelEntityItem->getModel(this);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -225,7 +226,71 @@ void EntityTreeRenderer::processEraseMessage(const QByteArray& dataByteArray, co
|
||||||
static_cast<EntityTree*>(_tree)->processEraseMessage(dataByteArray, sourceNode);
|
static_cast<EntityTree*>(_tree)->processEraseMessage(dataByteArray, sourceNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Model* EntityTreeRenderer::allocateModel(const QString& url) {
|
||||||
|
Model* model = NULL;
|
||||||
|
// Make sure we only create and delete models on the thread that owns the EntityTreeRenderer
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "allocateModel", Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(Model*, model),
|
||||||
|
Q_ARG(const QString&, url));
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
model = new Model();
|
||||||
|
model->init();
|
||||||
|
model->setURL(QUrl(url));
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
Model* EntityTreeRenderer::updateModel(Model* original, const QString& newUrl) {
|
||||||
|
Model* model = NULL;
|
||||||
|
|
||||||
|
// The caller shouldn't call us if the URL doesn't need to change. But if they
|
||||||
|
// do, we just return their original back to them.
|
||||||
|
if (!original || (QUrl(newUrl) == original->getURL())) {
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before we do any creating or deleting, make sure we're on our renderer thread
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "updateModel", Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(Model*, model),
|
||||||
|
Q_ARG(Model*, original),
|
||||||
|
Q_ARG(const QString&, newUrl));
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
// at this point we know we need to replace the model, and we know we're on the
|
||||||
|
// correct thread, so we can do all our work.
|
||||||
|
if (original) {
|
||||||
|
delete original; // delete the old model...
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the model and correctly initialize it with the new url
|
||||||
|
model = new Model();
|
||||||
|
model->init();
|
||||||
|
model->setURL(QUrl(newUrl));
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityTreeRenderer::releaseModel(Model* model) {
|
||||||
|
// If we're not on the renderer's thread, then remember this model to be deleted later
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
_releasedModels << model;
|
||||||
|
} else { // otherwise just delete it right away
|
||||||
|
delete model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityTreeRenderer::deleteReleasedModels() {
|
||||||
|
if (_releasedModels.size() > 0) {
|
||||||
|
foreach(Model* model, _releasedModels) {
|
||||||
|
delete model;
|
||||||
|
}
|
||||||
|
_releasedModels.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,19 @@ public:
|
||||||
void renderEntityTypeModel(EntityItem* entity, RenderArgs* args);
|
void renderEntityTypeModel(EntityItem* entity, RenderArgs* args);
|
||||||
|
|
||||||
static QThread* getMainThread();
|
static QThread* getMainThread();
|
||||||
|
|
||||||
|
/// if a renderable entity item needs a model, we will allocate it for them
|
||||||
|
Q_INVOKABLE Model* allocateModel(const QString& url);
|
||||||
|
|
||||||
|
/// if a renderable entity item needs to update the URL of a model, we will handle that for the entity
|
||||||
|
Q_INVOKABLE Model* updateModel(Model* original, const QString& newUrl);
|
||||||
|
|
||||||
|
/// if a renderable entity item is done with a model, it should return it to us
|
||||||
|
void releaseModel(Model* model);
|
||||||
|
|
||||||
|
void deleteReleasedModels();
|
||||||
|
private:
|
||||||
|
QList<Model*> _releasedModels;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_EntityTreeRenderer_h
|
#endif // hifi_EntityTreeRenderer_h
|
||||||
|
|
|
@ -29,10 +29,11 @@ EntityItem* RenderableModelEntityItem::factory(const EntityItemID& entityID, con
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderableModelEntityItem::~RenderableModelEntityItem() {
|
RenderableModelEntityItem::~RenderableModelEntityItem() {
|
||||||
|
assert(_myRenderer || !_model); // if we have a model, we need to know our renderer
|
||||||
// TODO: we can't just delete this because we may be on the wrong thread.
|
if (_myRenderer && _model) {
|
||||||
//delete _model;
|
_myRenderer->releaseModel(_model);
|
||||||
_model = NULL;
|
_model = NULL;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool RenderableModelEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
|
bool RenderableModelEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
|
||||||
|
@ -75,7 +76,8 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
if (!_model || _needsModelReload) {
|
if (!_model || _needsModelReload) {
|
||||||
// TODO: this getModel() appears to be about 3% of model render time. We should optimize
|
// TODO: this getModel() appears to be about 3% of model render time. We should optimize
|
||||||
PerformanceTimer perfTimer("getModel");
|
PerformanceTimer perfTimer("getModel");
|
||||||
getModel();
|
EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer);
|
||||||
|
getModel(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_model) {
|
if (_model) {
|
||||||
|
@ -191,47 +193,40 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Model* RenderableModelEntityItem::getModel() {
|
Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
||||||
|
Model* result = NULL;
|
||||||
|
|
||||||
|
// make sure our renderer is setup
|
||||||
|
if (!_myRenderer) {
|
||||||
|
_myRenderer = renderer;
|
||||||
|
}
|
||||||
|
assert(_myRenderer == renderer); // you should only ever render on one renderer
|
||||||
|
|
||||||
_needsModelReload = false; // this is the reload
|
_needsModelReload = false; // this is the reload
|
||||||
|
|
||||||
|
// if we have a URL, then we will want to end up returning a model...
|
||||||
if (!getModelURL().isEmpty()) {
|
if (!getModelURL().isEmpty()) {
|
||||||
// double check our URLS match...
|
|
||||||
|
// if we have a previously allocated model, but it's URL doesn't match
|
||||||
|
// then we need to let our renderer update our model for us.
|
||||||
if (_model && QUrl(getModelURL()) != _model->getURL()) {
|
if (_model && QUrl(getModelURL()) != _model->getURL()) {
|
||||||
delete _model; // delete the old model...
|
result = _model = _myRenderer->updateModel(_model, getModelURL());
|
||||||
_model = NULL;
|
|
||||||
_needsSimulation = true;
|
_needsSimulation = true;
|
||||||
}
|
} else if (!_model) { // if we don't yet have a model, then we want our renderer to allocate one
|
||||||
|
result = _model = _myRenderer->allocateModel(getModelURL());
|
||||||
// if we don't have a model... but our item does have a model URL
|
|
||||||
if (!_model) {
|
|
||||||
// Make sure we only create new models on the thread that owns the EntityTreeRenderer
|
|
||||||
if (QThread::currentThread() != EntityTreeRenderer::getMainThread()) {
|
|
||||||
|
|
||||||
// TODO: how do we better handle this??? we may need this for scripting...
|
|
||||||
// possible go back to a getModel() service on the TreeRenderer, but have it take a URL
|
|
||||||
// this would allow the entity items to use that service for loading, and since the
|
|
||||||
// EntityTreeRenderer is a Q_OBJECT it can call invokeMethod()
|
|
||||||
|
|
||||||
qDebug() << "can't call getModel() on thread other than rendering thread...";
|
|
||||||
|
|
||||||
//QMetaObject::invokeMethod(this, "getModel", Qt::BlockingQueuedConnection, Q_RETURN_ARG(Model*, _model));
|
|
||||||
//qDebug() << "got it... _model=" << _model;
|
|
||||||
return _model;
|
|
||||||
}
|
|
||||||
|
|
||||||
_model = new Model();
|
|
||||||
_model->init();
|
|
||||||
_model->setURL(QUrl(getModelURL()));
|
|
||||||
_needsSimulation = true;
|
_needsSimulation = true;
|
||||||
|
} else { // we already have the model we want...
|
||||||
|
result = _model;
|
||||||
}
|
}
|
||||||
} else {
|
} else { // if our desired URL is empty, we may need to delete our existing model
|
||||||
// our URL is empty, we should clean up our old model
|
|
||||||
if (_model) {
|
if (_model) {
|
||||||
delete _model; // delete the old model...
|
_myRenderer->releaseModel(_model);
|
||||||
_model = NULL;
|
result = _model = NULL;
|
||||||
_needsSimulation = true;
|
_needsSimulation = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _model;
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,8 @@ public:
|
||||||
ModelEntityItem(entityItemID, properties),
|
ModelEntityItem(entityItemID, properties),
|
||||||
_model(NULL),
|
_model(NULL),
|
||||||
_needsSimulation(true),
|
_needsSimulation(true),
|
||||||
_needsModelReload(true) { };
|
_needsModelReload(true),
|
||||||
|
_myRenderer(NULL) { };
|
||||||
|
|
||||||
virtual ~RenderableModelEntityItem();
|
virtual ~RenderableModelEntityItem();
|
||||||
|
|
||||||
|
@ -48,11 +49,12 @@ public:
|
||||||
virtual void somethingChangedNotification() { _needsSimulation = true; }
|
virtual void somethingChangedNotification() { _needsSimulation = true; }
|
||||||
|
|
||||||
virtual void render(RenderArgs* args);
|
virtual void render(RenderArgs* args);
|
||||||
Model* getModel();
|
Model* getModel(EntityTreeRenderer* renderer);
|
||||||
private:
|
private:
|
||||||
Model* _model;
|
Model* _model;
|
||||||
bool _needsSimulation;
|
bool _needsSimulation;
|
||||||
bool _needsModelReload;
|
bool _needsModelReload;
|
||||||
|
EntityTreeRenderer* _myRenderer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_RenderableModelEntityItem_h
|
#endif // hifi_RenderableModelEntityItem_h
|
||||||
|
|
Loading…
Reference in a new issue