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

Commit ee5f5f0

Browse files
committed
[Impeller] Create a wrapper Impeller context for each Vulkan surface and its swapchain
In #41059 the Android context and surface were changed to share one impeller::ContextVK across all instances of AndroidSurfaceVulkanImpeller. However, the ContextVK holds a reference to the current swapchain. If an app uses multiple AndroidSurfaceVulkanImpeller instances (e.g. for platform views), then one surface may overwrite the ContextVK's swapchain while another surface is trying to render. This patch allows each surface to get its own impeller::Context instance holding a swapchain tied to that surface. The per-surface contexts will delegate most operations to the shared parent ContextVK.
1 parent ae6d1d6 commit ee5f5f0

File tree

9 files changed

+214
-77
lines changed

9 files changed

+214
-77
lines changed

impeller/playground/backend/vulkan/playground_impl_vk.cc

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "impeller/playground/imgui/vk/imgui_shaders_vk.h"
1919
#include "impeller/renderer/backend/vulkan/context_vk.h"
2020
#include "impeller/renderer/backend/vulkan/formats_vk.h"
21+
#include "impeller/renderer/backend/vulkan/surface_context_vk.h"
2122
#include "impeller/renderer/backend/vulkan/surface_vk.h"
2223
#include "impeller/renderer/backend/vulkan/texture_vk.h"
2324
#include "impeller/renderer/vk/compute_shaders_vk.h"
@@ -86,27 +87,27 @@ PlaygroundImplVK::PlaygroundImplVK(PlaygroundSwitches switches)
8687
context_settings.cache_directory = fml::paths::GetCachesDirectory();
8788
context_settings.enable_validation = switches_.enable_vulkan_validation;
8889

