Skip to content
Snippets Groups Projects
Unverified Commit b985a699 authored by Brad Linden's avatar Brad Linden Committed by GitHub
Browse files

Merge pull request #191 from secondlife/brad/SL-19648-refcount-llgltfmaterial-thread-safety

Fix SL-19675 crash due to thread unsafe LLRefCount usage possibly related to SL-19648
parents 799d7605 5465594a
No related branches found
No related tags found
No related merge requests found
...@@ -167,6 +167,7 @@ class LLGLTFMaterial : public LLRefCount ...@@ -167,6 +167,7 @@ class LLGLTFMaterial : public LLRefCount
// set the contents of this LLGLTFMaterial from the given json // set the contents of this LLGLTFMaterial from the given json
// returns true if successful // returns true if successful
// if unsuccessful, the contents of this LLGLTFMaterial should be left unchanged and false is returned
// json - the json text to load from // json - the json text to load from
// warn_msg - warning message from TinyGLTF if any // warn_msg - warning message from TinyGLTF if any
// error_msg - error_msg from TinyGLTF if any // error_msg - error_msg from TinyGLTF if any
......
...@@ -219,40 +219,36 @@ class LLGLTFMaterialOverrideDispatchHandler : public LLDispatchHandler ...@@ -219,40 +219,36 @@ class LLGLTFMaterialOverrideDispatchHandler : public LLDispatchHandler
struct ReturnData struct ReturnData
{ {
public: public:
LLPointer<LLGLTFMaterial> mMaterial; LLGLTFMaterial mMaterial;
S32 mSide; S32 mSide;
bool mSuccess; bool mSuccess;
}; };
// fromJson() is performance heavy offload to a thread. if (!object_override.mSides.empty())
main_queue->postTo(
general_queue,
[object_override]() // Work done on general queue
{ {
std::vector<ReturnData> results; // fromJson() is performance heavy offload to a thread.
main_queue->postTo(
if (!object_override.mSides.empty()) general_queue,
[sides=object_override.mSides]() // Work done on general queue
{ {
results.reserve(object_override.mSides.size()); std::vector<ReturnData> results;
results.reserve(sides.size());
// parse json // parse json
std::unordered_map<S32, std::string>::const_iterator iter = object_override.mSides.begin(); std::unordered_map<S32, std::string>::const_iterator iter = sides.begin();
std::unordered_map<S32, std::string>::const_iterator end = object_override.mSides.end(); std::unordered_map<S32, std::string>::const_iterator end = sides.end();
while (iter != end) while (iter != end)
{ {
LLPointer<LLGLTFMaterial> override_data = new LLGLTFMaterial();
std::string warn_msg, error_msg; std::string warn_msg, error_msg;
bool success = override_data->fromJSON(iter->second, warn_msg, error_msg);
ReturnData result; ReturnData result;
bool success = result.mMaterial.fromJSON(iter->second, warn_msg, error_msg);
result.mSuccess = success; result.mSuccess = success;
result.mSide = iter->first; result.mSide = iter->first;
if (success) if (!success)
{
result.mMaterial = override_data;
}
else
{ {
LL_WARNS("GLTF") << "failed to parse GLTF override data. errors: " << error_msg << " | warnings: " << warn_msg << LL_ENDL; LL_WARNS("GLTF") << "failed to parse GLTF override data. errors: " << error_msg << " | warnings: " << warn_msg << LL_ENDL;
} }
...@@ -260,64 +256,68 @@ class LLGLTFMaterialOverrideDispatchHandler : public LLDispatchHandler ...@@ -260,64 +256,68 @@ class LLGLTFMaterialOverrideDispatchHandler : public LLDispatchHandler
results.push_back(result); results.push_back(result);
iter++; iter++;
} }
} return results;
return results; },
}, [object_id=object_override.mObjectId, this](std::vector<ReturnData> results) // Callback to main thread
[object_override, this](std::vector<ReturnData> results) // Callback to main thread
{ {
LLViewerObject * obj = gObjectList.findObject(object_override.mObjectId); LLViewerObject * obj = gObjectList.findObject(object_id);
if (results.size() > 0 ) if (results.size() > 0 )
{
std::unordered_set<S32> side_set;
for (int i = 0; i < results.size(); ++i)
{ {
if (results[i].mSuccess) std::unordered_set<S32> side_set;
for (auto const & result : results)
{ {
// flag this side to not be nulled out later S32 side = result.mSide;
side_set.insert(results[i].mSide); if (result.mSuccess)
{
// copy to heap here because LLTextureEntry is going to take ownership with an LLPointer
LLGLTFMaterial * material = new LLGLTFMaterial(result.mMaterial);
// flag this side to not be nulled out later
side_set.insert(side);
if (obj) if (obj)
{
obj->setTEGLTFMaterialOverride(side, material);
}
}
// unblock material editor
if (obj && obj->getTE(side) && obj->getTE(side)->isSelected())
{ {
obj->setTEGLTFMaterialOverride(results[i].mSide, results[i].mMaterial); doSelectionCallbacks(object_id, side);
} }
} }
// unblock material editor
if (obj && obj->getTE(results[i].mSide) && obj->getTE(results[i].mSide)->isSelected())
{
doSelectionCallbacks(object_override.mObjectId, results[i].mSide);
}
}
if (obj && side_set.size() != obj->getNumTEs()) if (obj && side_set.size() != obj->getNumTEs())
{ // object exists and at least one texture entry needs to have its override data nulled out { // object exists and at least one texture entry needs to have its override data nulled out
for (int i = 0; i < obj->getNumTEs(); ++i) for (int i = 0; i < obj->getNumTEs(); ++i)
{
if (side_set.find(i) == side_set.end())
{ {
obj->setTEGLTFMaterialOverride(i, nullptr); if (side_set.find(i) == side_set.end())
if (obj->getTE(i) && obj->getTE(i)->isSelected())
{ {
doSelectionCallbacks(object_override.mObjectId, i); obj->setTEGLTFMaterialOverride(i, nullptr);
if (obj->getTE(i) && obj->getTE(i)->isSelected())
{
doSelectionCallbacks(object_id, i);
}
} }
} }
} }
} }
} else if (obj)
else if (obj) { // override list was empty or an error occurred, null out all overrides for this object
{ // override list was empty or an error occurred, null out all overrides for this object for (int i = 0; i < obj->getNumTEs(); ++i)
for (int i = 0; i < obj->getNumTEs(); ++i)
{
obj->setTEGLTFMaterialOverride(i, nullptr);
if (obj->getTE(i) && obj->getTE(i)->isSelected())
{ {
doSelectionCallbacks(obj->getID(), i); obj->setTEGLTFMaterialOverride(i, nullptr);
if (obj->getTE(i) && obj->getTE(i)->isSelected())
{
doSelectionCallbacks(obj->getID(), i);
}
} }
} }
} });
}); }
} }
private: private:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment