-
Notifications
You must be signed in to change notification settings - Fork 6k
Preserve order when regenerating GPU images #40268
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,7 +14,7 @@ Texture::Texture(int64_t id) : id_(id) {} | |
|
|
||
| Texture::~Texture() = default; | ||
|
|
||
| TextureRegistry::TextureRegistry() = default; | ||
| TextureRegistry::TextureRegistry() : image_counter_(0) {} | ||
|
|
||
| void TextureRegistry::RegisterTexture(const std::shared_ptr<Texture>& texture) { | ||
| if (!texture) { | ||
|
|
@@ -26,7 +26,13 @@ void TextureRegistry::RegisterTexture(const std::shared_ptr<Texture>& texture) { | |
| void TextureRegistry::RegisterContextListener( | ||
| uintptr_t id, | ||
| std::weak_ptr<ContextListener> image) { | ||
| images_[id] = std::move(image); | ||
| size_t next_id = image_counter_.fetch_add(1); | ||
| auto const result = image_indices_.insert({id, next_id}); | ||
| if (!result.second) { | ||
| ordered_images_.erase(result.first->second); | ||
| result.first->second = next_id; | ||
| } | ||
| ordered_images_[next_id] = {next_id, std::move(image)}; | ||
| } | ||
|
|
||
| void TextureRegistry::UnregisterTexture(int64_t id) { | ||
|
|
@@ -39,19 +45,29 @@ void TextureRegistry::UnregisterTexture(int64_t id) { | |
| } | ||
|
|
||
| void TextureRegistry::UnregisterContextListener(uintptr_t id) { | ||
| images_.erase(id); | ||
| ordered_images_.erase(image_indices_[id]); | ||
| image_indices_.erase(id); | ||
| } | ||
|
|
||
| void TextureRegistry::OnGrContextCreated() { | ||
| for (auto& it : mapping_) { | ||
| it.second->OnGrContextCreated(); | ||
| } | ||
|
|
||
| for (const auto& [id, weak_image] : images_) { | ||
| // Calling OnGrContextCreated may result in a subsequent call to | ||
| // RegisterContextListener from the listener, which may modify the map. | ||
| std::vector< | ||
| std::pair<size_t, std::pair<uintptr_t, std::weak_ptr<ContextListener>>>> | ||
| ordered_images(ordered_images_.begin(), ordered_images_.end()); | ||
|
|
||
| for (const auto& [id, pair] : ordered_images) { | ||
| auto index_id = pair.first; | ||
| auto weak_image = pair.second; | ||
| if (auto image = weak_image.lock()) { | ||
| image->OnGrContextCreated(); | ||
| } else { | ||
| images_.erase(id); | ||
| image_indices_.erase(index_id); | ||
| ordered_images_.erase(id); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -61,11 +77,14 @@ void TextureRegistry::OnGrContextDestroyed() { | |
| it.second->OnGrContextDestroyed(); | ||
| } | ||
|
|
||
| for (const auto& [id, weak_image] : images_) { | ||
| for (const auto& [id, pair] : ordered_images_) { | ||
| auto index_id = pair.first; | ||
| auto weak_image = pair.second; | ||
| if (auto image = weak_image.lock()) { | ||
| image->OnGrContextDestroyed(); | ||
| } else { | ||
| images_.erase(id); | ||
| image_indices_.erase(index_id); | ||
| ordered_images_.erase(id); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here and elsewhere, mutation while enumeration makes me nervous. Are iterators on
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Used to doing this safely by using iterators explicitly and assigning the iterator to the return call of
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I'll change this. It seems to work but it'd be safer to use the iterator. I had another issue with mutation during iteration that I fixed by copying the map into a vector, but that would be overkill here. |
||
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -95,7 +95,15 @@ class TextureRegistry { | |
|
|
||
| private: | ||
| std::map<int64_t, std::shared_ptr<Texture>> mapping_; | ||
| std::map<uintptr_t, std::weak_ptr<ContextListener>> images_; | ||
| std::atomic_size_t image_counter_; | ||
| // This map keeps track of registered context listeners by their own | ||
| // externally provided id. It indexes into ordered_images_. | ||
| std::map<uintptr_t, size_t> image_indices_; | ||
| // This map makes sure that iteration of images happens in insertion order | ||
| // (managed by image_counter_) so that images which depend on other images get | ||
| // re-created in the right order. | ||
| std::map<size_t, std::pair<uintptr_t, std::weak_ptr<ContextListener>>> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess this makes sense but is a bit rough to read. How about we take advantage of the fact that the map is ordered already and store the existing key and the order as a key type. Then you can have a custom std::less on the key type and typedef the whole thing for more readibility. Iterating over the map elements will be order then. I suppose you will need a separate map for the removal (a unintptr to order association). Just a suggestion.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I considered that but it comes down to either storing extra data in the key or extra data in the value. This makes the key easier to hash and avoids the need for a custom comparer that ignores part of the data. I'll use the typedef though.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (if I didn't need to worry about updating the order when someone re-registers I could just use a std::vector) |
||
| ordered_images_; | ||
|
|
||
| FML_DISALLOW_COPY_AND_ASSIGN(TextureRegistry); | ||
| }; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C++ operator overloading of
++does this for you already. IMO that is more readable thatfetch_add.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides, does this need to be an atomic? I thought all texture registry operations were raster thread only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it doesn't need to be atomic. I was being overly cautious :)