Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit dfa70d7

Browse files
[Impeller] exploit content context options' perfect hash function. (#56360)
The content context options hash function is pefect - meaning a distinct hash guarantees a distinct value and vice versa. We can replace the hashing entirely with an equality check of the hash function. Additionally, we can remove the hashmap. As most of these maps have fewer than a dozen entries (often just 2 or 3) and the linear search is much faster.
1 parent 2a89d7b commit dfa70d7

File tree

3 files changed

+40
-55
lines changed

3 files changed

+40
-55
lines changed

impeller/entity/contents/content_context.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#include <utility>
99

1010
#include "fml/trace_event.h"
11-
#include "impeller/base/strings.h"
1211
#include "impeller/base/validation.h"
1312
#include "impeller/core/formats.h"
1413
#include "impeller/core/texture_descriptor.h"

impeller/entity/contents/content_context.h

Lines changed: 36 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -315,47 +315,27 @@ struct ContentContextOptions {
315315
bool wireframe = false;
316316
bool is_for_rrect_blur_clear = false;
317317

318-
struct Hash {
319-
constexpr uint64_t operator()(const ContentContextOptions& o) const {
320-
static_assert(sizeof(o.sample_count) == 1);
321-
static_assert(sizeof(o.blend_mode) == 1);
322-
static_assert(sizeof(o.sample_count) == 1);
323-
static_assert(sizeof(o.depth_compare) == 1);
324-
static_assert(sizeof(o.stencil_mode) == 1);
325-
static_assert(sizeof(o.primitive_type) == 1);
326-
static_assert(sizeof(o.color_attachment_pixel_format) == 1);
327-
328-
return (o.is_for_rrect_blur_clear ? 1llu : 0llu) << 0 |
329-
(o.wireframe ? 1llu : 0llu) << 1 |
330-
(o.has_depth_stencil_attachments ? 1llu : 0llu) << 2 |
331-
(o.depth_write_enabled ? 1llu : 0llu) << 3 |
332-
// enums
333-
static_cast<uint64_t>(o.color_attachment_pixel_format) << 8 |
334-
static_cast<uint64_t>(o.primitive_type) << 16 |
335-
static_cast<uint64_t>(o.stencil_mode) << 24 |
336-
static_cast<uint64_t>(o.depth_compare) << 32 |
337-
static_cast<uint64_t>(o.blend_mode) << 40 |
338-
static_cast<uint64_t>(o.sample_count) << 48;
339-
}
340-
};
341-
342-
struct Equal {
343-
constexpr bool operator()(const ContentContextOptions& lhs,
344-
const ContentContextOptions& rhs) const {
345-
return lhs.sample_count == rhs.sample_count &&
346-
lhs.blend_mode == rhs.blend_mode &&
347-
lhs.depth_write_enabled == rhs.depth_write_enabled &&
348-
lhs.depth_compare == rhs.depth_compare &&
349-
lhs.stencil_mode == rhs.stencil_mode &&
350-
lhs.primitive_type == rhs.primitive_type &&
351-
lhs.color_attachment_pixel_format ==
352-
rhs.color_attachment_pixel_format &&
353-
lhs.has_depth_stencil_attachments ==
354-
rhs.has_depth_stencil_attachments &&
355-
lhs.wireframe == rhs.wireframe &&
356-
lhs.is_for_rrect_blur_clear == rhs.is_for_rrect_blur_clear;
357-
}
358-
};
318+
constexpr uint64_t ToKey() const {
319+
static_assert(sizeof(sample_count) == 1);
320+
static_assert(sizeof(blend_mode) == 1);
321+
static_assert(sizeof(sample_count) == 1);
322+
static_assert(sizeof(depth_compare) == 1);
323+
static_assert(sizeof(stencil_mode) == 1);
324+
static_assert(sizeof(primitive_type) == 1);
325+
static_assert(sizeof(color_attachment_pixel_format) == 1);
326+
327+
return (is_for_rrect_blur_clear ? 1llu : 0llu) << 0 |
328+
(wireframe ? 1llu : 0llu) << 1 |
329+
(has_depth_stencil_attachments ? 1llu : 0llu) << 2 |
330+
(depth_write_enabled ? 1llu : 0llu) << 3 |
331+
// enums
332+
static_cast<uint64_t>(color_attachment_pixel_format) << 8 |
333+
static_cast<uint64_t>(primitive_type) << 16 |
334+
static_cast<uint64_t>(stencil_mode) << 24 |
335+
static_cast<uint64_t>(depth_compare) << 32 |
336+
static_cast<uint64_t>(blend_mode) << 40 |
337+
static_cast<uint64_t>(sample_count) << 48;
338+
}
359339

360340
void ApplyToPipelineDescriptor(PipelineDescriptor& desc) const;
361341
};
@@ -771,15 +751,15 @@ class ContentContext {
771751
struct Hash {
772752
std::size_t operator()(const RuntimeEffectPipelineKey& key) const {
773753
return fml::HashCombine(key.unique_entrypoint_name,
774-
ContentContextOptions::Hash{}(key.options));
754+
key.options.ToKey());
775755
}
776756
};
777757

