Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions impeller/aiks/testing/context_spy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ std::shared_ptr<ContextMock> ContextSpy::MakeContext(
return real_context->IsValid();
});

ON_CALL(*mock_context, GetBackendType)
.WillByDefault([real_context]() -> Context::BackendType {
return real_context->GetBackendType();
});

ON_CALL(*mock_context, GetCapabilities)
.WillByDefault(
[real_context]() -> const std::shared_ptr<const Capabilities>& {
Expand Down
63 changes: 63 additions & 0 deletions impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

#include <memory>

#include "fml/trace_event.h"
#include "impeller/base/strings.h"
#include "impeller/base/validation.h"
#include "impeller/core/formats.h"
#include "impeller/entity/contents/framebuffer_blend_contents.h"
#include "impeller/entity/entity.h"
Expand Down Expand Up @@ -460,6 +462,7 @@ ContentContext::ContentContext(
*context_, clip_pipeline_descriptor));

is_valid_ = true;
InitializeCommonlyUsedShadersIfNeeded();
}

ContentContext::~ContentContext() = default;
Expand Down Expand Up @@ -608,4 +611,64 @@ void ContentContext::FlushCommandBuffers() const {
GetContext()->GetCommandQueue()->Submit(buffers);
}

void ContentContext::InitializeCommonlyUsedShadersIfNeeded() const {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For accuracy, CommonlyUsedPipelinesIfNeeded since the shaders are already in their libraries.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose even that isn't entirely accurate since the render pass is being initialized. lol, just DoOneTimeVoodoo?

if (GetContext()->GetBackendType() == Context::BackendType::kOpenGLES) {
// TODO(jonahwilliams): The OpenGL Embedder Unittests hang if this code
// runs.
return;
}
TRACE_EVENT0("flutter", "InitializeCommonlyUsedShadersIfNeeded");

// Initialize commonly used shaders that aren't defaults. These settings were
// chosen based on the knowledge that we mix and match triangle and
// triangle-strip geometry, and also have fairly agressive srcOver to src
// blend mode conversions.
auto options = ContentContextOptions{
.sample_count = SampleCount::kCount4,
.color_attachment_pixel_format =
context_->GetCapabilities()->GetDefaultColorFormat()};

for (const auto mode : {BlendMode::kSource, BlendMode::kSourceOver}) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the proceedings of the last go/impeller-weekly, my understanding was that PSO variant construction time did not show up in traces yet. What gives for the need for this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two traces posted are also unrelated to PSO variant construction and the linked bug makes no mention of PSO variants being slow to initialize. This bit seems unrelated to the linked issue or any problem we've discussed in the past.

for (const auto geometry :
{PrimitiveType::kTriangle, PrimitiveType::kTriangleStrip}) {
options.blend_mode = mode;
options.primitive_type = geometry;
CreateIfNeeded(solid_fill_pipelines_, options);
CreateIfNeeded(texture_pipelines_, options);
if (GetContext()->GetCapabilities()->SupportsSSBO()) {
CreateIfNeeded(linear_gradient_ssbo_fill_pipelines_, options);
CreateIfNeeded(radial_gradient_ssbo_fill_pipelines_, options);
CreateIfNeeded(sweep_gradient_ssbo_fill_pipelines_, options);
CreateIfNeeded(conical_gradient_ssbo_fill_pipelines_, options);
}
}
}

options.blend_mode = BlendMode::kDestination;
options.primitive_type = PrimitiveType::kTriangleStrip;
for (const auto stencil_mode :
{ContentContextOptions::StencilMode::kLegacyClipIncrement,
ContentContextOptions::StencilMode::kLegacyClipDecrement,
ContentContextOptions::StencilMode::kLegacyClipRestore}) {
options.stencil_mode = stencil_mode;
CreateIfNeeded(clip_pipelines_, options);
}

// On ARM devices, the initial usage of vkCmdCopyBufferToImage has been
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We aren't completely in the dark about the reasons as to why this is happening. And we haven't fully convinced ourselves this isn't user error yet.

// observed to take 10s of ms as an internal shader is compiled to perform
// the operation. Similarly, the initial render pass can also take 10s of ms
// for a similar reason. Because the context object is initialized far
// before the first frame, create a trivial texture and render pass to force
// the driver to compiler these shaders before the frame begins.
TextureDescriptor desc;
desc.size = {1, 1};
desc.storage_mode = StorageMode::kHostVisible;
desc.format = context_->GetCapabilities()->GetDefaultColorFormat();
auto texture = GetContext()->GetResourceAllocator()->CreateTexture(desc);
uint32_t color = 0;
if (!texture->SetContents(reinterpret_cast<uint8_t*>(&color), 4u)) {
VALIDATION_LOG << "Failed to set bootstrap texture.";
}
}

} // namespace impeller
33 changes: 26 additions & 7 deletions impeller/entity/contents/content_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,14 @@ class ContentContext {
std::shared_ptr<Context> context_;
std::shared_ptr<LazyGlyphAtlas> lazy_glyph_atlas_;

/// Run backend specific additional setup and create common shader variants.
///
/// This bootstrap is intended to improve the performance of several
/// first frame benchmarks that are tracked in the flutter device lab.
/// The workload includes initializing commonly used but not default
/// shader variants, as well as forcing driver initialization.
void InitializeCommonlyUsedShadersIfNeeded() const;

struct RuntimeEffectPipelineKey {
std::string unique_entrypoint_name;
ContentContextOptions options;
Expand Down Expand Up @@ -1007,6 +1015,16 @@ class ContentContext {
std::shared_ptr<Pipeline<PipelineDescriptor>> GetPipeline(
Variants<TypedPipeline>& container,
ContentContextOptions opts) const {
TypedPipeline* pipeline = CreateIfNeeded(container, opts);
if (!pipeline) {
return nullptr;
}
return pipeline->WaitAndGet();
}

template <class TypedPipeline>
TypedPipeline* CreateIfNeeded(Variants<TypedPipeline>& container,
ContentContextOptions opts) const {
if (!IsValid()) {
return nullptr;
}
Expand All @@ -1015,16 +1033,17 @@ class ContentContext {
opts.wireframe = true;
}

if (auto found = container.Get(opts)) {
return found->WaitAndGet();
if (TypedPipeline* found = container.Get(opts)) {
return found;
}

auto prototype = container.GetDefault();
TypedPipeline* prototype = container.GetDefault();

// The prototype must always be initialized in the constructor.
FML_CHECK(prototype != nullptr);

auto pipeline = prototype->WaitAndGet();
std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline =
prototype->WaitAndGet();
if (!pipeline) {
return nullptr;
}
Expand All @@ -1036,10 +1055,10 @@ class ContentContext {
desc.SetLabel(
SPrintF("%s V#%zu", desc.GetLabel().c_str(), variants_count));
});
auto variant = std::make_unique<TypedPipeline>(std::move(variant_future));
auto variant_pipeline = variant->WaitAndGet();
std::unique_ptr<TypedPipeline> variant =
std::make_unique<TypedPipeline>(std::move(variant_future));
container.Set(opts, std::move(variant));
return variant_pipeline;
return container.Get(opts);
}

bool is_valid_ = false;
Expand Down
Loading