-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] use const std::unique_ptr ref for Sampler type. #49974
[Impeller] use const std::unique_ptr ref for Sampler type. #49974
Conversation
impeller/core/sampler.h
Outdated
|
|
||
| /// @brief A sampler subclass to be returned in the result of a lost device | ||
| // or other failure to allocate a sampler object. | ||
| class InvalidSampler : public Sampler { |
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'm not a huge fan of creating an object to represent what essentially a null value. I would prefer that instead of passing in a const Sampler& sampler we passed in const std::unique_ptr<Sampler>& sampler. Then we can keep the semantics all the same.
I think IsValid() is an anti-pattern. We shouldn't have invalid objects. It starts polluting your code where you have to check for validity all the time. Or it doesn't and you just have potential bugs everywhere.
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.
We can't use unique_ptr and have a global cache of samplers.
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.
You already are switching to a unique_ptr but you are dereferencing it below. All you have to do is not dereference this and pass the reference to the unique_ptr.
impeller/core/sampler.h
Outdated
|
|
||
| /// @brief A sampler subclass to be returned in the result of a lost device | ||
| // or other failure to allocate a sampler object. | ||
| class InvalidSampler : public Sampler { |
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.
You already are switching to a unique_ptr but you are dereferencing it below. All you have to do is not dereference this and pass the reference to the unique_ptr.
| auto found = samplers_.find(desc); | ||
| if (found != samplers_.end()) { | ||
| return found->second; | ||
| return *found->second.get(); |
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.
Right here, this is a no-no. You are transforming a std::unique_ptr to a reference. References are non-null, std::unique_ptr are nullable. If you return the reference to the unique_ptr you avoid that class of bugs.
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.
We cannot return a reference to a unique_ptr though?
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.
(from a hash map, specifically)
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.
Yea, you can. Depending on the method you might have to do that trick where you have a static nullptr std::unique_ptr that you return the reference to sometimes.
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.
Here's an example:
#include <map>
#include <memory>
class Foo {};
static const std::unique_ptr<Foo> kNullFoo;
const std::unique_ptr<Foo>& find(const std::map<int, std::unique_ptr<Foo>>& map) {
const auto& it = map.find(123);
if (it == map.end()) {
return kNullFoo;
} else {
return it->second;
}
}
int main() {
std::map<int, std::unique_ptr<Foo>> map;
map.insert(std::make_pair(123, std::make_unique<Foo>()));
const std::unique_ptr<Foo>& value = find(map);
return 0;
}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.
Pushed it up
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.
You have to make it return a const std::unique_ptr<const Sampler>& to fix what you have right now. I'm not sure if a const Sampler will work for you. I don't know why that is off the bat
--- a/impeller/renderer/backend/vulkan/sampler_library_vk.cc
+++ b/impeller/renderer/backend/vulkan/sampler_library_vk.cc
@@ -16,9 +16,9 @@ SamplerLibraryVK::SamplerLibraryVK(
SamplerLibraryVK::~SamplerLibraryVK() = default;
-static const std::unique_ptr<Sampler> kNullSampler = nullptr;
+static const std::unique_ptr<const Sampler> kNullSampler = nullptr;
-static const std::unique_ptr<Sampler>& find_thing(
+static const std::unique_ptr<const Sampler>& find_thing(
const SamplerMap& map,
const SamplerDescriptor& desc) {
const auto& it = map.find(desc);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.
(since you were using a const Sampler& it should be good)
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.
OH DUH
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.
OKAY! I DID IT
Thanks @gaaclarke I would have never figured that out!
| SampledImageSlot slot; | ||
| TextureResource texture; | ||
| std::shared_ptr<const Sampler> sampler; | ||
| const std::unique_ptr<const Sampler>& sampler; |
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.
This is potentially a dangling pointer now. What guarantees do we have that this reference will remain valid for the lifetime of the TextureAndSampler?
If we can be confident that it will remain valid, we should add documentation. If we aren't so sure I think maybe we should go back to std::shared_ptr but keep all your work converting the arguments to references. That would eliminate all those shared_ptr copies, except this one.
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.
The platform sampler libraries store the sampler in a unordered_map (which has stable references even when it reallocates) and never evicts them. This should keep the references valid for the lifetime of the program.
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.
This should keep the references valid for the lifetime of the program.
The lifetime of the Context, right? Can you add a comment for this please.
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.
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 think a comment right here at the field would be appropriate too since looking at this code peoples spider sense tingles for dangling pointers.
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.
This code is almost done being deleted :)
gaaclarke
left a comment
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.
lgtm!
…142157) flutter/engine@0b9fce3...4bc368e 2024-01-24 [email protected] [Impeller] use const std::unique_ptr ref for Sampler type. (flutter/engine#49974) 2024-01-24 [email protected] Roll Skia from c353c00a4dcb to 9ea7cb490804 (1 revision) (flutter/engine#50005) 2024-01-24 [email protected] Replace Fuchsia logging macros (FX_LOG*) with FML logging (flutter/engine#49970) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
The backend specific sampler libraries hold a strong reference to the native sampler objects and never clear this cache. As a result of this, we don't theoretically need rendering commands to increment a shared_ptr ref count - instead the sampler library can provide the Sampler object as a const ref and guarantee that it continues to be valid.
This allows us to reduce the amount of refcount ops for commands that use samplers.
Additionally, the sampler library uses nullptr as a sentinel for failing to construct a sampler object. Since sampler already has an isValid member that is checked - we can replace this with a specific invalid object subtype.