[Impeller] when mips are disabled, also disable from sampler options. (#161765)

If we have disabled mipmap generation on a platform due to GPU driver
bugs, make sure that all sampling options used declare that only the
base mip level should be read. Otherwise we can end up sampling from
unpopulated mip levels.
This commit is contained in:
Jonah Williams 2025-01-17 16:22:05 -08:00 committed by GitHub
parent 5e24ac89bc
commit fe257cbf5a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 61 additions and 4 deletions

View File

@ -24,6 +24,7 @@ impeller_component("vulkan_unittests") {
"test/mock_vulkan.cc",
"test/mock_vulkan.h",
"test/mock_vulkan_unittests.cc",
"test/sampler_library_vk_unittests.cc",
"test/swapchain_unittests.cc",
]
deps = [

View File

@ -464,6 +464,7 @@ void ContextVK::Setup(Settings settings) {
std::make_unique<DriverInfoVK>(device_holder->physical_device);
workarounds_ = GetWorkaroundsFromDriverInfo(*driver_info);
caps->ApplyWorkarounds(workarounds_);
sampler_library->ApplyWorkarounds(workarounds_);
device_holder_ = std::move(device_holder);
idle_waiter_vk_ = std::make_shared<IdleWaiterVK>(device_holder_);

View File

@ -4,6 +4,7 @@
#include "impeller/renderer/backend/vulkan/sampler_library_vk.h"
#include "impeller/core/formats.h"
#include "impeller/renderer/backend/vulkan/sampler_vk.h"
namespace impeller {
@ -14,9 +15,18 @@ SamplerLibraryVK::SamplerLibraryVK(
SamplerLibraryVK::~SamplerLibraryVK() = default;
void SamplerLibraryVK::ApplyWorkarounds(const WorkaroundsVK& workarounds) {
mips_disabled_workaround_ = workarounds.broken_mipmap_generation;
}
raw_ptr<const Sampler> SamplerLibraryVK::GetSampler(
const SamplerDescriptor& desc) {
uint64_t p_key = SamplerDescriptor::ToKey(desc);
SamplerDescriptor desc_copy = desc;
if (mips_disabled_workaround_) {
desc_copy.mip_filter = MipFilter::kBase;
}
uint64_t p_key = SamplerDescriptor::ToKey(desc_copy);
for (const auto& [key, value] : samplers_) {
if (key == p_key) {
return raw_ptr(value);
@ -27,7 +37,8 @@ raw_ptr<const Sampler> SamplerLibraryVK::GetSampler(
return raw_ptr<const Sampler>(nullptr);
}
samplers_.push_back(std::make_pair(
p_key, std::make_shared<SamplerVK>(device_holder->GetDevice(), desc)));
p_key,
std::make_shared<SamplerVK>(device_holder->GetDevice(), desc_copy)));
return raw_ptr(samplers_.back().second);
}

View File

@ -9,6 +9,7 @@
#include "impeller/core/sampler.h"
#include "impeller/core/sampler_descriptor.h"
#include "impeller/renderer/backend/vulkan/device_holder_vk.h"
#include "impeller/renderer/backend/vulkan/workarounds_vk.h"
#include "impeller/renderer/sampler_library.h"
namespace impeller {
@ -20,13 +21,16 @@ class SamplerLibraryVK final
// |SamplerLibrary|
~SamplerLibraryVK() override;
explicit SamplerLibraryVK(const std::weak_ptr<DeviceHolderVK>& device_holder);
void ApplyWorkarounds(const WorkaroundsVK& workarounds);
private:
friend class ContextVK;
std::weak_ptr<DeviceHolderVK> device_holder_;
std::vector<std::pair<uint64_t, std::shared_ptr<const Sampler>>> samplers_;
explicit SamplerLibraryVK(const std::weak_ptr<DeviceHolderVK>& device_holder);
bool mips_disabled_workaround_ = false;
// |SamplerLibrary|
raw_ptr<const Sampler> GetSampler(

View File

@ -37,6 +37,7 @@ class SamplerVK final : public Sampler, public BackendCast<SamplerVK, Sampler> {
const vk::Device device_;
SharedHandleVK<vk::Sampler> sampler_;
std::shared_ptr<YUVConversionVK> yuv_conversion_;
bool mips_disabled_workaround_ = false;
bool is_valid_ = false;
SamplerVK(const SamplerVK&) = delete;

View File

@ -0,0 +1,39 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include "flutter/testing/testing.h" // IWYU pragma: keep
#include "gtest/gtest.h"
#include "impeller/core/formats.h"
#include "impeller/core/sampler_descriptor.h"
#include "impeller/renderer/backend/vulkan/command_pool_vk.h"
#include "impeller/renderer/backend/vulkan/sampler_library_vk.h"
#include "impeller/renderer/backend/vulkan/test/mock_vulkan.h"
#include "impeller/renderer/backend/vulkan/workarounds_vk.h"
namespace impeller {
namespace testing {
TEST(SamplerLibraryVK, WorkaroundsCanDisableReadingFromMipLevels) {
auto const context = MockVulkanContextBuilder().Build();
auto library_vk =
std::make_shared<SamplerLibraryVK>(context->GetDeviceHolder());
std::shared_ptr<SamplerLibrary> library = library_vk;
SamplerDescriptor desc;
desc.mip_filter = MipFilter::kLinear;
auto sampler = library->GetSampler(desc);
EXPECT_EQ(sampler->GetDescriptor().mip_filter, MipFilter::kLinear);
// Apply mips disabled workaround.
library_vk->ApplyWorkarounds(WorkaroundsVK{.broken_mipmap_generation = true});
sampler = library->GetSampler(desc);
EXPECT_EQ(sampler->GetDescriptor().mip_filter, MipFilter::kBase);
}
} // namespace testing
} // namespace impeller