778758
struct Equal {
779759
constexpr bool operator()(const RuntimeEffectPipelineKey& lhs,
780760
const RuntimeEffectPipelineKey& rhs) const {
781761
return lhs.unique_entrypoint_name == rhs.unique_entrypoint_name &&
782-
ContentContextOptions::Equal{}(lhs.options, rhs.options);
762+
lhs.options.ToKey() == rhs.options.ToKey();
783763
}
784764
};
785765
};
@@ -810,7 +790,13 @@ class ContentContext {
810790

811791
void Set(const ContentContextOptions& options,
812792
std::unique_ptr<PipelineHandleT> pipeline) {
813-
pipelines_[options] = std::move(pipeline);
793+
uint64_t p_key = options.ToKey();
794+
for (const auto& [key, pipeline] : pipelines_) {
795+
if (key == p_key) {
796+
return;
797+
}
798+
}
799+
pipelines_.push_back(std::make_pair(p_key, std::move(pipeline)));
814800
}
815801

816802
void SetDefault(const ContentContextOptions& options,
@@ -833,8 +819,11 @@ class ContentContext {
833819
}
834820

835821
PipelineHandleT* Get(const ContentContextOptions& options) const {
836-
if (auto found = pipelines_.find(options); found != pipelines_.end()) {
837-
return found->second.get();
822+
uint64_t p_key = options.ToKey();
823+
for (const auto& [key, pipeline] : pipelines_) {
824+
if (key == p_key) {
825+
return pipeline.get();
826+
}
838827
}
839828
return nullptr;
840829
}
@@ -850,10 +839,7 @@ class ContentContext {
850839

851840
private:
852841
std::optional<ContentContextOptions> default_options_;
853-
std::unordered_map<ContentContextOptions,
854-
std::unique_ptr<PipelineHandleT>,
855-
ContentContextOptions::Hash,
856-
ContentContextOptions::Equal>
842+
std::vector<std::pair<uint64_t, std::unique_ptr<PipelineHandleT>>>
857843
pipelines_;
858844

859845
Variants(const Variants&) = delete;

impeller/entity/entity_unittests.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2170,16 +2170,16 @@ TEST_P(EntityTest, DecalSpecializationAppliedToMorphologyFilter) {
21702170
// set of options, we can just compare benchmarks.
21712171
TEST_P(EntityTest, ContentContextOptionsHasReasonableHashFunctions) {
21722172
ContentContextOptions opts;
2173-
auto hash_a = ContentContextOptions::Hash{}(opts);
2173+
auto hash_a = opts.ToKey();
21742174

21752175
opts.blend_mode = BlendMode::kColorBurn;
2176-
auto hash_b = ContentContextOptions::Hash{}(opts);
2176+
auto hash_b = opts.ToKey();
21772177

21782178
opts.has_depth_stencil_attachments = false;
2179-
auto hash_c = ContentContextOptions::Hash{}(opts);
2179+
auto hash_c = opts.ToKey();
21802180

21812181
opts.primitive_type = PrimitiveType::kPoint;
2182-
auto hash_d = ContentContextOptions::Hash{}(opts);
2182+
auto hash_d = opts.ToKey();
21832183

21842184
EXPECT_NE(hash_a, hash_b);
21852185
EXPECT_NE(hash_b, hash_c);

0 commit comments

Comments
 (0)