89-
auto context = ContextVK::Create(std::move(context_settings));
90-
91-
if (!context || !context->IsValid()) {
90+
auto context_vk = ContextVK::Create(std::move(context_settings));
91+
if (!context_vk || !context_vk->IsValid()) {
9292
VALIDATION_LOG << "Could not create Vulkan context in the playground.";
9393
return;
9494
}
9595

9696
VkSurfaceKHR vk_surface;
97-
auto res =
98-
vk::Result{::glfwCreateWindowSurface(context->GetInstance(), // instance
99-
window, // window
100-
nullptr, // allocator
101-
&vk_surface // surface
102-
)};
97+
auto res = vk::Result{::glfwCreateWindowSurface(
98+
context_vk->GetInstance(), // instance
99+
window, // window
100+
nullptr, // allocator
101+
&vk_surface // surface
102+
)};
103103
if (res != vk::Result::eSuccess) {
104104
VALIDATION_LOG << "Could not create surface for GLFW window: "
105105
<< vk::to_string(res);
106106
return;
107107
}
108108

109-
vk::UniqueSurfaceKHR surface{vk_surface, context->GetInstance()};
109+
vk::UniqueSurfaceKHR surface{vk_surface, context_vk->GetInstance()};
110+
auto context = context_vk->CreateSurfaceContext();
110111
if (!context->SetWindowSurface(std::move(surface))) {
111112
VALIDATION_LOG << "Could not set up surface for context.";
112113
return;
@@ -130,8 +131,9 @@ PlaygroundImpl::WindowHandle PlaygroundImplVK::GetWindowHandle() const {
130131
// |PlaygroundImpl|
131132
std::unique_ptr<Surface> PlaygroundImplVK::AcquireSurfaceFrame(
132133
std::shared_ptr<Context> context) {
133-
ContextVK* context_vk = reinterpret_cast<ContextVK*>(context_.get());
134-
return context_vk->AcquireNextSurface();
134+
SurfaceContextVK* surface_context_vk =
135+
reinterpret_cast<SurfaceContextVK*>(context_.get());
136+
return surface_context_vk->AcquireNextSurface();
135137
}
136138

137139
} // namespace impeller

impeller/renderer/backend/vulkan/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ impeller_component("vulkan") {
7979
"shader_library_vk.h",
8080
"shared_object_vk.cc",
8181
"shared_object_vk.h",
82+
"surface_context_vk.cc",
83+
"surface_context_vk.h",
8284
"surface_vk.cc",
8385
"surface_vk.h",
8486
"swapchain_image_vk.cc",

impeller/renderer/backend/vulkan/context_vk.cc

Lines changed: 3 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "impeller/renderer/backend/vulkan/fence_waiter_vk.h"
3131
#include "impeller/renderer/backend/vulkan/formats_vk.h"
3232
#include "impeller/renderer/backend/vulkan/resource_manager_vk.h"
33+
#include "impeller/renderer/backend/vulkan/surface_context_vk.h"
3334
#include "impeller/renderer/backend/vulkan/surface_vk.h"
3435
#include "impeller/renderer/backend/vulkan/vk.h"
3536
#include "impeller/renderer/capabilities.h"
@@ -489,49 +490,8 @@ void ContextVK::Shutdown() {
489490
raster_message_loop_->Terminate();
490491
}
491492

492-
std::unique_ptr<Surface> ContextVK::AcquireNextSurface() {
493-
TRACE_EVENT0("impeller", __FUNCTION__);
494-
auto surface = swapchain_ ? swapchain_->AcquireNextDrawable() : nullptr;
495-
if (surface && pipeline_library_) {
496-
pipeline_library_->DidAcquireSurfaceFrame();
497-
}
498-
if (allocator_) {
499-
allocator_->DidAcquireSurfaceFrame();
500-
}
501-
return surface;
502-
}
503-
504-
#ifdef FML_OS_ANDROID
505-
506-
vk::UniqueSurfaceKHR ContextVK::CreateAndroidSurface(
507-
ANativeWindow* window) const {
508-
if (!device_holder_->instance) {
509-
return vk::UniqueSurfaceKHR{VK_NULL_HANDLE};
510-
}
511-
512-
auto create_info = vk::AndroidSurfaceCreateInfoKHR().setWindow(window);
513-
auto surface_res =
514-
device_holder_->instance->createAndroidSurfaceKHRUnique(create_info);
515-
516-
if (surface_res.result != vk::Result::eSuccess) {
517-
VALIDATION_LOG << "Could not create Android surface, error: "
518-
<< vk::to_string(surface_res.result);
519-
return vk::UniqueSurfaceKHR{VK_NULL_HANDLE};
520-
}
521-
522-
return std::move(surface_res.value);
523-
}
524-
525-
#endif // FML_OS_ANDROID
526-
527-
bool ContextVK::SetWindowSurface(vk::UniqueSurfaceKHR surface) {
528-
auto swapchain = SwapchainVK::Create(shared_from_this(), std::move(surface));
529-
if (!swapchain) {
530-
VALIDATION_LOG << "Could not create swapchain.";
531-
return false;
532-
}
533-
swapchain_ = std::move(swapchain);
534-
return true;
493+
std::shared_ptr<SurfaceContextVK> ContextVK::CreateSurfaceContext() {
494+
return std::make_shared<SurfaceContextVK>(shared_from_this());
535495
}
536496

537497
const std::shared_ptr<const Capabilities>& ContextVK::GetCapabilities() const {

impeller/renderer/backend/vulkan/context_vk.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class CommandEncoderVK;
3232
class DebugReportVK;
3333
class FenceWaiterVK;
3434
class ResourceManagerVK;
35+
class SurfaceContextVK;
3536

3637
class ContextVK final : public Context,
3738
public BackendCast<ContextVK, Context>,
@@ -127,13 +128,7 @@ class ContextVK final : public Context,
127128
const std::shared_ptr<fml::ConcurrentTaskRunner>
128129
GetConcurrentWorkerTaskRunner() const;
129130

130-
[[nodiscard]] bool SetWindowSurface(vk::UniqueSurfaceKHR surface);
131-
132-
std::unique_ptr<Surface> AcquireNextSurface();
133-
134-
#ifdef FML_OS_ANDROID
135-
vk::UniqueSurfaceKHR CreateAndroidSurface(ANativeWindow* window) const;
136-
#endif // FML_OS_ANDROID
131+
std::shared_ptr<SurfaceContextVK> CreateSurfaceContext();
137132

138133
const std::shared_ptr<QueueVK>& GetGraphicsQueue() const;
139134

@@ -164,7 +159,6 @@ class ContextVK final : public Context,
164159
std::shared_ptr<SamplerLibraryVK> sampler_library_;
165160
std::shared_ptr<PipelineLibraryVK> pipeline_library_;
166161
QueuesVK queues_;
167-
std::shared_ptr<SwapchainVK> swapchain_;
168162
std::shared_ptr<const Capabilities> device_capabilities_;
169163
std::shared_ptr<FenceWaiterVK> fence_waiter_;
170164
std::shared_ptr<ResourceManagerVK> resource_manager_;
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "impeller/renderer/backend/vulkan/surface_context_vk.h"
6+
7+
#include "flutter/fml/trace_event.h"
8+
#include "impeller/renderer/backend/vulkan/context_vk.h"
9+
#include "impeller/renderer/backend/vulkan/swapchain_vk.h"
10+
11+
namespace impeller {
12+
13+
SurfaceContextVK::SurfaceContextVK(const std::shared_ptr<ContextVK>& parent)
14+
: parent_(parent) {}
15+
16+
SurfaceContextVK::~SurfaceContextVK() = default;
17+
18+
Context::BackendType SurfaceContextVK::GetBackendType() const {
19+
return parent_->GetBackendType();
20+
}
21+
22+
std::string SurfaceContextVK::DescribeGpuModel() const {
23+
return parent_->DescribeGpuModel();
24+
}
25+
26+
bool SurfaceContextVK::IsValid() const {
27+
return parent_->IsValid();
28+
}
29+
30+
std::shared_ptr<Allocator> SurfaceContextVK::GetResourceAllocator() const {
31+
return parent_->GetResourceAllocator();
32+
}
33+
34+
std::shared_ptr<ShaderLibrary> SurfaceContextVK::GetShaderLibrary() const {
35+
return parent_->GetShaderLibrary();
36+
}
37+
38+
std::shared_ptr<SamplerLibrary> SurfaceContextVK::GetSamplerLibrary() const {
39+
return parent_->GetSamplerLibrary();
40+
}
41+
42+
std::shared_ptr<PipelineLibrary> SurfaceContextVK::GetPipelineLibrary() const {
43+
return parent_->GetPipelineLibrary();
44+
}
45+
46+
std::shared_ptr<CommandBuffer> SurfaceContextVK::CreateCommandBuffer() const {
47+
return parent_->CreateCommandBuffer();
48+
}
49+
50+
const std::shared_ptr<const Capabilities>& SurfaceContextVK::GetCapabilities()
51+
const {
52+
return parent_->GetCapabilities();
53+
}
54+
55+
void SurfaceContextVK::Shutdown() {
56+
parent_->Shutdown();
57+
}
58+
59+
bool SurfaceContextVK::SetWindowSurface(vk::UniqueSurfaceKHR surface) {
60+
auto swapchain = SwapchainVK::Create(parent_, std::move(surface));
61+
if (!swapchain) {
62+
VALIDATION_LOG << "Could not create swapchain.";
63+
return false;
64+
}
65+
swapchain_ = std::move(swapchain);
66+
return true;
67+
}
68+
69+
std::unique_ptr<Surface> SurfaceContextVK::AcquireNextSurface() {
70+
TRACE_EVENT0("impeller", __FUNCTION__);
71+
auto surface = swapchain_ ? swapchain_->AcquireNextDrawable() : nullptr;
72+
auto pipeline_library = parent_->GetPipelineLibrary();
73+
if (surface && pipeline_library) {
74+
impeller::PipelineLibraryVK::Cast(*pipeline_library)
75+
.DidAcquireSurfaceFrame();
76+
}
77+
auto allocator = parent_->GetResourceAllocator();
78+
if (allocator) {
79+
allocator->DidAcquireSurfaceFrame();
80+
}
81+
return surface;
82+
}
83+
84+
#ifdef FML_OS_ANDROID
85+
86+
vk::UniqueSurfaceKHR SurfaceContextVK::CreateAndroidSurface(
87+
ANativeWindow* window) const {
88+
if (!parent_->GetInstance()) {
89+
return vk::UniqueSurfaceKHR{VK_NULL_HANDLE};
90+
}
91+
92+
auto create_info = vk::AndroidSurfaceCreateInfoKHR().setWindow(window);
93+
auto surface_res =
94+
parent_->GetInstance().createAndroidSurfaceKHRUnique(create_info);
95+
96+
if (surface_res.result != vk::Result::eSuccess) {
97+
VALIDATION_LOG << "Could not create Android surface, error: "
98+
<< vk::to_string(surface_res.result);
99+
return vk::UniqueSurfaceKHR{VK_NULL_HANDLE};
100+
}
101+
102+
return std::move(surface_res.value);
103+
}
104+
105+
#endif // FML_OS_ANDROID
106+
107+
} // namespace impeller
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#pragma once
6+
7+
#include <memory>
8+
9+
#include "impeller/base/backend_cast.h"
10+
#include "impeller/renderer/backend/vulkan/vk.h"
11+
#include "impeller/renderer/context.h"
12+
13+
namespace impeller {
14+
15+
class ContextVK;
16+
class Surface;
17+
class SwapchainVK;
18+
19+
class SurfaceContextVK : public Context,
20+
public BackendCast<SurfaceContextVK, Context> {
21+
public:
22+
SurfaceContextVK(const std::shared_ptr<ContextVK>& parent);
23+
24+
// |Context|
25+
~SurfaceContextVK() override;
26+
27+
// |Context|
28+
BackendType GetBackendType() const override;
29+
30+
// |Context|
31+
std::string DescribeGpuModel() const override;
32+
33+
// |Context|
34+
bool IsValid() const override;
35+
36+
// |Context|
37+
std::shared_ptr<Allocator> GetResourceAllocator() const override;
38+
39+
// |Context|
40+
std::shared_ptr<ShaderLibrary> GetShaderLibrary() const override;
41+
42+
// |Context|
43+
std::shared_ptr<SamplerLibrary> GetSamplerLibrary() const override;
44+
45+
// |Context|
46+
std::shared_ptr<PipelineLibrary> GetPipelineLibrary() const override;
47+
48+
// |Context|
49+
std::shared_ptr<CommandBuffer> CreateCommandBuffer() const override;
50+
51+
// |Context|
52+
const std::shared_ptr<const Capabilities>& GetCapabilities() const override;
53+
54+
// |Context|
55+
void Shutdown() override;
56+
57+
[[nodiscard]] bool SetWindowSurface(vk::UniqueSurfaceKHR surface);
58+
59+
std::unique_ptr<Surface> AcquireNextSurface();
60+
61+
#ifdef FML_OS_ANDROID
62+
vk::UniqueSurfaceKHR CreateAndroidSurface(ANativeWindow* window) const;
63+
#endif // FML_OS_ANDROID
64+
65+
private:
66+
std::shared_ptr<ContextVK> parent_;
67+
std::shared_ptr<SwapchainVK> swapchain_;
68+
};
69+
70+
} // namespace impeller

shell/gpu/gpu_surface_vulkan_impeller.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
#include "flutter/fml/make_copyable.h"
88
#include "flutter/impeller/display_list/dl_dispatcher.h"
99
#include "flutter/impeller/renderer/renderer.h"
10-
#include "impeller/renderer/backend/vulkan/context_vk.h"
10+
#include "impeller/renderer/backend/vulkan/surface_context_vk.h"
11+
#include "impeller/renderer/surface.h"
1112

1213
namespace flutter {
1314

@@ -54,7 +55,7 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceVulkanImpeller::AcquireFrame(
5455
return nullptr;
5556
}
5657

57-
auto& context_vk = impeller::ContextVK::Cast(*impeller_context_);
58+
auto& context_vk = impeller::SurfaceContextVK::Cast(*impeller_context_);
5859
std::unique_ptr<impeller::Surface> surface = context_vk.AcquireNextSurface();
5960

6061
SurfaceFrame::SubmitCallback submit_callback =

0 commit comments

Comments
 (0)