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

Commit e32f60a

Browse files
author
Jonah Williams
authored
[Impeller] Treat SubOptimalKHR as rotated. (#43214)
If we don't follow the guidelines at https://developer.android.com/games/optimize/vulkan-prerotation , then any presentations while the screen is rotated will result in suboptimalKHR. Use a change in state across presentations from sucess -> suboptimal or suboptimal -> sucess to detect whether the swapchain needs to be recreated. Fixes flutter/flutter#129459 (mostly)
1 parent f128827 commit e32f60a

File tree

3 files changed

+32
-6
lines changed

3 files changed

+32
-6
lines changed

impeller/renderer/backend/vulkan/swapchain_impl_vk.cc

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,15 @@ static std::optional<vk::Queue> ChoosePresentQueue(
124124
std::shared_ptr<SwapchainImplVK> SwapchainImplVK::Create(
125125
const std::shared_ptr<Context>& context,
126126
vk::UniqueSurfaceKHR surface,
127+
bool was_rotated,
127128
vk::SwapchainKHR old_swapchain) {
128-
return std::shared_ptr<SwapchainImplVK>(
129-
new SwapchainImplVK(context, std::move(surface), old_swapchain));
129+
return std::shared_ptr<SwapchainImplVK>(new SwapchainImplVK(
130+
context, std::move(surface), was_rotated, old_swapchain));
130131
}
131132

132133
SwapchainImplVK::SwapchainImplVK(const std::shared_ptr<Context>& context,
133134
vk::UniqueSurfaceKHR surface,
135+
bool was_rotated,
134136
vk::SwapchainKHR old_swapchain) {
135137
if (!context) {
136138
return;
@@ -197,7 +199,7 @@ SwapchainImplVK::SwapchainImplVK(const std::shared_ptr<Context>& context,
197199
);
198200
swapchain_info.imageArrayLayers = 1u;
199201
swapchain_info.imageUsage = vk::ImageUsageFlagBits::eColorAttachment;
200-
swapchain_info.preTransform = caps.currentTransform;
202+
swapchain_info.preTransform = vk::SurfaceTransformFlagBitsKHR::eIdentity;
201203
swapchain_info.compositeAlpha = composite.value();
202204
// If we set the clipped value to true, Vulkan expects we will never read back
203205
// from the buffer. This is analogous to [CAMetalLayer framebufferOnly] in
@@ -273,6 +275,8 @@ SwapchainImplVK::SwapchainImplVK(const std::shared_ptr<Context>& context,
273275
synchronizers_ = std::move(synchronizers);
274276
current_frame_ = synchronizers_.size() - 1u;
275277
is_valid_ = true;
278+
was_rotated_ = was_rotated;
279+
is_rotated_ = was_rotated;
276280
}
277281

278282
SwapchainImplVK::~SwapchainImplVK() {
@@ -314,6 +318,10 @@ SwapchainImplVK::AcquireResult SwapchainImplVK::AcquireNextDrawable() {
314318
return {};
315319
}
316320

321+
if (was_rotated_ != is_rotated_) {
322+
return AcquireResult{true /* out of date */};
323+
}
324+
317325
const auto& context = ContextVK::Cast(*context_strong);
318326

319327
current_frame_ = (current_frame_ + 1u) % synchronizers_.size();
@@ -338,8 +346,12 @@ SwapchainImplVK::AcquireResult SwapchainImplVK::AcquireNextDrawable() {
338346
nullptr // fence
339347
);
340348

341-
if (acq_result == vk::Result::eSuboptimalKHR ||
342-
acq_result == vk::Result::eErrorOutOfDateKHR) {
349+
if (acq_result == vk::Result::eSuboptimalKHR) {
350+
is_rotated_ = true;
351+
return AcquireResult{true /* out of date */};
352+
}
353+
354+
if (acq_result == vk::Result::eErrorOutOfDateKHR) {
343355
return AcquireResult{true /* out of date */};
344356
}
345357

@@ -448,6 +460,10 @@ bool SwapchainImplVK::Present(const std::shared_ptr<SwapchainImageVK>& image,
448460
// successfully.
449461
[[fallthrough]];
450462
case vk::Result::eSuccess:
463+
is_rotated_ = false;
464+
return true;
465+
case vk::Result::eSuboptimalKHR:
466+
is_rotated_ = true;
451467
return true;
452468
default:
453469
VALIDATION_LOG << "Could not present queue: " << vk::to_string(result);

impeller/renderer/backend/vulkan/swapchain_impl_vk.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class SwapchainImplVK final
3131
static std::shared_ptr<SwapchainImplVK> Create(
3232
const std::shared_ptr<Context>& context,
3333
vk::UniqueSurfaceKHR surface,
34+
bool was_rotated,
3435
vk::SwapchainKHR old_swapchain = VK_NULL_HANDLE);
3536

3637
~SwapchainImplVK();
@@ -47,6 +48,8 @@ class SwapchainImplVK final
4748
: surface(std::move(p_surface)) {}
4849
};
4950

51+
bool GetIsRotated() const { return is_rotated_; }
52+
5053
AcquireResult AcquireNextDrawable();
5154

5255
vk::Format GetSurfaceFormat() const;
@@ -66,8 +69,12 @@ class SwapchainImplVK final
6669
size_t current_frame_ = 0u;
6770
bool is_valid_ = false;
6871

72+
bool was_rotated_ = false;
73+
bool is_rotated_ = false;
74+
6975
SwapchainImplVK(const std::shared_ptr<Context>& context,
7076
vk::UniqueSurfaceKHR surface,
77+
bool was_rotated,
7178
vk::SwapchainKHR old_swapchain);
7279

7380
bool Present(const std::shared_ptr<SwapchainImageVK>& image, uint32_t index);

impeller/renderer/backend/vulkan/swapchain_vk.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ namespace impeller {
1212
std::shared_ptr<SwapchainVK> SwapchainVK::Create(
1313
const std::shared_ptr<Context>& context,
1414
vk::UniqueSurfaceKHR surface) {
15-
auto impl = SwapchainImplVK::Create(context, std::move(surface));
15+
auto impl = SwapchainImplVK::Create(context, std::move(surface),
16+
/*was_rotated=*/false);
1617
if (!impl || !impl->IsValid()) {
1718
return nullptr;
1819
}
@@ -45,10 +46,12 @@ std::unique_ptr<Surface> SwapchainVK::AcquireNextDrawable() {
4546
// This swapchain implementation indicates that it is out of date. Tear it
4647
// down and make a new one.
4748
auto context = impl_->GetContext();
49+
auto was_rotated = impl_->GetIsRotated();
4850
auto [surface, old_swapchain] = impl_->DestroySwapchain();
4951

5052
auto new_impl = SwapchainImplVK::Create(context, //
5153
std::move(surface), //
54+
was_rotated, //
5255
*old_swapchain //
5356
);
5457
if (!new_impl || !new_impl->IsValid()) {

0 commit comments

Comments
 (0)