Cache VkFramebuffers
It seems that creation of VkFramebuffers is more expensive than expected
on mobile devices, so this introduces a framebuffer cache that mimics
the existing Vulkan Render Pass cache in hopes of reducing that
overhead.
Bug: 416088623
Change-Id: I89bc608fc66b088d267c0263f79ed93fcdbe890a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/243636
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Loko Kung <lokokung@google.com>
Commit-Queue: Brandon Jones <bajones@chromium.org>
diff --git a/src/dawn/native/BUILD.gn b/src/dawn/native/BUILD.gn
index 6b7226d..e5d23d4 100644
--- a/src/dawn/native/BUILD.gn
+++ b/src/dawn/native/BUILD.gn
@@ -836,6 +836,8 @@
"vulkan/FencedDeleter.cpp",
"vulkan/FencedDeleter.h",
"vulkan/Forward.h",
+ "vulkan/FramebufferCache.cpp",
+ "vulkan/FramebufferCache.h",
"vulkan/PhysicalDeviceVk.cpp",
"vulkan/PhysicalDeviceVk.h",
"vulkan/PipelineCacheVk.cpp",
diff --git a/src/dawn/native/CMakeLists.txt b/src/dawn/native/CMakeLists.txt
index 1b69194..b49ffc9 100644
--- a/src/dawn/native/CMakeLists.txt
+++ b/src/dawn/native/CMakeLists.txt
@@ -708,6 +708,7 @@
"vulkan/ExternalHandle.h"
"vulkan/FencedDeleter.h"
"vulkan/Forward.h"
+ "vulkan/FramebufferCache.h"
"vulkan/PhysicalDeviceVk.h"
"vulkan/PipelineVk.h"
"vulkan/PipelineCacheVk.h"
@@ -749,6 +750,7 @@
"vulkan/DescriptorSetAllocator.cpp"
"vulkan/DeviceVk.cpp"
"vulkan/FencedDeleter.cpp"
+ "vulkan/FramebufferCache.cpp"
"vulkan/PhysicalDeviceVk.cpp"
"vulkan/PipelineVk.cpp"
"vulkan/PipelineCacheVk.cpp"
diff --git a/src/dawn/native/Toggles.cpp b/src/dawn/native/Toggles.cpp
index 21bd277..5fe3040 100644
--- a/src/dawn/native/Toggles.cpp
+++ b/src/dawn/native/Toggles.cpp
@@ -659,6 +659,12 @@
"Compute the range of the index with Integer Range Analysis in the robustness transform and "
"skip doing index clamping when the out of bound access cannot happen.",
"https://crbug.com/348701956", ToggleStage::Device}},
+ {Toggle::VulkanDisableFramebufferCache,
+ {"vulkan_disable_framebuffer_cache",
+ "Prevents caching of VkFramebuffer objects. When active a new framebuffer will be created "
+ "for every render pass. Enabled by default on Qualcomm GPUs, which have issues with "
+ "framebuffer reuse.",
+ "https://crbug.com/416088623", ToggleStage::Device}},
{Toggle::NoWorkaroundSampleMaskBecomesZeroForAllButLastColorTarget,
{"no_workaround_sample_mask_becomes_zero_for_all_but_last_color_target",
"MacOS 12.0+ Intel has a bug where the sample mask is only applied for the last color "
diff --git a/src/dawn/native/Toggles.h b/src/dawn/native/Toggles.h
index e2ea5c6..fa3a385 100644
--- a/src/dawn/native/Toggles.h
+++ b/src/dawn/native/Toggles.h
@@ -156,6 +156,7 @@
VulkanDirectVariableAccessTransformHandle,
VulkanAddWorkToEmptyResolvePass,
EnableIntegerRangeAnalysisInRobustness,
+ VulkanDisableFramebufferCache,
// Unresolved issues.
NoWorkaroundSampleMaskBecomesZeroForAllButLastColorTarget,
diff --git a/src/dawn/native/vulkan/CommandBufferVk.cpp b/src/dawn/native/vulkan/CommandBufferVk.cpp
index 25539fe..c02b390 100644
--- a/src/dawn/native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn/native/vulkan/CommandBufferVk.cpp
@@ -45,6 +45,7 @@
#include "dawn/native/vulkan/ComputePipelineVk.h"
#include "dawn/native/vulkan/DeviceVk.h"
#include "dawn/native/vulkan/FencedDeleter.h"
+#include "dawn/native/vulkan/FramebufferCache.h"
#include "dawn/native/vulkan/PhysicalDeviceVk.h"
#include "dawn/native/vulkan/PipelineLayoutVk.h"
#include "dawn/native/vulkan/QuerySetVk.h"
@@ -452,15 +453,15 @@
renderPassVK = renderPassInfo.renderPass;
}
- // Create a framebuffer that will be used once for the render pass and gather the clear
- // values for the attachments at the same time.
+ // Query a framebuffer from the cache and gather the clear values for the attachments at the
+ // same time.
+ FramebufferCacheQuery framebufferQuery;
std::array<VkClearValue, kMaxColorAttachments + 1> clearValues;
VkFramebuffer framebuffer = VK_NULL_HANDLE;
- uint32_t attachmentCount = 0;
{
- // Fill in the attachment info that will be chained in the framebuffer create info.
- std::array<VkImageView, kMaxColorAttachments * 2 + 1> attachments;
+ framebufferQuery.SetRenderPass(renderPassVK, renderPass->width, renderPass->height);
+ // Fill in the attachment info that will be chained in the framebuffer create info.
for (auto i : renderPass->attachmentState->GetColorAttachmentsMask()) {
auto& attachmentInfo = renderPass->colorAttachments[i];
TextureView* view = ToBackend(attachmentInfo.view.Get());
@@ -468,13 +469,14 @@
continue;
}
+ uint32_t attachmentIndex;
if (view->GetDimension() == wgpu::TextureViewDimension::e3D) {
VkImageView handleFor2DViewOn3D;
DAWN_TRY_ASSIGN(handleFor2DViewOn3D,
view->GetOrCreate2DViewOn3D(attachmentInfo.depthSlice));
- attachments[attachmentCount] = handleFor2DViewOn3D;
+ attachmentIndex = framebufferQuery.AddAttachment(handleFor2DViewOn3D);
} else {
- attachments[attachmentCount] = view->GetHandle();
+ attachmentIndex = framebufferQuery.AddAttachment(view->GetHandle());
}
switch (view->GetFormat().GetAspectInfo(Aspect::Color).baseType) {
@@ -482,7 +484,7 @@
const std::array<float, 4> appliedClearColor =
ConvertToFloatColor(attachmentInfo.clearColor);
for (uint32_t j = 0; j < 4; ++j) {
- clearValues[attachmentCount].color.float32[j] = appliedClearColor[j];
+ clearValues[attachmentIndex].color.float32[j] = appliedClearColor[j];
}
break;
}
@@ -490,7 +492,7 @@
const std::array<uint32_t, 4> appliedClearColor =
ConvertToUnsignedIntegerColor(attachmentInfo.clearColor);
for (uint32_t j = 0; j < 4; ++j) {
- clearValues[attachmentCount].color.uint32[j] = appliedClearColor[j];
+ clearValues[attachmentIndex].color.uint32[j] = appliedClearColor[j];
}
break;
}
@@ -498,55 +500,52 @@
const std::array<int32_t, 4> appliedClearColor =
ConvertToSignedIntegerColor(attachmentInfo.clearColor);
for (uint32_t j = 0; j < 4; ++j) {
- clearValues[attachmentCount].color.int32[j] = appliedClearColor[j];
+ clearValues[attachmentIndex].color.int32[j] = appliedClearColor[j];
}
break;
}
}
- attachmentCount++;
}
if (renderPass->attachmentState->HasDepthStencilAttachment()) {
auto& attachmentInfo = renderPass->depthStencilAttachment;
TextureView* view = ToBackend(attachmentInfo.view.Get());
- attachments[attachmentCount] = view->GetHandle();
+ uint32_t attachmentIndex = framebufferQuery.AddAttachment(view->GetHandle());
- clearValues[attachmentCount].depthStencil.depth = attachmentInfo.clearDepth;
- clearValues[attachmentCount].depthStencil.stencil = attachmentInfo.clearStencil;
-
- attachmentCount++;
+ clearValues[attachmentIndex].depthStencil.depth = attachmentInfo.clearDepth;
+ clearValues[attachmentIndex].depthStencil.stencil = attachmentInfo.clearStencil;
}
for (auto i : renderPass->attachmentState->GetColorAttachmentsMask()) {
if (renderPass->colorAttachments[i].resolveTarget != nullptr) {
TextureView* view = ToBackend(renderPass->colorAttachments[i].resolveTarget.Get());
-
- attachments[attachmentCount] = view->GetHandle();
-
- attachmentCount++;
+ framebufferQuery.AddAttachment(view->GetHandle());
}
}
- // Chain attachments and create the framebuffer
- VkFramebufferCreateInfo createInfo;
- createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
- createInfo.pNext = nullptr;
- createInfo.flags = 0;
- createInfo.renderPass = renderPassVK;
- createInfo.attachmentCount = attachmentCount;
- createInfo.pAttachments = AsVkArray(attachments.data());
- createInfo.width = renderPass->width;
- createInfo.height = renderPass->height;
- createInfo.layers = 1;
+ DAWN_TRY_ASSIGN(framebuffer,
+ device->GetFramebufferCache()->GetOrCreate(
+ framebufferQuery,
+ [&](FramebufferCacheQuery& query) -> ResultOrError<VkFramebuffer> {
+ VkFramebufferCreateInfo createInfo;
+ createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ createInfo.pNext = nullptr;
+ createInfo.flags = 0;
+ createInfo.renderPass = query.renderPass;
+ createInfo.attachmentCount = query.attachmentCount;
+ createInfo.pAttachments = AsVkArray(query.attachments.data());
+ createInfo.width = query.width;
+ createInfo.height = query.height;
+ createInfo.layers = 1;
- DAWN_TRY(CheckVkSuccess(device->fn.CreateFramebuffer(device->GetVkDevice(), &createInfo,
- nullptr, &*framebuffer),
- "CreateFramebuffer"));
-
- // We don't reuse VkFramebuffers so mark the framebuffer for deletion as soon as the
- // commands currently being recorded are finished.
- device->GetFencedDeleter()->DeleteWhenUnused(framebuffer);
+ VkFramebuffer framebuffer;
+ DAWN_TRY(CheckVkSuccess(
+ device->fn.CreateFramebuffer(device->GetVkDevice(), &createInfo,
+ nullptr, &*framebuffer),
+ "CreateFramebuffer"));
+ return framebuffer;
+ }));
}
VkRenderPassBeginInfo beginInfo;
@@ -558,7 +557,7 @@
beginInfo.renderArea.offset.y = 0;
beginInfo.renderArea.extent.width = renderPass->width;
beginInfo.renderArea.extent.height = renderPass->height;
- beginInfo.clearValueCount = attachmentCount;
+ beginInfo.clearValueCount = framebufferQuery.attachmentCount;
beginInfo.pClearValues = clearValues.data();
if (renderPass->attachmentState->GetExpandResolveInfo().attachmentsToExpandResolve.any()) {
diff --git a/src/dawn/native/vulkan/DeviceVk.cpp b/src/dawn/native/vulkan/DeviceVk.cpp
index ca84294..8ed06fe 100644
--- a/src/dawn/native/vulkan/DeviceVk.cpp
+++ b/src/dawn/native/vulkan/DeviceVk.cpp
@@ -50,6 +50,7 @@
#include "dawn/native/vulkan/CommandBufferVk.h"
#include "dawn/native/vulkan/ComputePipelineVk.h"
#include "dawn/native/vulkan/FencedDeleter.h"
+#include "dawn/native/vulkan/FramebufferCache.h"
#include "dawn/native/vulkan/PhysicalDeviceVk.h"
#include "dawn/native/vulkan/PipelineCacheVk.h"
#include "dawn/native/vulkan/PipelineLayoutVk.h"
@@ -141,6 +142,10 @@
functions->CmdDrawIndexedIndirect = NoopDrawFunction<PFN_vkCmdDrawIndexedIndirect>::Fun;
}
+ mFramebufferCache = std::make_unique<FramebufferCache>(
+ this, IsToggleEnabled(Toggle::VulkanDisableFramebufferCache)
+ ? 0
+ : FramebufferCache::kDefaultCapacity);
mRenderPassCache = std::make_unique<RenderPassCache>(this);
VkDeviceSize heapBlockSize =
@@ -388,6 +393,10 @@
return *mDeleter;
}
+FramebufferCache* Device::GetFramebufferCache() const {
+ return mFramebufferCache.get();
+}
+
RenderPassCache* Device::GetRenderPassCache() const {
return mRenderPassCache.get();
}
@@ -944,8 +953,9 @@
// Allow recycled memory to be deleted.
GetResourceMemoryAllocator()->FreeRecycledMemory();
- // The VkRenderPasses in the cache can be destroyed immediately since all commands referring
- // to them are guaranteed to be finished executing.
+ // The VkFramebuffers and VkRenderPasses in the cache can be destroyed immediately since all
+ // commands referring to them are guaranteed to be finished executing.
+ mFramebufferCache = nullptr;
mRenderPassCache = nullptr;
// Destroy the VkPipelineCache before VkDevice.
diff --git a/src/dawn/native/vulkan/DeviceVk.h b/src/dawn/native/vulkan/DeviceVk.h
index 547e362..690e9e9 100644
--- a/src/dawn/native/vulkan/DeviceVk.h
+++ b/src/dawn/native/vulkan/DeviceVk.h
@@ -53,6 +53,7 @@
class BufferUploader;
class FencedDeleter;
+class FramebufferCache;
class RenderPassCache;
class ResourceMemoryAllocator;
@@ -76,6 +77,7 @@
uint32_t GetGraphicsQueueFamily() const;
MutexProtected<FencedDeleter>& GetFencedDeleter() const;
+ FramebufferCache* GetFramebufferCache() const;
RenderPassCache* GetRenderPassCache() const;
MutexProtected<ResourceMemoryAllocator>& GetResourceMemoryAllocator() const;
external_semaphore::Service* GetExternalSemaphoreService() const;
@@ -201,6 +203,7 @@
mDescriptorAllocatorsPendingDeallocation;
std::unique_ptr<MutexProtected<FencedDeleter>> mDeleter;
std::unique_ptr<MutexProtected<ResourceMemoryAllocator>> mResourceMemoryAllocator;
+ std::unique_ptr<FramebufferCache> mFramebufferCache;
std::unique_ptr<RenderPassCache> mRenderPassCache;
std::unique_ptr<external_memory::Service> mExternalMemoryService;
diff --git a/src/dawn/native/vulkan/FramebufferCache.cpp b/src/dawn/native/vulkan/FramebufferCache.cpp
new file mode 100644
index 0000000..58bbb73
--- /dev/null
+++ b/src/dawn/native/vulkan/FramebufferCache.cpp
@@ -0,0 +1,100 @@
+// Copyright 2025 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "dawn/native/vulkan/FramebufferCache.h"
+
+#include "absl/container/inlined_vector.h"
+#include "dawn/common/HashUtils.h"
+#include "dawn/common/Range.h"
+#include "dawn/common/vulkan_platform.h"
+#include "dawn/native/vulkan/DeviceVk.h"
+#include "dawn/native/vulkan/FencedDeleter.h"
+#include "dawn/native/vulkan/VulkanError.h"
+
+namespace dawn::native::vulkan {
+
+// FramebufferCacheQuery
+
+void FramebufferCacheQuery::SetRenderPass(VkRenderPass pass,
+ uint32_t passWidth,
+ uint32_t passHeight) {
+ renderPass = pass;
+ width = passWidth;
+ height = passHeight;
+}
+
+uint32_t FramebufferCacheQuery::AddAttachment(VkImageView attachment) {
+ attachments[attachmentCount] = attachment;
+ return attachmentCount++;
+}
+
+// FramebufferCache
+
+FramebufferCache::FramebufferCache(Device* device, size_t capacity)
+ : FramebufferCache::Base(capacity), mDevice(device) {}
+
+FramebufferCache::~FramebufferCache() {
+ mCache.Use([this](auto cache) {
+ for (auto [_, framebuffer] : cache->list) {
+ mDevice->fn.DestroyFramebuffer(mDevice->GetVkDevice(), framebuffer, nullptr);
+ }
+ });
+}
+
+void FramebufferCache::EvictedFromCache(const VkFramebuffer& framebuffer) {
+ mDevice->GetFencedDeleter()->DeleteWhenUnused(framebuffer);
+}
+
+size_t FramebufferCacheFuncs::operator()(const FramebufferCacheQuery& query) const {
+ size_t hash = Hash(query.renderPass.GetHandle());
+
+ HashCombine(&hash, query.width, query.height, query.attachmentCount);
+
+ for (uint32_t i = 0; i < query.attachmentCount; ++i) {
+ HashCombine(&hash, query.attachments[i].GetHandle());
+ }
+
+ return hash;
+}
+
+bool FramebufferCacheFuncs::operator()(const FramebufferCacheQuery& a,
+ const FramebufferCacheQuery& b) const {
+ if (a.renderPass != b.renderPass || a.width != b.width || a.height != b.height ||
+ a.attachmentCount != b.attachmentCount) {
+ return false;
+ }
+
+ for (uint32_t i = 0; i < a.attachmentCount; ++i) {
+ if (a.attachments[i] != b.attachments[i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace dawn::native::vulkan
diff --git a/src/dawn/native/vulkan/FramebufferCache.h b/src/dawn/native/vulkan/FramebufferCache.h
new file mode 100644
index 0000000..8944004
--- /dev/null
+++ b/src/dawn/native/vulkan/FramebufferCache.h
@@ -0,0 +1,93 @@
+// Copyright 2025 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_DAWN_NATIVE_VULKAN_FRAMEBUFFERCACHE_H_
+#define SRC_DAWN_NATIVE_VULKAN_FRAMEBUFFERCACHE_H_
+
+#include <array>
+#include <list>
+#include <mutex>
+#include <utility>
+
+#include "absl/container/flat_hash_map.h"
+#include "dawn/common/Constants.h"
+#include "dawn/common/LRUCache.h"
+#include "dawn/common/vulkan_platform.h"
+#include "dawn/native/Error.h"
+#include "dawn/native/dawn_platform.h"
+#include "partition_alloc/pointers/raw_ptr.h"
+
+namespace dawn::native::vulkan {
+
+class Device;
+
+// A key to query the FramebufferCache
+struct FramebufferCacheQuery {
+ // Use these helpers to build the query, they make sure all relevant data is initialized and
+ // masks set.
+ void SetRenderPass(VkRenderPass pass, uint32_t passWidth, uint32_t passHeight);
+ uint32_t AddAttachment(VkImageView attachment);
+
+ VkRenderPass renderPass;
+ uint32_t width;
+ uint32_t height;
+
+ std::array<VkImageView, kMaxColorAttachments * 2 + 1> attachments;
+ uint32_t attachmentCount = 0;
+};
+
+// Implements the functors necessary for to use RenderPassCacheQueries as absl::flat_hash_map keys.
+struct FramebufferCacheFuncs {
+ size_t operator()(const FramebufferCacheQuery& query) const;
+ bool operator()(const FramebufferCacheQuery& a, const FramebufferCacheQuery& b) const;
+};
+
+// A LRU Cache of VkFramebuffers so that we reduce the need to re-create framebuffers for every
+// render pass. We always arrange the order of attachments in "color-depthstencil-resolve" order
+// when creating render pass and framebuffer so that we can always make sure the order of
+// attachments in the rendering pipeline matches the one of the framebuffer.
+// All the operations on FramebufferCache are guaranteed to be thread-safe.
+class FramebufferCache final
+ : public LRUCache<FramebufferCacheQuery, VkFramebuffer, ErrorData, FramebufferCacheFuncs> {
+ using Base = LRUCache<FramebufferCacheQuery, VkFramebuffer, ErrorData, FramebufferCacheFuncs>;
+
+ public:
+ static const size_t kDefaultCapacity = 32;
+ explicit FramebufferCache(Device* device, size_t capacity = kDefaultCapacity);
+ ~FramebufferCache() override;
+
+ void EvictedFromCache(const VkFramebuffer& value) override;
+
+ private:
+ // We use a raw pointer to the device here because the cache is always owned by the device
+ // and hence should always be valid.
+ raw_ptr<Device> mDevice;
+};
+
+} // namespace dawn::native::vulkan
+
+#endif // SRC_DAWN_NATIVE_VULKAN_FRAMEBUFFERCACHE_H_
diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
index 5e28bc7..8ae8bef 100644
--- a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
+++ b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
@@ -817,6 +817,9 @@
// chromium:407109052: Qualcomm devices have a bug where the spirv extended op NClamp
// modifies other components of a vector when one of the components is nan.
deviceToggles->Default(Toggle::VulkanScalarizeClampBuiltin, true);
+
+ // chromium:416088623: Some Qualcomm devices have issues with reusing VkFramebuffers.
+ deviceToggles->Default(Toggle::VulkanDisableFramebufferCache, true);
}
if (IsAndroidARM()) {
@@ -842,6 +845,11 @@
deviceToggles->Default(Toggle::IgnoreImportedAHardwareBufferVulkanImageSize, true);
}
+ if (IsAndroidSwiftshader()) {
+ // Disable framebuffer caching to avoid timeout errors seen on some Android emulators.
+ deviceToggles->Default(Toggle::VulkanDisableFramebufferCache, true);
+ }
+
if (IsIntelMesa() && gpu_info::IsIntelGen12LP(GetVendorId(), GetDeviceId())) {
// dawn:1688: Intel Mesa driver has a bug about reusing the VkDeviceMemory that was
// previously bound to a 2D VkImage. To work around that bug we have to disable the resource
@@ -1033,6 +1041,14 @@
return false;
}
+bool PhysicalDevice::IsAndroidSwiftshader() const {
+#if DAWN_PLATFORM_IS(ANDROID)
+ return gpu_info::IsGoogle(GetVendorId());
+#else
+ return false;
+#endif
+}
+
uint32_t PhysicalDevice::FindDefaultComputeSubgroupSize() const {
if (!mDeviceInfo.HasExt(DeviceExt::SubgroupSizeControl)) {
return 0;
diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.h b/src/dawn/native/vulkan/PhysicalDeviceVk.h
index 0d15851..02d6a7f 100644
--- a/src/dawn/native/vulkan/PhysicalDeviceVk.h
+++ b/src/dawn/native/vulkan/PhysicalDeviceVk.h
@@ -66,6 +66,7 @@
bool IsAndroidSamsung() const;
bool IsIntelMesa() const;
bool IsAndroidHuawei() const;
+ bool IsAndroidSwiftshader() const;
uint32_t GetDefaultComputeSubgroupSize() const;