From b6b5f80830969c54342f82d5f53a8e17bf6fa941 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 28 Jun 2023 12:52:54 -0700 Subject: [PATCH 01/16] [Impeller] allocate fewer textures in dedicated memory. --- .../renderer/backend/vulkan/allocator_vk.cc | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index be0674f82a9ec..6611d35cc5894 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -15,6 +15,11 @@ namespace impeller { +// Maximum size to use VMA image suballocation. Any allocation greater than or +// equal to this value will use a dedicated VkDeviceMemory. +constexpr size_t kImageSizeThresholdForDedicatedMemoryAllocation = + 4 * 1024 * 1024; + AllocatorVK::AllocatorVK(std::weak_ptr context, uint32_t vulkan_api_version, const vk::PhysicalDevice& physical_device, @@ -184,19 +189,25 @@ static constexpr VkMemoryPropertyFlags ToVKMemoryPropertyFlags( } static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode, - bool is_texture) { + bool is_texture, + size_t size) { VmaAllocationCreateFlags flags = 0; switch (mode) { case StorageMode::kHostVisible: if (is_texture) { - flags |= {}; + if (size >= kImageSizeThresholdForDedicatedMemoryAllocation) { + flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; + } else { + flags |= {}; + } } else { flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT; } return flags; case StorageMode::kDevicePrivate: - if (is_texture) { + if (is_texture && + size >= kImageSizeThresholdForDedicatedMemoryAllocation) { flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; } return flags; @@ -234,7 +245,8 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { alloc_nfo.usage = ToVMAMemoryUsage(); alloc_nfo.preferredFlags = ToVKMemoryPropertyFlags(desc.storage_mode); - alloc_nfo.flags = ToVmaAllocationCreateFlags(desc.storage_mode, true); + alloc_nfo.flags = ToVmaAllocationCreateFlags( + desc.storage_mode, true, desc.GetByteSizeOfBaseMipLevel()); auto create_info_native = static_cast(image_info); @@ -366,7 +378,8 @@ std::shared_ptr AllocatorVK::OnCreateBuffer( VmaAllocationCreateInfo allocation_info = {}; allocation_info.usage = ToVMAMemoryUsage(); allocation_info.preferredFlags = ToVKMemoryPropertyFlags(desc.storage_mode); - allocation_info.flags = ToVmaAllocationCreateFlags(desc.storage_mode, false); + allocation_info.flags = ToVmaAllocationCreateFlags( + desc.storage_mode, /*is_texture=*/false, desc.size); VkBuffer buffer = {}; VmaAllocation buffer_allocation = {}; From 0798fe19ff38cacda010f38b785152dadd7bf119 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 28 Jun 2023 12:55:00 -0700 Subject: [PATCH 02/16] Update allocator_vk.cc --- impeller/renderer/backend/vulkan/allocator_vk.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index 6611d35cc5894..5e1030e35a75c 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -246,7 +246,7 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { alloc_nfo.usage = ToVMAMemoryUsage(); alloc_nfo.preferredFlags = ToVKMemoryPropertyFlags(desc.storage_mode); alloc_nfo.flags = ToVmaAllocationCreateFlags( - desc.storage_mode, true, desc.GetByteSizeOfBaseMipLevel()); + desc.storage_mode, /*is_texture=*/true, desc.GetByteSizeOfBaseMipLevel()); auto create_info_native = static_cast(image_info); From 4826724fda7e369faffb1a272a02d4d3662de3b7 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 28 Jun 2023 12:55:33 -0700 Subject: [PATCH 03/16] format --- impeller/renderer/backend/vulkan/allocator_vk.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index 5e1030e35a75c..63567f928e75e 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -245,8 +245,9 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { alloc_nfo.usage = ToVMAMemoryUsage(); alloc_nfo.preferredFlags = ToVKMemoryPropertyFlags(desc.storage_mode); - alloc_nfo.flags = ToVmaAllocationCreateFlags( - desc.storage_mode, /*is_texture=*/true, desc.GetByteSizeOfBaseMipLevel()); + alloc_nfo.flags = + ToVmaAllocationCreateFlags(desc.storage_mode, /*is_texture=*/true, + desc.GetByteSizeOfBaseMipLevel()); auto create_info_native = static_cast(image_info); From 75c4015a373857eca6c4750cfebb516ecacd7d5b Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 28 Jun 2023 17:42:56 -0700 Subject: [PATCH 04/16] [Impeller] use separate pools for image upload work. --- impeller/core/device_buffer_descriptor.h | 1 + impeller/core/formats.h | 7 ++ impeller/core/texture_descriptor.h | 1 + .../renderer/backend/vulkan/allocator_vk.cc | 109 +++++++++++++++++- .../renderer/backend/vulkan/allocator_vk.h | 4 + lib/ui/painting/image_decoder_impeller.cc | 2 + 6 files changed, 118 insertions(+), 6 deletions(-) diff --git a/impeller/core/device_buffer_descriptor.h b/impeller/core/device_buffer_descriptor.h index 976b8f7b0acac..7352712b89404 100644 --- a/impeller/core/device_buffer_descriptor.h +++ b/impeller/core/device_buffer_descriptor.h @@ -13,6 +13,7 @@ namespace impeller { struct DeviceBufferDescriptor { StorageMode storage_mode = StorageMode::kDeviceTransient; size_t size = 0u; + UsageHint usage_hint = UsageHint::kRasterWorkload; }; } // namespace impeller diff --git a/impeller/core/formats.h b/impeller/core/formats.h index ff031d96008b1..4f0a642de1bc3 100644 --- a/impeller/core/formats.h +++ b/impeller/core/formats.h @@ -293,6 +293,13 @@ constexpr const char* TextureUsageToString(TextureUsage usage) { std::string TextureUsageMaskToString(TextureUsageMask mask); +enum class UsageHint { + /// @brief Texture or buffer is being used during the raster workload. + kRasterWorkload, + /// @brief Texture or buffer is being used as part of an async image upload. + kImageUpload, +}; + enum class TextureIntent { kUploadFromHost, kRenderToTexture, diff --git a/impeller/core/texture_descriptor.h b/impeller/core/texture_descriptor.h index 7d99d20408da5..32ccd0098f175 100644 --- a/impeller/core/texture_descriptor.h +++ b/impeller/core/texture_descriptor.h @@ -46,6 +46,7 @@ struct TextureDescriptor { static_cast(TextureUsage::kShaderRead); SampleCount sample_count = SampleCount::kCount1; CompressionType compression_type = CompressionType::kLossless; + UsageHint usage_hint = UsageHint::kRasterWorkload; constexpr size_t GetByteSizeOfBaseMipLevel() const { if (!IsValid()) { diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index 63567f928e75e..fea849a4154af 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -20,6 +20,38 @@ namespace impeller { constexpr size_t kImageSizeThresholdForDedicatedMemoryAllocation = 4 * 1024 * 1024; +static bool CreateBufferPool(VmaAllocator allocator, VmaPool* pool) { + vk::BufferCreateInfo buffer_info; + buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer | + vk::BufferUsageFlagBits::eIndexBuffer | + vk::BufferUsageFlagBits::eUniformBuffer | + vk::BufferUsageFlagBits::eStorageBuffer | + vk::BufferUsageFlagBits::eTransferSrc | + vk::BufferUsageFlagBits::eTransferDst; + buffer_info.size = 1u; // doesn't matter + buffer_info.sharingMode = vk::SharingMode::eExclusive; + auto buffer_info_native = + static_cast(buffer_info); + + VmaAllocationCreateInfo sampleAllocCreateInfo = {}; + sampleAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; + + uint32_t memTypeIndex; + VkResult res = vmaFindMemoryTypeIndexForBufferInfo( + allocator, &buffer_info_native, &sampleAllocCreateInfo, &memTypeIndex); + + VmaPoolCreateInfo poolCreateInfo = {}; + poolCreateInfo.memoryTypeIndex = memTypeIndex; + poolCreateInfo.blockSize = 128ull * 1024 * 1024; + + auto result = vk::Result{vmaCreatePool(allocator, &poolCreateInfo, pool)}; + if (result != vk::Result::eSuccess) { + VALIDATION_LOG << "Could not create memory allocator"; + return false; + } + return true; +} + AllocatorVK::AllocatorVK(std::weak_ptr context, uint32_t vulkan_api_version, const vk::PhysicalDevice& physical_device, @@ -95,12 +127,67 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, VALIDATION_LOG << "Could not create memory allocator"; return; } + if (!CreateBufferPool(allocator, &raster_buffer_pool_)) { + return; + } + if (!CreateBufferPool(allocator, &image_upload_buffer_pool_)) { + return; + } + + { + vk::ImageCreateInfo image_info; + image_info.flags = {}; + image_info.imageType = vk::ImageType::e2D; + image_info.format = vk::Format::eR8G8B8A8Unorm; + image_info.extent = VkExtent3D{1u, 1u, 1u}; + image_info.samples = vk::SampleCountFlagBits::e1; + image_info.mipLevels = 1u; + image_info.arrayLayers = 1u; + image_info.tiling = vk::ImageTiling::eOptimal; + image_info.initialLayout = vk::ImageLayout::eUndefined; + image_info.usage = + vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst; + image_info.sharingMode = vk::SharingMode::eExclusive; + + auto create_info_native = + static_cast(image_info); + + VmaAllocationCreateInfo sampleAllocCreateInfo = {}; + sampleAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; + sampleAllocCreateInfo.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + uint32_t memTypeIndex; + VkResult res = vmaFindMemoryTypeIndexForImageInfo( + allocator, &create_info_native, &sampleAllocCreateInfo, &memTypeIndex); + + // Create a pool that can have at most 2 blocks, 128 MiB each. + VmaPoolCreateInfo poolCreateInfo = {}; + poolCreateInfo.memoryTypeIndex = memTypeIndex; + poolCreateInfo.blockSize = 128ull * 1024 * 1024; + + result = vk::Result{ + vmaCreatePool(allocator, &poolCreateInfo, &image_upload_texture_pool_)}; + if (result != vk::Result::eSuccess) { + VALIDATION_LOG << "Could not create memory allocator"; + return; + } + } + allocator_ = allocator; is_valid_ = true; } AllocatorVK::~AllocatorVK() { if (allocator_) { + if (raster_buffer_pool_) { + ::vmaDestroyPool(allocator_, raster_buffer_pool_); + } + if (image_upload_buffer_pool_) { + ::vmaDestroyPool(allocator_, image_upload_buffer_pool_); + } + if (image_upload_texture_pool_) { + ::vmaDestroyPool(allocator_, image_upload_texture_pool_); + } ::vmaDestroyAllocator(allocator_); } } @@ -221,6 +308,7 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { public: AllocatedTextureSourceVK(const TextureDescriptor& desc, VmaAllocator allocator, + VmaPool pool, vk::Device device) : TextureSourceVK(desc) { vk::ImageCreateInfo image_info; @@ -245,9 +333,14 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { alloc_nfo.usage = ToVMAMemoryUsage(); alloc_nfo.preferredFlags = ToVKMemoryPropertyFlags(desc.storage_mode); - alloc_nfo.flags = - ToVmaAllocationCreateFlags(desc.storage_mode, /*is_texture=*/true, - desc.GetByteSizeOfBaseMipLevel()); + + auto image_upload = desc.usage_hint == UsageHint::kImageUpload; + alloc_nfo.flags = ToVmaAllocationCreateFlags( + desc.storage_mode, /*is_texture=*/true, + image_upload ? 0u : desc.GetByteSizeOfBaseMipLevel()); + if (image_upload) { + alloc_nfo.pool = pool; + } auto create_info_native = static_cast(image_info); @@ -350,9 +443,10 @@ std::shared_ptr AllocatorVK::OnCreateTexture( return nullptr; } auto source = - std::make_shared(desc, // - allocator_, // - device_holder->GetDevice() // + std::make_shared(desc, // + allocator_, // + image_upload_texture_pool_, // + device_holder->GetDevice() // ); if (!source->IsValid()) { return nullptr; @@ -381,6 +475,9 @@ std::shared_ptr AllocatorVK::OnCreateBuffer( allocation_info.preferredFlags = ToVKMemoryPropertyFlags(desc.storage_mode); allocation_info.flags = ToVmaAllocationCreateFlags( desc.storage_mode, /*is_texture=*/false, desc.size); + auto image_upload = desc.usage_hint == UsageHint::kImageUpload; + allocation_info.pool = + image_upload ? image_upload_buffer_pool_ : raster_buffer_pool_; VkBuffer buffer = {}; VmaAllocation buffer_allocation = {}; diff --git a/impeller/renderer/backend/vulkan/allocator_vk.h b/impeller/renderer/backend/vulkan/allocator_vk.h index 64b9ba4c2ac5c..6c8cc4befa101 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.h +++ b/impeller/renderer/backend/vulkan/allocator_vk.h @@ -27,6 +27,10 @@ class AllocatorVK final : public Allocator { fml::RefPtr vk_; VmaAllocator allocator_ = {}; + VmaPool raster_buffer_pool_ = {}; + VmaPool image_upload_buffer_pool_ = {}; + VmaPool image_upload_texture_pool_ = {}; + std::weak_ptr context_; std::weak_ptr device_holder_; ISize max_texture_size_; diff --git a/lib/ui/painting/image_decoder_impeller.cc b/lib/ui/painting/image_decoder_impeller.cc index c0776b0caa35e..02a1d7572e796 100644 --- a/lib/ui/painting/image_decoder_impeller.cc +++ b/lib/ui/painting/image_decoder_impeller.cc @@ -268,6 +268,7 @@ static std::pair, std::string> UnsafeUploadTextureToPrivate( texture_descriptor.size = {image_info.width(), image_info.height()}; texture_descriptor.mip_count = texture_descriptor.size.MipCount(); texture_descriptor.compression_type = impeller::CompressionType::kLossy; + texture_descriptor.usage_hint = impeller::UsageHint::kImageUpload; auto dest_texture = context->GetResourceAllocator()->CreateTexture(texture_descriptor); @@ -527,6 +528,7 @@ bool ImpellerAllocator::allocPixelRef(SkBitmap* bitmap) { descriptor.storage_mode = impeller::StorageMode::kHostVisible; descriptor.size = ((bitmap->height() - 1) * bitmap->rowBytes()) + (bitmap->width() * bitmap->bytesPerPixel()); + descriptor.usage_hint = impeller::UsageHint::kImageUpload; auto device_buffer = allocator_->CreateBuffer(descriptor); From b2a7afc6eb5e8f49dd082a84cb0b2d7d16966d4a Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 29 Jun 2023 09:01:03 -0700 Subject: [PATCH 05/16] wip --- .../renderer/backend/vulkan/allocator_vk.cc | 150 ++++++++++-------- 1 file changed, 84 insertions(+), 66 deletions(-) diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index fea849a4154af..a8512ae722a89 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -20,29 +20,89 @@ namespace impeller { constexpr size_t kImageSizeThresholdForDedicatedMemoryAllocation = 4 * 1024 * 1024; -static bool CreateBufferPool(VmaAllocator allocator, VmaPool* pool) { +static constexpr VkMemoryPropertyFlags ToVKMemoryPropertyFlags( + StorageMode mode) { + switch (mode) { + case StorageMode::kHostVisible: + // See https://github.com/flutter/flutter/issues/128556 . Some devices do + // not have support for coherent host memory so we don't request it here. + return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + case StorageMode::kDevicePrivate: + return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + case StorageMode::kDeviceTransient: + return VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; + } + FML_UNREACHABLE(); +} + +static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode, + bool is_texture, + size_t size) { + VmaAllocationCreateFlags flags = 0; + switch (mode) { + case StorageMode::kHostVisible: + if (is_texture) { + if (size >= kImageSizeThresholdForDedicatedMemoryAllocation) { + flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; + } else { + flags |= {}; + } + } else { + flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; + flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT; + } + return flags; + case StorageMode::kDevicePrivate: + if (is_texture && + size >= kImageSizeThresholdForDedicatedMemoryAllocation) { + flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; + } + return flags; + case StorageMode::kDeviceTransient: + return flags; + } + FML_UNREACHABLE(); +} + +vk::Flags VmaBufferUsageFlags(UsageHint usage) { + switch (usage) { + case UsageHint::kRasterWorkload: + return vk::BufferUsageFlagBits::eVertexBuffer | + vk::BufferUsageFlagBits::eIndexBuffer | + vk::BufferUsageFlagBits::eUniformBuffer | + vk::BufferUsageFlagBits::eStorageBuffer | + vk::BufferUsageFlagBits::eTransferSrc | + vk::BufferUsageFlagBits::eTransferDst; + case UsageHint::kImageUpload: + return vk::BufferUsageFlagBits::eTransferSrc; + } + FML_UNREACHABLE(); +} + +static bool CreateBufferPool(VmaAllocator allocator, + UsageHint usage, + VmaPool* pool) { vk::BufferCreateInfo buffer_info; - buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer | - vk::BufferUsageFlagBits::eIndexBuffer | - vk::BufferUsageFlagBits::eUniformBuffer | - vk::BufferUsageFlagBits::eStorageBuffer | - vk::BufferUsageFlagBits::eTransferSrc | - vk::BufferUsageFlagBits::eTransferDst; + buffer_info.usage = VmaBufferUsageFlags(usage); buffer_info.size = 1u; // doesn't matter buffer_info.sharingMode = vk::SharingMode::eExclusive; auto buffer_info_native = static_cast(buffer_info); - VmaAllocationCreateInfo sampleAllocCreateInfo = {}; - sampleAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; + VmaAllocationCreateInfo allocation_info = {}; + allocation_info.usage = VMA_MEMORY_USAGE_AUTO; + allocation_info.preferredFlags = + ToVKMemoryPropertyFlags(StorageMode::kHostVisible); + allocation_info.flags = + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; uint32_t memTypeIndex; VkResult res = vmaFindMemoryTypeIndexForBufferInfo( - allocator, &buffer_info_native, &sampleAllocCreateInfo, &memTypeIndex); + allocator, &buffer_info_native, &allocation_info, &memTypeIndex); VmaPoolCreateInfo poolCreateInfo = {}; poolCreateInfo.memoryTypeIndex = memTypeIndex; - poolCreateInfo.blockSize = 128ull * 1024 * 1024; auto result = vk::Result{vmaCreatePool(allocator, &poolCreateInfo, pool)}; if (result != vk::Result::eSuccess) { @@ -127,10 +187,12 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, VALIDATION_LOG << "Could not create memory allocator"; return; } - if (!CreateBufferPool(allocator, &raster_buffer_pool_)) { + if (!CreateBufferPool(allocator, UsageHint::kRasterWorkload, + &raster_buffer_pool_)) { return; } - if (!CreateBufferPool(allocator, &image_upload_buffer_pool_)) { + if (!CreateBufferPool(allocator, UsageHint::kImageUpload, + &image_upload_buffer_pool_)) { return; } @@ -160,7 +222,6 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, VkResult res = vmaFindMemoryTypeIndexForImageInfo( allocator, &create_info_native, &sampleAllocCreateInfo, &memTypeIndex); - // Create a pool that can have at most 2 blocks, 128 MiB each. VmaPoolCreateInfo poolCreateInfo = {}; poolCreateInfo.memoryTypeIndex = memTypeIndex; poolCreateInfo.blockSize = 128ull * 1024 * 1024; @@ -260,50 +321,6 @@ static constexpr VmaMemoryUsage ToVMAMemoryUsage() { return VMA_MEMORY_USAGE_AUTO; } -static constexpr VkMemoryPropertyFlags ToVKMemoryPropertyFlags( - StorageMode mode) { - switch (mode) { - case StorageMode::kHostVisible: - // See https://github.com/flutter/flutter/issues/128556 . Some devices do - // not have support for coherent host memory so we don't request it here. - return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; - case StorageMode::kDevicePrivate: - return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - case StorageMode::kDeviceTransient: - return VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; - } - FML_UNREACHABLE(); -} - -static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode, - bool is_texture, - size_t size) { - VmaAllocationCreateFlags flags = 0; - switch (mode) { - case StorageMode::kHostVisible: - if (is_texture) { - if (size >= kImageSizeThresholdForDedicatedMemoryAllocation) { - flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; - } else { - flags |= {}; - } - } else { - flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; - flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT; - } - return flags; - case StorageMode::kDevicePrivate: - if (is_texture && - size >= kImageSizeThresholdForDedicatedMemoryAllocation) { - flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; - } - return flags; - case StorageMode::kDeviceTransient: - return flags; - } - FML_UNREACHABLE(); -} - class AllocatedTextureSourceVK final : public TextureSourceVK { public: AllocatedTextureSourceVK(const TextureDescriptor& desc, @@ -459,12 +476,7 @@ std::shared_ptr AllocatorVK::OnCreateBuffer( const DeviceBufferDescriptor& desc) { TRACE_EVENT0("impeller", "AllocatorVK::OnCreateBuffer"); vk::BufferCreateInfo buffer_info; - buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer | - vk::BufferUsageFlagBits::eIndexBuffer | - vk::BufferUsageFlagBits::eUniformBuffer | - vk::BufferUsageFlagBits::eStorageBuffer | - vk::BufferUsageFlagBits::eTransferSrc | - vk::BufferUsageFlagBits::eTransferDst; + buffer_info.usage = VmaBufferUsageFlags(desc.usage_hint); buffer_info.size = desc.size; buffer_info.sharingMode = vk::SharingMode::eExclusive; auto buffer_info_native = @@ -473,8 +485,14 @@ std::shared_ptr AllocatorVK::OnCreateBuffer( VmaAllocationCreateInfo allocation_info = {}; allocation_info.usage = ToVMAMemoryUsage(); allocation_info.preferredFlags = ToVKMemoryPropertyFlags(desc.storage_mode); - allocation_info.flags = ToVmaAllocationCreateFlags( - desc.storage_mode, /*is_texture=*/false, desc.size); + if (desc.usage_hint == UsageHint::kRasterWorkload) { + allocation_info.flags = ToVmaAllocationCreateFlags( + desc.storage_mode, /*is_texture=*/false, desc.size); + } else { + allocation_info.flags = + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; + } auto image_upload = desc.usage_hint == UsageHint::kImageUpload; allocation_info.pool = image_upload ? image_upload_buffer_pool_ : raster_buffer_pool_; From 82063b9bfdda112ed744a54294638d37183e6c55 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 29 Jun 2023 09:39:43 -0700 Subject: [PATCH 06/16] merge --- ci/licenses_golden/licenses_flutter | 2 ++ impeller/renderer/backend/vulkan/BUILD.gn | 1 + impeller/renderer/backend/vulkan/allocator_vk.cc | 6 +----- impeller/renderer/backend/vulkan/limits_vk.h | 14 ++++++++++++++ 4 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 impeller/renderer/backend/vulkan/limits_vk.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index d57b461954b05..9cb6faf5d7be2 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1521,6 +1521,7 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.cc + . ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/limits_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pass_bindings_cache.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pass_bindings_cache.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_cache_vk.cc + ../../../flutter/LICENSE @@ -4200,6 +4201,7 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/limits_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/pass_bindings_cache.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/pass_bindings_cache.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_cache_vk.cc diff --git a/impeller/renderer/backend/vulkan/BUILD.gn b/impeller/renderer/backend/vulkan/BUILD.gn index 4e451c4a233a7..1d21955728e65 100644 --- a/impeller/renderer/backend/vulkan/BUILD.gn +++ b/impeller/renderer/backend/vulkan/BUILD.gn @@ -52,6 +52,7 @@ impeller_component("vulkan") { "fence_waiter_vk.h", "formats_vk.cc", "formats_vk.h", + "limits_vk.h", "pass_bindings_cache.cc", "pass_bindings_cache.h", "pipeline_cache_vk.cc", diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index a8512ae722a89..f02dae6f1672c 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -11,15 +11,11 @@ #include "impeller/core/formats.h" #include "impeller/renderer/backend/vulkan/device_buffer_vk.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" +#include "impeller/renderer/backend/vulkan/limits_vk.h" #include "impeller/renderer/backend/vulkan/texture_vk.h" namespace impeller { -// Maximum size to use VMA image suballocation. Any allocation greater than or -// equal to this value will use a dedicated VkDeviceMemory. -constexpr size_t kImageSizeThresholdForDedicatedMemoryAllocation = - 4 * 1024 * 1024; - static constexpr VkMemoryPropertyFlags ToVKMemoryPropertyFlags( StorageMode mode) { switch (mode) { diff --git a/impeller/renderer/backend/vulkan/limits_vk.h b/impeller/renderer/backend/vulkan/limits_vk.h new file mode 100644 index 0000000000000..14e2dce906e49 --- /dev/null +++ b/impeller/renderer/backend/vulkan/limits_vk.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +namespace impeller { + +// Maximum size to use VMA image suballocation. Any allocation greater than or +// equal to this value will use a dedicated VkDeviceMemory. +// +// This value was taken from ANGLE. +constexpr size_t kImageSizeThresholdForDedicatedMemoryAllocation = + 4 * 1024 * 1024; + +} // namespace impeller From cb1c12d9868a2b9aeb0229bb940bbb96393a2aae Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 30 Jun 2023 17:05:16 -0700 Subject: [PATCH 07/16] ++ --- DEPS | 10 +- ci/licenses_golden/excluded_files | 4 +- ci/licenses_golden/licenses_flutter | 6 + ci/licenses_golden/licenses_fuchsia | 24 +- ci/licenses_golden/licenses_skia | 35 +- ci/licenses_golden/licenses_third_party | 2 +- .../benchmarking/dl_complexity_unittests.cc | 2 +- display_list/display_list.cc | 5 +- display_list/display_list.h | 16 - display_list/display_list_unittests.cc | 160 ----- display_list/dl_builder.cc | 627 +++++------------- display_list/dl_builder.h | 70 +- display_list/dl_color.h | 32 +- display_list/dl_paint.h | 1 - .../testing/dl_rendering_unittests.cc | 393 +---------- display_list/testing/dl_test_snippets.cc | 2 +- display_list/testing/dl_test_snippets.h | 6 +- display_list/utils/dl_matrix_clip_tracker.h | 4 +- flow/diff_context_unittests.cc | 2 +- flow/layers/container_layer_unittests.cc | 12 +- flow/layers/display_list_layer_unittests.cc | 19 +- flow/layers/opacity_layer_unittests.cc | 4 +- flow/testing/diff_context_test.cc | 2 +- flow/testing/diff_context_test.h | 3 +- impeller/aiks/BUILD.gn | 10 +- impeller/aiks/aiks_unittests.cc | 111 +++- impeller/aiks/canvas.cc | 26 +- impeller/aiks/canvas.h | 6 +- impeller/aiks/paint.cc | 13 +- impeller/aiks/paint.h | 4 +- impeller/aiks/paint_pass_delegate.cc | 2 +- impeller/aiks/testing/context_mock.h | 88 +++ impeller/aiks/testing/context_spy.cc | 111 ++++ impeller/aiks/testing/context_spy.h | 30 + impeller/core/device_buffer.cc | 2 - impeller/core/device_buffer.h | 2 - impeller/display_list/dl_dispatcher.cc | 39 +- impeller/display_list/dl_unittests.cc | 16 +- impeller/entity/contents/atlas_contents.cc | 9 +- impeller/entity/contents/atlas_contents.h | 2 +- impeller/entity/contents/contents.h | 5 + .../entity/contents/solid_color_contents.cc | 15 + .../entity/contents/solid_color_contents.h | 3 + .../entity/contents/tiled_texture_contents.cc | 23 +- .../entity/contents/tiled_texture_contents.h | 6 +- impeller/entity/entity_pass.cc | 68 +- impeller/entity/entity_pass.h | 9 +- impeller/entity/geometry/cover_geometry.cc | 5 + impeller/entity/geometry/cover_geometry.h | 3 + impeller/entity/geometry/geometry.h | 6 + impeller/entity/geometry/rect_geometry.cc | 8 + impeller/entity/geometry/rect_geometry.h | 3 + .../shaders/blending/advanced_blend.vert | 10 +- impeller/entity/shaders/blending/blend.vert | 6 +- impeller/entity/shaders/border_mask_blur.vert | 6 +- .../shaders/color_matrix_color_filter.vert | 4 +- .../shaders/gaussian_blur/gaussian_blur.vert | 10 +- impeller/entity/shaders/glyph_atlas.vert | 20 +- impeller/entity/shaders/gradient_fill.vert | 4 +- .../entity/shaders/linear_to_srgb_filter.vert | 4 +- .../entity/shaders/morphology_filter.vert | 6 +- impeller/entity/shaders/position_color.vert | 6 +- impeller/entity/shaders/rrect_blur.vert | 4 +- impeller/entity/shaders/runtime_effect.vert | 4 +- impeller/entity/shaders/solid_fill.vert | 2 +- .../entity/shaders/srgb_to_linear_filter.vert | 4 +- impeller/entity/shaders/texture_fill.vert | 4 +- .../entity/shaders/yuv_to_rgb_filter.vert | 4 +- impeller/geometry/color.cc | 241 ++++--- impeller/geometry/color.h | 8 +- impeller/geometry/vector.h | 4 + .../golden_tests/golden_playground_test.h | 10 +- impeller/golden_tests/golden_tests.cc | 5 + .../renderer/backend/gles/context_gles.cc | 1 + .../renderer/backend/metal/context_mtl.mm | 1 + .../backend/metal/vertex_descriptor_mtl.mm | 4 +- .../renderer/backend/vulkan/allocator_vk.cc | 223 +++---- .../renderer/backend/vulkan/allocator_vk.h | 4 +- .../backend/vulkan/capabilities_vk.cc | 20 + .../renderer/backend/vulkan/capabilities_vk.h | 4 + .../renderer/backend/vulkan/context_vk.cc | 3 +- .../backend/vulkan/device_buffer_vk.cc | 12 +- .../backend/vulkan/device_buffer_vk.h | 5 - .../renderer/backend/vulkan/surface_vk.cc | 26 +- impeller/renderer/backend/vulkan/surface_vk.h | 2 +- .../backend/vulkan/swapchain_image_vk.cc | 12 + .../backend/vulkan/swapchain_image_vk.h | 7 + impeller/renderer/capabilities.cc | 14 + impeller/renderer/capabilities.h | 5 + impeller/renderer/capabilities_unittests.cc | 1 + impeller/renderer/command_buffer.h | 6 + impeller/renderer/render_pass.h | 7 + lib/ui/painting/image_decoder_impeller.cc | 15 +- lib/ui/painting/image_decoder_impeller.h | 5 +- lib/web_ui/lib/initialization.dart | 129 ++-- .../src/engine/canvaskit/canvaskit_api.dart | 3 +- lib/web_ui/lib/src/engine/canvaskit/text.dart | 7 +- lib/web_ui/lib/src/engine/configuration.dart | 9 + lib/web_ui/lib/src/engine/dom.dart | 32 +- lib/web_ui/lib/src/engine/embedder.dart | 8 +- .../lib/src/engine/html/scene_builder.dart | 5 +- lib/web_ui/lib/src/engine/initialization.dart | 2 +- .../lib/src/engine/platform_dispatcher.dart | 2 +- lib/web_ui/lib/src/engine/plugins.dart | 4 +- .../lib/src/engine/semantics/semantics.dart | 3 +- lib/web_ui/lib/src/engine/text/paragraph.dart | 5 +- lib/web_ui/lib/src/engine/text/ruler.dart | 3 +- lib/web_ui/lib/ui_web/src/ui_web.dart | 3 + .../lib/ui_web/src/ui_web/initialization.dart | 57 ++ .../src/ui_web/navigation/url_strategy.dart | 3 +- lib/web_ui/lib/ui_web/src/ui_web/plugins.dart | 14 + lib/web_ui/lib/ui_web/src/ui_web/testing.dart | 27 + .../flutter_tester_emulation_golden_test.dart | 3 +- .../test/canvaskit/fragment_program_test.dart | 2 +- lib/web_ui/test/canvaskit/text_test.dart | 7 +- .../test/common/test_initialization.dart | 3 +- .../test/engine/channel_buffers_test.dart | 2 +- .../test/engine/dom_http_fetch_test.dart | 1 - .../test/engine/global_styles_test.dart | 10 +- .../test/engine/initialization_test.dart | 10 +- ...application_switcher_description_test.dart | 5 +- .../system_ui_overlay_style_test.dart | 3 +- .../canvas_draw_image_golden_test.dart | 3 +- .../text/canvas_paragraph_builder_test.dart | 5 +- .../html/text/layout_service_plain_test.dart | 5 +- lib/web_ui/test/html/text_test.dart | 19 +- shell/common/dl_op_spy_unittests.cc | 202 ++---- .../fuchsia/dart-pkg/zircon/sdk_ext/system.h | 9 - .../flatland_external_view_embedder.cc | 22 +- .../windows/accessibility_bridge_windows.cc | 12 +- .../windows/accessibility_bridge_windows.h | 3 + .../accessibility_bridge_windows_unittests.cc | 49 +- testing/dart/channel_buffers_test.dart | 2 +- 133 files changed, 1598 insertions(+), 1904 deletions(-) create mode 100644 impeller/aiks/testing/context_mock.h create mode 100644 impeller/aiks/testing/context_spy.cc create mode 100644 impeller/aiks/testing/context_spy.h create mode 100644 lib/web_ui/lib/ui_web/src/ui_web/initialization.dart create mode 100644 lib/web_ui/lib/ui_web/src/ui_web/plugins.dart create mode 100644 lib/web_ui/lib/ui_web/src/ui_web/testing.dart diff --git a/DEPS b/DEPS index 79208ff538c36..6088d4e5cef1b 100644 --- a/DEPS +++ b/DEPS @@ -18,7 +18,7 @@ vars = { 'llvm_git': 'https://llvm.googlesource.com', # OCMock is for testing only so there is no google clone 'ocmock_git': 'https://github.com/erikdoe/ocmock.git', - 'skia_revision': '5209dc7702d07de875ccff4db3859efd14d9746b', + 'skia_revision': '2d05e3ec6b6702eff0105940fd76b6b499acd031', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. @@ -53,7 +53,7 @@ vars = { # Dart is: https://github.com/dart-lang/sdk/blob/main/DEPS # You can use //tools/dart/create_updated_flutter_deps.py to produce # updated revision list of existing dependencies. - 'dart_revision': '5a59cd06e49dc0a2c7bb946986df50e5750831e9', + 'dart_revision': '2d98d9e27daeb80dd6ddb6da94ea9f1a4fe7e5ca', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -63,7 +63,7 @@ vars = { 'dart_browser_launcher_rev': '40e431543840cbe7fc05b95a2f851d9f1bd3bc14', 'dart_clock_rev': '21caac1cbcea147708fc26989733cd6a486177e7', 'dart_collection_rev': 'a37bd51c63b7720799869e3448eafbc19c88bfa6', - 'dart_devtools_rev': '0c0c65dbaf53f8c508bfd6acbeb7f1986c1ca1f8', + 'dart_devtools_rev': '99dca813aaa7fa23ccd6fe3901ac7665e96db3cb', 'dart_libprotobuf_rev': '24487dd1045c7f3d64a21f38a3f0c06cc4cf2edb', 'dart_perfetto_rev': 'b8da07095979310818f0efde2ef3c69ea70d62c5', 'dart_protobuf_gn_rev': 'ca669f79945418f6229e4fef89b666b2a88cbb10', @@ -332,7 +332,7 @@ deps = { Var('chromium_git') + '/external/github.com/WebAssembly/binaryen.git@b9b5f162ca8bf5b899ff0f0351491d7d403d7ed9', 'src/third_party/dart/third_party/devtools': - {'packages': [{'version': 'git_revision:0c0c65dbaf53f8c508bfd6acbeb7f1986c1ca1f8', 'package': 'dart/third_party/flutter/devtools'}], 'dep_type': 'cipd'}, + {'packages': [{'version': 'git_revision:99dca813aaa7fa23ccd6fe3901ac7665e96db3cb', 'package': 'dart/third_party/flutter/devtools'}], 'dep_type': 'cipd'}, 'src/third_party/dart/third_party/pkg/args': Var('dart_git') + '/args.git@a9543c021f9409832b1668f9256f247585362389', @@ -899,7 +899,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': '10hNrVMjnCypybnz2JvFbUdvapBYUDa_l3p486QuWs4C' + 'version': 'iwgWLB4KaXslnaGwKuAD5S9wamgkF0Mj9a411131XdkC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 8c0100eeeaeb7..78407c28040f1 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -121,6 +121,7 @@ ../../../flutter/impeller/README.md ../../../flutter/impeller/aiks/aiks_unittests.cc ../../../flutter/impeller/aiks/canvas_unittests.cc +../../../flutter/impeller/aiks/testing ../../../flutter/impeller/archivist/archivist_unittests.cc ../../../flutter/impeller/base/README.md ../../../flutter/impeller/base/base_unittests.cc @@ -449,7 +450,6 @@ ../../../fuchsia/sdk/linux/arch/x64/sysroot/dist/lib/ld.so.1 ../../../fuchsia/sdk/linux/dart/fidl/meta.json ../../../fuchsia/sdk/linux/dart/fuchsia/meta.json -../../../fuchsia/sdk/linux/dart/fuchsia_component_test/meta.json ../../../fuchsia/sdk/linux/dart/fuchsia_logger/meta.json ../../../fuchsia/sdk/linux/dart/fuchsia_services/meta.json ../../../fuchsia/sdk/linux/dart/fuchsia_vfs/meta.json @@ -497,6 +497,7 @@ ../../../fuchsia/sdk/linux/fidl/fuchsia.device.fs/meta.json ../../../fuchsia/sdk/linux/fidl/fuchsia.diagnostics.types/meta.json ../../../fuchsia/sdk/linux/fidl/fuchsia.diagnostics/meta.json +../../../fuchsia/sdk/linux/fidl/fuchsia.driver.framework/meta.json ../../../fuchsia/sdk/linux/fidl/fuchsia.driver.test/meta.json ../../../fuchsia/sdk/linux/fidl/fuchsia.element/meta.json ../../../fuchsia/sdk/linux/fidl/fuchsia.factory.wlan/meta.json @@ -2611,6 +2612,7 @@ ../../../third_party/skia/experimental ../../../third_party/skia/fuzz/README.md ../../../third_party/skia/gm/BUILD.bazel +../../../third_party/skia/gm/android_gm_test.bzl ../../../third_party/skia/gn/BUILD.bazel ../../../third_party/skia/gn/__init__.py ../../../third_party/skia/gn/bazel_build.py diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 9cb6faf5d7be2..e4e881570c01d 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2111,9 +2111,12 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/tile_mode.dart + ../../../flutter/LICENS ORIGIN: ../../../flutter/lib/web_ui/lib/ui.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/asset_manager.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/initialization.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/navigation/platform_location.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/navigation/url_strategy.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/platform_view_registry.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/plugins.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/testing.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/window.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/canvas.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/contour_measure.cpp + ../../../flutter/LICENSE @@ -4793,9 +4796,12 @@ FILE: ../../../flutter/lib/web_ui/lib/tile_mode.dart FILE: ../../../flutter/lib/web_ui/lib/ui.dart FILE: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web.dart FILE: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/asset_manager.dart +FILE: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/initialization.dart FILE: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/navigation/platform_location.dart FILE: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/navigation/url_strategy.dart FILE: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/platform_view_registry.dart +FILE: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/plugins.dart +FILE: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/testing.dart FILE: ../../../flutter/lib/web_ui/lib/window.dart FILE: ../../../flutter/lib/web_ui/skwasm/canvas.cpp FILE: ../../../flutter/lib/web_ui/skwasm/contour_measure.cpp diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 7a25c674d8c65..d323204155b88 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 136adbdab0de3d2952b3ad51a3835520 +Signature: 35f2c5af32e2d5074b973b70478bddc4 ==================================================================================================== LIBRARY: fuchsia_sdk @@ -2757,6 +2757,8 @@ ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.component/error.fidl + ../../../ ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.component/types.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.diagnostics/interest.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.diagnostics/severity.fidl + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.driver.framework/driver_start_args.fidl + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.driver.framework/topology.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.factory.wlan/iovar.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.feedback/crash_register.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.feedback/data_register.fidl + ../../../fuchsia/sdk/linux/LICENSE @@ -2917,6 +2919,8 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.component/error.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.component/types.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.diagnostics/interest.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.diagnostics/severity.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.driver.framework/driver_start_args.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.driver.framework/topology.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.factory.wlan/iovar.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.feedback/crash_register.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.feedback/data_register.fidl @@ -3395,12 +3399,6 @@ ORIGIN: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/in ORIGIN: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/errors.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/internal/cdecls.inc + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/dart/fidl/lib/src/optional_nullable.dart + ../../../fuchsia/sdk/linux/LICENSE -ORIGIN: ../../../fuchsia/sdk/linux/dart/fuchsia_component_test/lib/realm_builder.dart + ../../../fuchsia/sdk/linux/LICENSE -ORIGIN: ../../../fuchsia/sdk/linux/dart/fuchsia_component_test/lib/src/error.dart + ../../../fuchsia/sdk/linux/LICENSE -ORIGIN: ../../../fuchsia/sdk/linux/dart/fuchsia_component_test/lib/src/internal/local_component.dart + ../../../fuchsia/sdk/linux/LICENSE -ORIGIN: ../../../fuchsia/sdk/linux/dart/fuchsia_component_test/lib/src/internal/local_component_runner.dart + ../../../fuchsia/sdk/linux/LICENSE -ORIGIN: ../../../fuchsia/sdk/linux/dart/fuchsia_component_test/lib/src/local_component_handles.dart + ../../../fuchsia/sdk/linux/LICENSE -ORIGIN: ../../../fuchsia/sdk/linux/dart/fuchsia_component_test/lib/src/realm_builder.dart + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/dart/sl4f/lib/src/performance_publish.dart + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/dart/sl4f/lib/src/trace_processing/metrics/power_metrics.dart + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.accessibility.semantics/overview.fidl + ../../../fuchsia/sdk/linux/LICENSE @@ -3428,6 +3426,8 @@ ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.component.resolution/resolver.fi ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.component/overview.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.debugdata/publisher.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.diagnostics/overview.fidl + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.driver.framework/composite_node_spec.fidl + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.driver.framework/overview.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.element/overview.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.feedback/overview.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.fonts/overview.fidl + ../../../fuchsia/sdk/linux/LICENSE @@ -3623,12 +3623,6 @@ FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/inte FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/errors.h FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/internal/cdecls.inc FILE: ../../../fuchsia/sdk/linux/dart/fidl/lib/src/optional_nullable.dart -FILE: ../../../fuchsia/sdk/linux/dart/fuchsia_component_test/lib/realm_builder.dart -FILE: ../../../fuchsia/sdk/linux/dart/fuchsia_component_test/lib/src/error.dart -FILE: ../../../fuchsia/sdk/linux/dart/fuchsia_component_test/lib/src/internal/local_component.dart -FILE: ../../../fuchsia/sdk/linux/dart/fuchsia_component_test/lib/src/internal/local_component_runner.dart -FILE: ../../../fuchsia/sdk/linux/dart/fuchsia_component_test/lib/src/local_component_handles.dart -FILE: ../../../fuchsia/sdk/linux/dart/fuchsia_component_test/lib/src/realm_builder.dart FILE: ../../../fuchsia/sdk/linux/dart/sl4f/lib/src/performance_publish.dart FILE: ../../../fuchsia/sdk/linux/dart/sl4f/lib/src/trace_processing/metrics/power_metrics.dart FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.accessibility.semantics/overview.fidl @@ -3656,6 +3650,8 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.component.resolution/resolver.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.component/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.debugdata/publisher.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.diagnostics/overview.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.driver.framework/composite_node_spec.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.driver.framework/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.element/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.feedback/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.fonts/overview.fidl @@ -3876,6 +3872,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIBRARY: fuchsia_sdk ORIGIN: ../../../fuchsia/sdk/linux/dart/sl4f/lib/src/flatland_example.dart + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/dart/sl4f/lib/src/media_session.dart + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.component/controller.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.device.fs/names.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.element/graphical_presenter.fidl + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.audio.signalprocessing/endpoint.fidl + ../../../fuchsia/sdk/linux/LICENSE @@ -3910,6 +3907,7 @@ ORIGIN: ../../../fuchsia/sdk/linux/pkg/sys_service_cpp/service_handler.cc + ../. TYPE: LicenseType.bsd FILE: ../../../fuchsia/sdk/linux/dart/sl4f/lib/src/flatland_example.dart FILE: ../../../fuchsia/sdk/linux/dart/sl4f/lib/src/media_session.dart +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.component/controller.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.device.fs/names.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.element/graphical_presenter.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.hardware.audio.signalprocessing/endpoint.fidl diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 261dcadacb01e..56ad4fb5023ec 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e5d66f08a5f6a3c4dede0b4f3f904487 +Signature: 0e2849bbe385fcb055c27cc9d8abcf79 ==================================================================================================== LIBRARY: etc1 @@ -384,6 +384,11 @@ FILE: ../../../third_party/skia/modules/pathkit/perf/pathops.bench.js FILE: ../../../third_party/skia/modules/pathkit/perf/perfReporter.js FILE: ../../../third_party/skia/modules/skparagraph/test.html FILE: ../../../third_party/skia/package-lock.json +FILE: ../../../third_party/skia/relnotes/canvas_flush.md +FILE: ../../../third_party/skia/relnotes/const_context.md +FILE: ../../../third_party/skia/relnotes/runtimeeffect_const.md +FILE: ../../../third_party/skia/relnotes/runtimeeffect_image.md +FILE: ../../../third_party/skia/relnotes/tiledimages.md FILE: ../../../third_party/skia/src/core/SkOrderedReadBuffer.h FILE: ../../../third_party/skia/src/gpu/gpu_workaround_list.txt FILE: ../../../third_party/skia/src/sksl/generated/sksl_compute.minified.sksl @@ -8191,7 +8196,6 @@ ORIGIN: ../../../third_party/skia/include/private/base/SkAttributes.h + ../../.. ORIGIN: ../../../third_party/skia/include/private/base/SkDebug.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/include/private/base/SkFeatures.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/include/private/base/SkLoadUserConfig.h + ../../../third_party/skia/LICENSE -ORIGIN: ../../../third_party/skia/include/private/base/SkPathEnums.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/include/private/base/SkTypeTraits.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/include/sksl/SkSLVersion.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/modules/skunicode/src/SkUnicode.cpp + ../../../third_party/skia/LICENSE @@ -8199,6 +8203,7 @@ ORIGIN: ../../../third_party/skia/modules/skunicode/src/SkUnicode_icu_bidi.cpp + ORIGIN: ../../../third_party/skia/src/android/SkAndroidFrameworkPerfettoStaticStorage.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/core/SkCapabilities.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/core/SkDebugUtils.h + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/src/core/SkPathEnums.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/core/SkPathUtils.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/core/SkSLTypeShared.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/core/SkSLTypeShared.h + ../../../third_party/skia/LICENSE @@ -8343,8 +8348,8 @@ ORIGIN: ../../../third_party/skia/src/gpu/graphite/render/TessellateWedgesRender ORIGIN: ../../../third_party/skia/src/gpu/graphite/render/TessellateWedgesRenderStep.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/gpu/graphite/render/VerticesRenderStep.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/gpu/graphite/render/VerticesRenderStep.h + ../../../third_party/skia/LICENSE -ORIGIN: ../../../third_party/skia/src/gpu/graphite/text/AtlasManager.cpp + ../../../third_party/skia/LICENSE -ORIGIN: ../../../third_party/skia/src/gpu/graphite/text/AtlasManager.h + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/src/gpu/graphite/text/TextAtlasManager.cpp + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/src/gpu/graphite/text/TextAtlasManager.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/gpu/graphite/vk/VulkanBuffer.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/gpu/graphite/vk/VulkanBuffer.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/gpu/graphite/vk/VulkanCaps.cpp + ../../../third_party/skia/LICENSE @@ -8411,7 +8416,6 @@ FILE: ../../../third_party/skia/include/private/base/SkAttributes.h FILE: ../../../third_party/skia/include/private/base/SkDebug.h FILE: ../../../third_party/skia/include/private/base/SkFeatures.h FILE: ../../../third_party/skia/include/private/base/SkLoadUserConfig.h -FILE: ../../../third_party/skia/include/private/base/SkPathEnums.h FILE: ../../../third_party/skia/include/private/base/SkTypeTraits.h FILE: ../../../third_party/skia/include/sksl/SkSLVersion.h FILE: ../../../third_party/skia/modules/skunicode/src/SkUnicode.cpp @@ -8419,6 +8423,7 @@ FILE: ../../../third_party/skia/modules/skunicode/src/SkUnicode_icu_bidi.cpp FILE: ../../../third_party/skia/src/android/SkAndroidFrameworkPerfettoStaticStorage.cpp FILE: ../../../third_party/skia/src/core/SkCapabilities.cpp FILE: ../../../third_party/skia/src/core/SkDebugUtils.h +FILE: ../../../third_party/skia/src/core/SkPathEnums.h FILE: ../../../third_party/skia/src/core/SkPathUtils.cpp FILE: ../../../third_party/skia/src/core/SkSLTypeShared.cpp FILE: ../../../third_party/skia/src/core/SkSLTypeShared.h @@ -8563,8 +8568,8 @@ FILE: ../../../third_party/skia/src/gpu/graphite/render/TessellateWedgesRenderSt FILE: ../../../third_party/skia/src/gpu/graphite/render/TessellateWedgesRenderStep.h FILE: ../../../third_party/skia/src/gpu/graphite/render/VerticesRenderStep.cpp FILE: ../../../third_party/skia/src/gpu/graphite/render/VerticesRenderStep.h -FILE: ../../../third_party/skia/src/gpu/graphite/text/AtlasManager.cpp -FILE: ../../../third_party/skia/src/gpu/graphite/text/AtlasManager.h +FILE: ../../../third_party/skia/src/gpu/graphite/text/TextAtlasManager.cpp +FILE: ../../../third_party/skia/src/gpu/graphite/text/TextAtlasManager.h FILE: ../../../third_party/skia/src/gpu/graphite/vk/VulkanBuffer.cpp FILE: ../../../third_party/skia/src/gpu/graphite/vk/VulkanBuffer.h FILE: ../../../third_party/skia/src/gpu/graphite/vk/VulkanCaps.cpp @@ -8759,6 +8764,8 @@ ORIGIN: ../../../third_party/skia/include/private/SkJpegGainmapEncoder.h + ../.. ORIGIN: ../../../third_party/skia/include/private/SkXmp.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/modules/skottie/include/SlotManager.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/modules/skottie/src/SlotManager.cpp + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/modules/skunicode/src/SkUnicode_hardcoded.cpp + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/modules/skunicode/src/SkUnicode_hardcoded.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/modules/skunicode/src/SkUnicode_icu_bidi.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/codec/SkJpegConstants.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/codec/SkJpegMultiPicture.cpp + ../../../third_party/skia/LICENSE @@ -8796,6 +8803,8 @@ FILE: ../../../third_party/skia/include/private/SkJpegGainmapEncoder.h FILE: ../../../third_party/skia/include/private/SkXmp.h FILE: ../../../third_party/skia/modules/skottie/include/SlotManager.h FILE: ../../../third_party/skia/modules/skottie/src/SlotManager.cpp +FILE: ../../../third_party/skia/modules/skunicode/src/SkUnicode_hardcoded.cpp +FILE: ../../../third_party/skia/modules/skunicode/src/SkUnicode_hardcoded.h FILE: ../../../third_party/skia/modules/skunicode/src/SkUnicode_icu_bidi.h FILE: ../../../third_party/skia/src/codec/SkJpegConstants.h FILE: ../../../third_party/skia/src/codec/SkJpegMultiPicture.cpp @@ -8859,6 +8868,8 @@ ORIGIN: ../../../third_party/skia/fuzz/FuzzCubicRoots.cpp + ../../../third_party ORIGIN: ../../../third_party/skia/fuzz/FuzzQuadRoots.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/fuzz/oss_fuzz/FuzzCubicRoots.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/fuzz/oss_fuzz/FuzzQuadRoots.cpp + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/gm/BazelGMRunner.cpp + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/gm/BazelNoopRunner.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/gm/graphite_replay.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/gm/scaledrects.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/include/android/SkCanvasAndroid.h + ../../../third_party/skia/LICENSE @@ -8971,6 +8982,8 @@ ORIGIN: ../../../third_party/skia/src/gpu/ganesh/image/SkImage_LazyTexture.h + . ORIGIN: ../../../third_party/skia/src/gpu/ganesh/image/SkImage_RasterPinnable.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/gpu/ganesh/image/SkImage_RasterPinnable.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/gpu/ganesh/surface/SkSurface_AndroidFactories.cpp + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/src/gpu/graphite/AtlasProvider.cpp + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/src/gpu/graphite/AtlasProvider.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/gpu/graphite/BackendSemaphore.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/gpu/graphite/DescriptorTypes.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/gpu/graphite/ImageFactories.cpp + ../../../third_party/skia/LICENSE @@ -8983,6 +8996,7 @@ ORIGIN: ../../../third_party/skia/src/gpu/graphite/PathAtlas.h + ../../../third_ ORIGIN: ../../../third_party/skia/src/gpu/graphite/ProxyCache.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/gpu/graphite/ProxyCache.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/gpu/graphite/ReadSwizzle.h + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/src/gpu/graphite/TiledTextureUtils_Graphite.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/gpu/graphite/YUVABackendTextures.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/gpu/graphite/YUVATextureProxies.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/gpu/graphite/YUVATextureProxies.h + ../../../third_party/skia/LICENSE @@ -9042,6 +9056,7 @@ ORIGIN: ../../../third_party/skia/src/sksl/tracing/SkSLTraceHook.cpp + ../../../ ORIGIN: ../../../third_party/skia/src/sksl/tracing/SkSLTraceHook.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/sksl/transform/SkSLHoistSwitchVarDeclarationsAtTopLevel.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/sksl/transform/SkSLRewriteIndexedSwizzle.cpp + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/src/text/EmptySlugImpl.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/text/gpu/SlugImpl.cpp + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/text/gpu/SlugImpl.h + ../../../third_party/skia/LICENSE ORIGIN: ../../../third_party/skia/src/text/gpu/VertexFiller.cpp + ../../../third_party/skia/LICENSE @@ -9053,6 +9068,8 @@ FILE: ../../../third_party/skia/fuzz/FuzzCubicRoots.cpp FILE: ../../../third_party/skia/fuzz/FuzzQuadRoots.cpp FILE: ../../../third_party/skia/fuzz/oss_fuzz/FuzzCubicRoots.cpp FILE: ../../../third_party/skia/fuzz/oss_fuzz/FuzzQuadRoots.cpp +FILE: ../../../third_party/skia/gm/BazelGMRunner.cpp +FILE: ../../../third_party/skia/gm/BazelNoopRunner.cpp FILE: ../../../third_party/skia/gm/graphite_replay.cpp FILE: ../../../third_party/skia/gm/scaledrects.cpp FILE: ../../../third_party/skia/include/android/SkCanvasAndroid.h @@ -9165,6 +9182,8 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/image/SkImage_LazyTexture.h FILE: ../../../third_party/skia/src/gpu/ganesh/image/SkImage_RasterPinnable.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/image/SkImage_RasterPinnable.h FILE: ../../../third_party/skia/src/gpu/ganesh/surface/SkSurface_AndroidFactories.cpp +FILE: ../../../third_party/skia/src/gpu/graphite/AtlasProvider.cpp +FILE: ../../../third_party/skia/src/gpu/graphite/AtlasProvider.h FILE: ../../../third_party/skia/src/gpu/graphite/BackendSemaphore.cpp FILE: ../../../third_party/skia/src/gpu/graphite/DescriptorTypes.h FILE: ../../../third_party/skia/src/gpu/graphite/ImageFactories.cpp @@ -9177,6 +9196,7 @@ FILE: ../../../third_party/skia/src/gpu/graphite/PathAtlas.h FILE: ../../../third_party/skia/src/gpu/graphite/ProxyCache.cpp FILE: ../../../third_party/skia/src/gpu/graphite/ProxyCache.h FILE: ../../../third_party/skia/src/gpu/graphite/ReadSwizzle.h +FILE: ../../../third_party/skia/src/gpu/graphite/TiledTextureUtils_Graphite.cpp FILE: ../../../third_party/skia/src/gpu/graphite/YUVABackendTextures.cpp FILE: ../../../third_party/skia/src/gpu/graphite/YUVATextureProxies.cpp FILE: ../../../third_party/skia/src/gpu/graphite/YUVATextureProxies.h @@ -9236,6 +9256,7 @@ FILE: ../../../third_party/skia/src/sksl/tracing/SkSLTraceHook.cpp FILE: ../../../third_party/skia/src/sksl/tracing/SkSLTraceHook.h FILE: ../../../third_party/skia/src/sksl/transform/SkSLHoistSwitchVarDeclarationsAtTopLevel.cpp FILE: ../../../third_party/skia/src/sksl/transform/SkSLRewriteIndexedSwizzle.cpp +FILE: ../../../third_party/skia/src/text/EmptySlugImpl.cpp FILE: ../../../third_party/skia/src/text/gpu/SlugImpl.cpp FILE: ../../../third_party/skia/src/text/gpu/SlugImpl.h FILE: ../../../third_party/skia/src/text/gpu/VertexFiller.cpp diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 083b30999fa7e..ba0d39c5a3b22 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 6e560ebdd30f319b7aeab455043944f0 +Signature: a4b0b757c68ecbaddc512bcdc32f5eb6 ==================================================================================================== LIBRARY: angle diff --git a/display_list/benchmarking/dl_complexity_unittests.cc b/display_list/benchmarking/dl_complexity_unittests.cc index eee77ac9bdf55..4ec6111485d88 100644 --- a/display_list/benchmarking/dl_complexity_unittests.cc +++ b/display_list/benchmarking/dl_complexity_unittests.cc @@ -423,7 +423,7 @@ TEST(DisplayListComplexity, DrawAtlas) { std::vector xforms; for (int i = 0; i < 10; i++) { rects.push_back(SkRect::MakeXYWH(0, 0, 10, 10)); - xforms.push_back(SkRSXform::Make(1, 0, 0, 0)); + xforms.push_back(SkRSXform::Make(0, 0, 0, 0)); } DisplayListBuilder builder; diff --git a/display_list/display_list.cc b/display_list/display_list.cc index e06bcf246d3d4..378f86804f260 100644 --- a/display_list/display_list.cc +++ b/display_list/display_list.cc @@ -22,8 +22,7 @@ DisplayList::DisplayList() unique_id_(0), bounds_({0, 0, 0, 0}), can_apply_group_opacity_(true), - is_ui_thread_safe_(true), - modifies_transparent_black_(false) {} + is_ui_thread_safe_(true) {} DisplayList::DisplayList(DisplayListStorage&& storage, size_t byte_count, @@ -33,7 +32,6 @@ DisplayList::DisplayList(DisplayListStorage&& storage, const SkRect& bounds, bool can_apply_group_opacity, bool is_ui_thread_safe, - bool modifies_transparent_black, sk_sp rtree) : storage_(std::move(storage)), byte_count_(byte_count), @@ -44,7 +42,6 @@ DisplayList::DisplayList(DisplayListStorage&& storage, bounds_(bounds), can_apply_group_opacity_(can_apply_group_opacity), is_ui_thread_safe_(is_ui_thread_safe), - modifies_transparent_black_(modifies_transparent_black), rtree_(std::move(rtree)) {} DisplayList::~DisplayList() { diff --git a/display_list/display_list.h b/display_list/display_list.h index 668a247d5596f..4a6f339fdea0d 100644 --- a/display_list/display_list.h +++ b/display_list/display_list.h @@ -265,19 +265,6 @@ class DisplayList : public SkRefCnt { bool can_apply_group_opacity() const { return can_apply_group_opacity_; } bool isUIThreadSafe() const { return is_ui_thread_safe_; } - /// @brief Indicates if there are any rendering operations in this - /// DisplayList that will modify a surface of transparent black - /// pixels. - /// - /// This condition can be used to determine whether to create a cleared - /// surface, render a DisplayList into it, and then composite the - /// result into a scene. It is not uncommon for code in the engine to - /// come across such degenerate DisplayList objects when slicing up a - /// frame between platform views. - bool modifies_transparent_black() const { - return modifies_transparent_black_; - } - private: DisplayList(DisplayListStorage&& ptr, size_t byte_count, @@ -287,7 +274,6 @@ class DisplayList : public SkRefCnt { const SkRect& bounds, bool can_apply_group_opacity, bool is_ui_thread_safe, - bool modifies_transparent_black, sk_sp rtree); static uint32_t next_unique_id(); @@ -306,8 +292,6 @@ class DisplayList : public SkRefCnt { const bool can_apply_group_opacity_; const bool is_ui_thread_safe_; - const bool modifies_transparent_black_; - const sk_sp rtree_; void Dispatch(DlOpReceiver& ctx, diff --git a/display_list/display_list_unittests.cc b/display_list/display_list_unittests.cc index 0b4763895579a..28f3c005d488a 100644 --- a/display_list/display_list_unittests.cc +++ b/display_list/display_list_unittests.cc @@ -23,7 +23,6 @@ #include "third_party/skia/include/core/SkBBHFactory.h" #include "third_party/skia/include/core/SkPictureRecorder.h" -#include "third_party/skia/include/core/SkRSXform.h" #include "third_party/skia/include/core/SkSurface.h" namespace flutter { @@ -3018,164 +3017,5 @@ TEST_F(DisplayListTest, DrawUnorderedRoundRectPathCCW) { check_inverted_bounds(renderer, "DrawRoundRectPath Counter-Clockwise"); } -TEST_F(DisplayListTest, NopOperationsOmittedFromRecords) { - auto run_tests = [](const std::string& name, - void init(DisplayListBuilder & builder, DlPaint & paint), - uint32_t expected_op_count = 0u) { - auto run_one_test = - [init](const std::string& name, - void build(DisplayListBuilder & builder, DlPaint & paint), - uint32_t expected_op_count = 0u) { - DisplayListBuilder builder; - DlPaint paint; - init(builder, paint); - build(builder, paint); - auto list = builder.Build(); - if (list->op_count() != expected_op_count) { - FML_LOG(ERROR) << *list; - } - ASSERT_EQ(list->op_count(), expected_op_count) << name; - ASSERT_TRUE(list->bounds().isEmpty()) << name; - }; - run_one_test( - name + " DrawColor", - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.DrawColor(paint.getColor(), paint.getBlendMode()); - }, - expected_op_count); - run_one_test( - name + " DrawPaint", - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.DrawPaint(paint); - }, - expected_op_count); - run_one_test( - name + " DrawRect", - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.DrawRect({10, 10, 20, 20}, paint); - }, - expected_op_count); - run_one_test( - name + " Other Draw Ops", - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.DrawLine({10, 10}, {20, 20}, paint); - builder.DrawOval({10, 10, 20, 20}, paint); - builder.DrawCircle({50, 50}, 20, paint); - builder.DrawRRect(SkRRect::MakeRectXY({10, 10, 20, 20}, 5, 5), paint); - builder.DrawDRRect(SkRRect::MakeRectXY({5, 5, 100, 100}, 5, 5), - SkRRect::MakeRectXY({10, 10, 20, 20}, 5, 5), - paint); - builder.DrawPath(kTestPath1, paint); - builder.DrawArc({10, 10, 20, 20}, 45, 90, true, paint); - SkPoint pts[] = {{10, 10}, {20, 20}}; - builder.DrawPoints(PointMode::kLines, 2, pts, paint); - builder.DrawVertices(TestVertices1, DlBlendMode::kSrcOver, paint); - builder.DrawImage(TestImage1, {10, 10}, DlImageSampling::kLinear, - &paint); - builder.DrawImageRect(TestImage1, SkRect{0.0f, 0.0f, 10.0f, 10.0f}, - SkRect{10.0f, 10.0f, 25.0f, 25.0f}, - DlImageSampling::kLinear, &paint); - builder.DrawImageNine(TestImage1, {10, 10, 20, 20}, - {10, 10, 100, 100}, DlFilterMode::kLinear, - &paint); - SkRSXform xforms[] = {{1, 0, 10, 10}, {0, 1, 10, 10}}; - SkRect rects[] = {{10, 10, 20, 20}, {10, 20, 30, 20}}; - builder.DrawAtlas(TestImage1, xforms, rects, nullptr, 2, - DlBlendMode::kSrcOver, DlImageSampling::kLinear, - nullptr, &paint); - builder.DrawTextBlob(TestBlob1, 10, 10, paint); - - // Dst mode eliminates most rendering ops except for - // the following two, so we'll prune those manually... - if (paint.getBlendMode() != DlBlendMode::kDst) { - builder.DrawDisplayList(TestDisplayList1, paint.getOpacity()); - builder.DrawShadow(kTestPath1, paint.getColor(), 1, true, 1); - } - }, - expected_op_count); - run_one_test( - name + " SaveLayer", - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.SaveLayer(nullptr, &paint, nullptr); - builder.DrawRect({10, 10, 20, 20}, DlPaint()); - builder.Restore(); - }, - expected_op_count); - run_one_test( - name + " inside Save", - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.Save(); - builder.DrawRect({10, 10, 20, 20}, paint); - builder.Restore(); - }, - expected_op_count); - }; - run_tests("transparent color", // - [](DisplayListBuilder& builder, DlPaint& paint) { - paint.setColor(DlColor::kTransparent()); - }); - run_tests("0 alpha", // - [](DisplayListBuilder& builder, DlPaint& paint) { - // The transparent test above already tested transparent - // black (all 0s), we set White color here so we can test - // the case of all 1s with a 0 alpha - paint.setColor(DlColor::kWhite()); - paint.setAlpha(0); - }); - run_tests("BlendMode::kDst", // - [](DisplayListBuilder& builder, DlPaint& paint) { - paint.setBlendMode(DlBlendMode::kDst); - }); - run_tests("Empty rect clip", // - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.ClipRect(SkRect::MakeEmpty(), ClipOp::kIntersect, false); - }); - run_tests("Empty rrect clip", // - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.ClipRRect(SkRRect::MakeEmpty(), ClipOp::kIntersect, - false); - }); - run_tests("Empty path clip", // - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.ClipPath(SkPath(), ClipOp::kIntersect, false); - }); - run_tests("Transparent SaveLayer", // - [](DisplayListBuilder& builder, DlPaint& paint) { - DlPaint save_paint; - save_paint.setColor(DlColor::kTransparent()); - builder.SaveLayer(nullptr, &save_paint); - }); - run_tests("0 alpha SaveLayer", // - [](DisplayListBuilder& builder, DlPaint& paint) { - DlPaint save_paint; - // The transparent test above already tested transparent - // black (all 0s), we set White color here so we can test - // the case of all 1s with a 0 alpha - save_paint.setColor(DlColor::kWhite()); - save_paint.setAlpha(0); - builder.SaveLayer(nullptr, &save_paint); - }); - run_tests("Dst blended SaveLayer", // - [](DisplayListBuilder& builder, DlPaint& paint) { - DlPaint save_paint; - save_paint.setBlendMode(DlBlendMode::kDst); - builder.SaveLayer(nullptr, &save_paint); - }); - run_tests( - "Nop inside SaveLayer", - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.SaveLayer(nullptr, nullptr); - paint.setBlendMode(DlBlendMode::kDst); - }, - 2u); - run_tests("DrawImage inside Culled SaveLayer", // - [](DisplayListBuilder& builder, DlPaint& paint) { - DlPaint save_paint; - save_paint.setColor(DlColor::kTransparent()); - builder.SaveLayer(nullptr, &save_paint); - builder.DrawImage(TestImage1, {10, 10}, DlImageSampling::kLinear); - }); -} - } // namespace testing } // namespace flutter diff --git a/display_list/dl_builder.cc b/display_list/dl_builder.cc index 266a8609ec5ed..ea2a132580780 100644 --- a/display_list/dl_builder.cc +++ b/display_list/dl_builder.cc @@ -6,12 +6,10 @@ #include "flutter/display_list/display_list.h" #include "flutter/display_list/dl_blend_mode.h" -#include "flutter/display_list/dl_op_flags.h" #include "flutter/display_list/dl_op_records.h" #include "flutter/display_list/effects/dl_color_source.h" #include "flutter/display_list/utils/dl_bounds_accumulator.h" #include "fml/logging.h" -#include "third_party/skia/include/core/SkScalar.h" namespace flutter { @@ -72,22 +70,20 @@ sk_sp DisplayListBuilder::Build() { int count = render_op_count_; size_t nested_bytes = nested_bytes_; int nested_count = nested_op_count_; - bool compatible = current_layer_->is_group_opacity_compatible(); + bool compatible = layer_stack_.back().is_group_opacity_compatible(); bool is_safe = is_ui_thread_safe_; - bool affects_transparency = current_layer_->affects_transparent_layer(); used_ = allocated_ = render_op_count_ = op_index_ = 0; nested_bytes_ = nested_op_count_ = 0; - is_ui_thread_safe_ = true; storage_.realloc(bytes); layer_stack_.pop_back(); layer_stack_.emplace_back(); tracker_.reset(); current_ = DlPaint(); - return sk_sp(new DisplayList( - std::move(storage_), bytes, count, nested_bytes, nested_count, bounds(), - compatible, is_safe, affects_transparency, rtree())); + return sk_sp( + new DisplayList(std::move(storage_), bytes, count, nested_bytes, + nested_count, bounds(), compatible, is_safe, rtree())); } DisplayListBuilder::DisplayListBuilder(const SkRect& cull_rect, @@ -393,11 +389,9 @@ void DisplayListBuilder::checkForDeferredSave() { } void DisplayListBuilder::Save() { - bool is_nop = current_layer_->is_nop_; layer_stack_.emplace_back(); current_layer_ = &layer_stack_.back(); current_layer_->has_deferred_save_op_ = true; - current_layer_->is_nop_ = is_nop; tracker_.save(); accumulator()->save(); } @@ -484,16 +478,18 @@ void DisplayListBuilder::saveLayer(const SkRect* bounds, const SaveLayerOptions in_options, const DlImageFilter* backdrop) { SaveLayerOptions options = in_options.without_optimizations(); - DisplayListAttributeFlags flags = options.renders_with_attributes() - ? kSaveLayerWithPaintFlags - : kSaveLayerFlags; - OpResult result = PaintResult(current_, flags); - if (result == OpResult::kNoEffect) { - save(); - current_layer_->is_nop_ = true; - return; - } size_t save_layer_offset = used_; + if (backdrop) { + bounds // + ? Push(0, 1, options, *bounds, backdrop) + : Push(0, 1, options, backdrop); + } else { + bounds // + ? Push(0, 1, options, *bounds) + : Push(0, 1, options); + } + CheckLayerOpacityCompatibility(options.renders_with_attributes()); + if (options.renders_with_attributes()) { // The actual flood of the outer layer clip will occur after the // (eventual) corresponding restore is called, but rather than @@ -504,41 +500,17 @@ void DisplayListBuilder::saveLayer(const SkRect* bounds, // with its full bounds and the right op_index so that it doesn't // get culled during rendering. if (!paint_nops_on_transparency()) { - // We will fill the clip of the outer layer when we restore. - // Accumulate should always return true here because if the - // clip was empty then that would have been caught up above - // when we tested the PaintResult. - [[maybe_unused]] bool unclipped = AccumulateUnbounded(); - FML_DCHECK(unclipped); + // We will fill the clip of the outer layer when we restore + AccumulateUnbounded(); } - CheckLayerOpacityCompatibility(true); layer_stack_.emplace_back(save_layer_offset, true, current_.getImageFilter()); } else { - CheckLayerOpacityCompatibility(false); layer_stack_.emplace_back(save_layer_offset, true, nullptr); } - current_layer_ = &layer_stack_.back(); - tracker_.save(); accumulator()->save(); - - if (backdrop) { - // A backdrop will affect up to the entire surface, bounded by the clip - // Accumulate should always return true here because if the - // clip was empty then that would have been caught up above - // when we tested the PaintResult. - [[maybe_unused]] bool unclipped = AccumulateUnbounded(); - FML_DCHECK(unclipped); - bounds // - ? Push(0, 1, options, *bounds, backdrop) - : Push(0, 1, options, backdrop); - } else { - bounds // - ? Push(0, 1, options, *bounds) - : Push(0, 1, options); - } - + current_layer_ = &layer_stack_.back(); if (options.renders_with_attributes()) { // |current_opacity_compatibility_| does not take an ImageFilter into // account because an individual primitive with an ImageFilter can apply @@ -549,7 +521,6 @@ void DisplayListBuilder::saveLayer(const SkRect* bounds, UpdateLayerOpacityCompatibility(false); } } - UpdateLayerResult(result); // Even though Skia claims that the bounds are only a hint, they actually // use them as the temporary layer bounds during rendering the layer, so @@ -557,6 +528,10 @@ void DisplayListBuilder::saveLayer(const SkRect* bounds, if (bounds) { tracker_.clipRect(*bounds, ClipOp::kIntersect, false); } + if (backdrop) { + // A backdrop will affect up to the entire surface, bounded by the clip + AccumulateUnbounded(); + } } void DisplayListBuilder::SaveLayer(const SkRect* bounds, const DlPaint* paint, @@ -679,11 +654,6 @@ void DisplayListBuilder::ClipRect(const SkRect& rect, if (!rect.isFinite()) { return; } - tracker_.clipRect(rect, clip_op, is_aa); - if (current_layer_->is_nop_ || tracker_.is_cull_rect_empty()) { - current_layer_->is_nop_ = true; - return; - } checkForDeferredSave(); switch (clip_op) { case ClipOp::kIntersect: @@ -693,6 +663,7 @@ void DisplayListBuilder::ClipRect(const SkRect& rect, Push(0, 1, rect, is_aa); break; } + tracker_.clipRect(rect, clip_op, is_aa); } void DisplayListBuilder::ClipRRect(const SkRRect& rrect, ClipOp clip_op, @@ -700,11 +671,6 @@ void DisplayListBuilder::ClipRRect(const SkRRect& rrect, if (rrect.isRect()) { clipRect(rrect.rect(), clip_op, is_aa); } else { - tracker_.clipRRect(rrect, clip_op, is_aa); - if (current_layer_->is_nop_ || tracker_.is_cull_rect_empty()) { - current_layer_->is_nop_ = true; - return; - } checkForDeferredSave(); switch (clip_op) { case ClipOp::kIntersect: @@ -714,6 +680,7 @@ void DisplayListBuilder::ClipRRect(const SkRRect& rrect, Push(0, 1, rrect, is_aa); break; } + tracker_.clipRRect(rrect, clip_op, is_aa); } } void DisplayListBuilder::ClipPath(const SkPath& path, @@ -736,11 +703,6 @@ void DisplayListBuilder::ClipPath(const SkPath& path, return; } } - tracker_.clipPath(path, clip_op, is_aa); - if (current_layer_->is_nop_ || tracker_.is_cull_rect_empty()) { - current_layer_->is_nop_ = true; - return; - } checkForDeferredSave(); switch (clip_op) { case ClipOp::kIntersect: @@ -750,6 +712,7 @@ void DisplayListBuilder::ClipPath(const SkPath& path, Push(0, 1, path, is_aa); break; } + tracker_.clipPath(path, clip_op, is_aa); } bool DisplayListBuilder::QuickReject(const SkRect& bounds) const { @@ -757,36 +720,27 @@ bool DisplayListBuilder::QuickReject(const SkRect& bounds) const { } void DisplayListBuilder::drawPaint() { - OpResult result = PaintResult(current_, kDrawPaintFlags); - if (result != OpResult::kNoEffect && AccumulateUnbounded()) { - Push(0, 1); - CheckLayerOpacityCompatibility(); - UpdateLayerResult(result); - } + Push(0, 1); + CheckLayerOpacityCompatibility(); + AccumulateUnbounded(); } void DisplayListBuilder::DrawPaint(const DlPaint& paint) { SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawPaintFlags); drawPaint(); } void DisplayListBuilder::DrawColor(DlColor color, DlBlendMode mode) { - OpResult result = PaintResult(DlPaint(color).setBlendMode(mode)); - if (result != OpResult::kNoEffect && AccumulateUnbounded()) { - Push(0, 1, color, mode); - CheckLayerOpacityCompatibility(mode); - UpdateLayerResult(result); - } + Push(0, 1, color, mode); + CheckLayerOpacityCompatibility(mode); + AccumulateUnbounded(); } void DisplayListBuilder::drawLine(const SkPoint& p0, const SkPoint& p1) { + Push(0, 1, p0, p1); + CheckLayerOpacityCompatibility(); SkRect bounds = SkRect::MakeLTRB(p0.fX, p0.fY, p1.fX, p1.fY).makeSorted(); DisplayListAttributeFlags flags = (bounds.width() > 0.0f && bounds.height() > 0.0f) ? kDrawLineFlags : kDrawHVLineFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && AccumulateOpBounds(bounds, flags)) { - Push(0, 1, p0, p1); - CheckLayerOpacityCompatibility(); - UpdateLayerResult(result); - } + AccumulateOpBounds(bounds, flags); } void DisplayListBuilder::DrawLine(const SkPoint& p0, const SkPoint& p1, @@ -795,45 +749,29 @@ void DisplayListBuilder::DrawLine(const SkPoint& p0, drawLine(p0, p1); } void DisplayListBuilder::drawRect(const SkRect& rect) { - DisplayListAttributeFlags flags = kDrawRectFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && - AccumulateOpBounds(rect.makeSorted(), flags)) { - Push(0, 1, rect); - CheckLayerOpacityCompatibility(); - UpdateLayerResult(result); - } + Push(0, 1, rect); + CheckLayerOpacityCompatibility(); + AccumulateOpBounds(rect.makeSorted(), kDrawRectFlags); } void DisplayListBuilder::DrawRect(const SkRect& rect, const DlPaint& paint) { SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawRectFlags); drawRect(rect); } void DisplayListBuilder::drawOval(const SkRect& bounds) { - DisplayListAttributeFlags flags = kDrawOvalFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && - AccumulateOpBounds(bounds.makeSorted(), flags)) { - Push(0, 1, bounds); - CheckLayerOpacityCompatibility(); - UpdateLayerResult(result); - } + Push(0, 1, bounds); + CheckLayerOpacityCompatibility(); + AccumulateOpBounds(bounds.makeSorted(), kDrawOvalFlags); } void DisplayListBuilder::DrawOval(const SkRect& bounds, const DlPaint& paint) { SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawOvalFlags); drawOval(bounds); } void DisplayListBuilder::drawCircle(const SkPoint& center, SkScalar radius) { - DisplayListAttributeFlags flags = kDrawCircleFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect) { - SkRect bounds = SkRect::MakeLTRB(center.fX - radius, center.fY - radius, - center.fX + radius, center.fY + radius); - if (AccumulateOpBounds(bounds, flags)) { - Push(0, 1, center, radius); - CheckLayerOpacityCompatibility(); - UpdateLayerResult(result); - } - } + Push(0, 1, center, radius); + CheckLayerOpacityCompatibility(); + AccumulateOpBounds(SkRect::MakeLTRB(center.fX - radius, center.fY - radius, + center.fX + radius, center.fY + radius), + kDrawCircleFlags); } void DisplayListBuilder::DrawCircle(const SkPoint& center, SkScalar radius, @@ -847,14 +785,9 @@ void DisplayListBuilder::drawRRect(const SkRRect& rrect) { } else if (rrect.isOval()) { drawOval(rrect.rect()); } else { - DisplayListAttributeFlags flags = kDrawRRectFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && - AccumulateOpBounds(rrect.getBounds(), flags)) { - Push(0, 1, rrect); - CheckLayerOpacityCompatibility(); - UpdateLayerResult(result); - } + Push(0, 1, rrect); + CheckLayerOpacityCompatibility(); + AccumulateOpBounds(rrect.getBounds(), kDrawRRectFlags); } } void DisplayListBuilder::DrawRRect(const SkRRect& rrect, const DlPaint& paint) { @@ -863,14 +796,9 @@ void DisplayListBuilder::DrawRRect(const SkRRect& rrect, const DlPaint& paint) { } void DisplayListBuilder::drawDRRect(const SkRRect& outer, const SkRRect& inner) { - DisplayListAttributeFlags flags = kDrawDRRectFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && - AccumulateOpBounds(outer.getBounds(), flags)) { - Push(0, 1, outer, inner); - CheckLayerOpacityCompatibility(); - UpdateLayerResult(result); - } + Push(0, 1, outer, inner); + CheckLayerOpacityCompatibility(); + AccumulateOpBounds(outer.getBounds(), kDrawDRRectFlags); } void DisplayListBuilder::DrawDRRect(const SkRRect& outer, const SkRRect& inner, @@ -879,17 +807,12 @@ void DisplayListBuilder::DrawDRRect(const SkRRect& outer, drawDRRect(outer, inner); } void DisplayListBuilder::drawPath(const SkPath& path) { - DisplayListAttributeFlags flags = kDrawPathFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect) { - bool is_visible = path.isInverseFillType() - ? AccumulateUnbounded() - : AccumulateOpBounds(path.getBounds(), flags); - if (is_visible) { - Push(0, 1, path); - CheckLayerOpacityHairlineCompatibility(); - UpdateLayerResult(result); - } + Push(0, 1, path); + CheckLayerOpacityHairlineCompatibility(); + if (path.isInverseFillType()) { + AccumulateUnbounded(); + } else { + AccumulateOpBounds(path.getBounds(), kDrawPathFlags); } } void DisplayListBuilder::DrawPath(const SkPath& path, const DlPaint& paint) { @@ -901,23 +824,19 @@ void DisplayListBuilder::drawArc(const SkRect& bounds, SkScalar start, SkScalar sweep, bool useCenter) { - DisplayListAttributeFlags flags = // - useCenter // - ? kDrawArcWithCenterFlags - : kDrawArcNoCenterFlags; - OpResult result = PaintResult(current_, flags); + Push(0, 1, bounds, start, sweep, useCenter); + if (useCenter) { + CheckLayerOpacityHairlineCompatibility(); + } else { + CheckLayerOpacityCompatibility(); + } // This could be tighter if we compute where the start and end // angles are and then also consider the quadrants swept and // the center if specified. - if (result != OpResult::kNoEffect && AccumulateOpBounds(bounds, flags)) { - Push(0, 1, bounds, start, sweep, useCenter); - if (useCenter) { - CheckLayerOpacityHairlineCompatibility(); - } else { - CheckLayerOpacityCompatibility(); - } - UpdateLayerResult(result); - } + AccumulateOpBounds(bounds, + useCenter // + ? kDrawArcWithCenterFlags + : kDrawArcNoCenterFlags); } void DisplayListBuilder::DrawArc(const SkRect& bounds, SkScalar start, @@ -928,31 +847,14 @@ void DisplayListBuilder::DrawArc(const SkRect& bounds, paint, useCenter ? kDrawArcWithCenterFlags : kDrawArcNoCenterFlags); drawArc(bounds, start, sweep, useCenter); } - -DisplayListAttributeFlags DisplayListBuilder::FlagsForPointMode( - PointMode mode) { - switch (mode) { - case DlCanvas::PointMode::kPoints: - return kDrawPointsAsPointsFlags; - case PointMode::kLines: - return kDrawPointsAsLinesFlags; - case PointMode::kPolygon: - return kDrawPointsAsPolygonFlags; - } - FML_UNREACHABLE(); -} void DisplayListBuilder::drawPoints(PointMode mode, uint32_t count, const SkPoint pts[]) { if (count == 0) { return; } - DisplayListAttributeFlags flags = FlagsForPointMode(mode); - OpResult result = PaintResult(current_, flags); - if (result == OpResult::kNoEffect) { - return; - } + void* data_ptr; FML_DCHECK(count < DlOpReceiver::kMaxDrawPointsCount); int bytes = count * sizeof(SkPoint); RectBoundsAccumulator ptBounds; @@ -960,23 +862,21 @@ void DisplayListBuilder::drawPoints(PointMode mode, ptBounds.accumulate(pts[i]); } SkRect point_bounds = ptBounds.bounds(); - if (!AccumulateOpBounds(point_bounds, flags)) { - return; - } - - void* data_ptr; switch (mode) { case PointMode::kPoints: data_ptr = Push(bytes, 1, count); + AccumulateOpBounds(point_bounds, kDrawPointsAsPointsFlags); break; case PointMode::kLines: data_ptr = Push(bytes, 1, count); + AccumulateOpBounds(point_bounds, kDrawPointsAsLinesFlags); break; case PointMode::kPolygon: data_ptr = Push(bytes, 1, count); + AccumulateOpBounds(point_bounds, kDrawPointsAsPolygonFlags); break; default: - FML_UNREACHABLE(); + FML_DCHECK(false); return; } CopyV(data_ptr, pts, count); @@ -986,30 +886,39 @@ void DisplayListBuilder::drawPoints(PointMode mode, // bounds of every sub-primitive. // See: https://fiddle.skia.org/c/228459001d2de8db117ce25ef5cedb0c UpdateLayerOpacityCompatibility(false); - UpdateLayerResult(result); } void DisplayListBuilder::DrawPoints(PointMode mode, uint32_t count, const SkPoint pts[], const DlPaint& paint) { - SetAttributesFromPaint(paint, FlagsForPointMode(mode)); + const DisplayListAttributeFlags* flags; + switch (mode) { + case PointMode::kPoints: + flags = &DisplayListOpFlags::kDrawPointsAsPointsFlags; + break; + case PointMode::kLines: + flags = &DisplayListOpFlags::kDrawPointsAsLinesFlags; + break; + case PointMode::kPolygon: + flags = &DisplayListOpFlags::kDrawPointsAsPolygonFlags; + break; + default: + FML_DCHECK(false); + return; + } + SetAttributesFromPaint(paint, *flags); drawPoints(mode, count, pts); } void DisplayListBuilder::drawVertices(const DlVertices* vertices, DlBlendMode mode) { - DisplayListAttributeFlags flags = kDrawVerticesFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && - AccumulateOpBounds(vertices->bounds(), flags)) { - void* pod = Push(vertices->size(), 1, mode); - new (pod) DlVertices(vertices); - // DrawVertices applies its colors to the paint so we have no way - // of controlling opacity using the current paint attributes. - // Although, examination of the |mode| might find some predictable - // cases. - UpdateLayerOpacityCompatibility(false); - UpdateLayerResult(result); - } + void* pod = Push(vertices->size(), 1, mode); + new (pod) DlVertices(vertices); + // DrawVertices applies its colors to the paint so we have no way + // of controlling opacity using the current paint attributes. + // Although, examination of the |mode| might find some predictable + // cases. + UpdateLayerOpacityCompatibility(false); + AccumulateOpBounds(vertices->bounds(), kDrawVerticesFlags); } void DisplayListBuilder::DrawVertices(const DlVertices* vertices, DlBlendMode mode, @@ -1022,23 +931,17 @@ void DisplayListBuilder::drawImage(const sk_sp image, const SkPoint point, DlImageSampling sampling, bool render_with_attributes) { + render_with_attributes + ? Push(0, 1, image, point, sampling) + : Push(0, 1, image, point, sampling); + CheckLayerOpacityCompatibility(render_with_attributes); + is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe(); + SkRect bounds = SkRect::MakeXYWH(point.fX, point.fY, // + image->width(), image->height()); DisplayListAttributeFlags flags = render_with_attributes // ? kDrawImageWithPaintFlags : kDrawImageFlags; - OpResult result = PaintResult(current_, flags); - if (result == OpResult::kNoEffect) { - return; - } - SkRect bounds = SkRect::MakeXYWH(point.fX, point.fY, // - image->width(), image->height()); - if (AccumulateOpBounds(bounds, flags)) { - render_with_attributes - ? Push(0, 1, image, point, sampling) - : Push(0, 1, image, point, sampling); - CheckLayerOpacityCompatibility(render_with_attributes); - UpdateLayerResult(result); - is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe(); - } + AccumulateOpBounds(bounds, flags); } void DisplayListBuilder::DrawImage(const sk_sp& image, const SkPoint point, @@ -1058,17 +961,14 @@ void DisplayListBuilder::drawImageRect(const sk_sp image, DlImageSampling sampling, bool render_with_attributes, SrcRectConstraint constraint) { + Push(0, 1, image, src, dst, sampling, render_with_attributes, + constraint); + CheckLayerOpacityCompatibility(render_with_attributes); + is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe(); DisplayListAttributeFlags flags = render_with_attributes ? kDrawImageRectWithPaintFlags : kDrawImageRectFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && AccumulateOpBounds(dst, flags)) { - Push(0, 1, image, src, dst, sampling, - render_with_attributes, constraint); - CheckLayerOpacityCompatibility(render_with_attributes); - UpdateLayerResult(result); - is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe(); - } + AccumulateOpBounds(dst, flags); } void DisplayListBuilder::DrawImageRect(const sk_sp& image, const SkRect& src, @@ -1089,18 +989,15 @@ void DisplayListBuilder::drawImageNine(const sk_sp image, const SkRect& dst, DlFilterMode filter, bool render_with_attributes) { + render_with_attributes + ? Push(0, 1, image, center, dst, filter) + : Push(0, 1, image, center, dst, filter); + CheckLayerOpacityCompatibility(render_with_attributes); + is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe(); DisplayListAttributeFlags flags = render_with_attributes ? kDrawImageNineWithPaintFlags : kDrawImageNineFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && AccumulateOpBounds(dst, flags)) { - render_with_attributes - ? Push(0, 1, image, center, dst, filter) - : Push(0, 1, image, center, dst, filter); - CheckLayerOpacityCompatibility(render_with_attributes); - UpdateLayerResult(result); - is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe(); - } + AccumulateOpBounds(dst, flags); } void DisplayListBuilder::DrawImageNine(const sk_sp& image, const SkIRect& center, @@ -1124,27 +1021,6 @@ void DisplayListBuilder::drawAtlas(const sk_sp atlas, DlImageSampling sampling, const SkRect* cull_rect, bool render_with_attributes) { - DisplayListAttributeFlags flags = render_with_attributes // - ? kDrawAtlasWithPaintFlags - : kDrawAtlasFlags; - OpResult result = PaintResult(current_, flags); - if (result == OpResult::kNoEffect) { - return; - } - SkPoint quad[4]; - RectBoundsAccumulator atlasBounds; - for (int i = 0; i < count; i++) { - const SkRect& src = tex[i]; - xform[i].toQuad(src.width(), src.height(), quad); - for (int j = 0; j < 4; j++) { - atlasBounds.accumulate(quad[j]); - } - } - if (atlasBounds.is_empty() || - !AccumulateOpBounds(atlasBounds.bounds(), flags)) { - return; - } - int bytes = count * (sizeof(SkRSXform) + sizeof(SkRect)); void* data_ptr; if (colors != nullptr) { @@ -1173,8 +1049,23 @@ void DisplayListBuilder::drawAtlas(const sk_sp atlas, // on it to distribute the opacity without overlap without checking all // of the transforms and texture rectangles. UpdateLayerOpacityCompatibility(false); - UpdateLayerResult(result); is_ui_thread_safe_ = is_ui_thread_safe_ && atlas->isUIThreadSafe(); + + SkPoint quad[4]; + RectBoundsAccumulator atlasBounds; + for (int i = 0; i < count; i++) { + const SkRect& src = tex[i]; + xform[i].toQuad(src.width(), src.height(), quad); + for (int j = 0; j < 4; j++) { + atlasBounds.accumulate(quad[j]); + } + } + if (atlasBounds.is_not_empty()) { + DisplayListAttributeFlags flags = render_with_attributes // + ? kDrawAtlasWithPaintFlags + : kDrawAtlasFlags; + AccumulateOpBounds(atlasBounds.bounds(), flags); + } } void DisplayListBuilder::DrawAtlas(const sk_sp& atlas, const SkRSXform xform[], @@ -1198,49 +1089,35 @@ void DisplayListBuilder::DrawAtlas(const sk_sp& atlas, void DisplayListBuilder::DrawDisplayList(const sk_sp display_list, SkScalar opacity) { - if (!SkScalarIsFinite(opacity) || opacity <= SK_ScalarNearlyZero || - display_list->op_count() == 0 || display_list->bounds().isEmpty() || - current_layer_->is_nop_) { - return; - } + DlPaint current_paint = current_; + Push(0, 1, display_list, opacity); + is_ui_thread_safe_ = is_ui_thread_safe_ && display_list->isUIThreadSafe(); + // Not really necessary if the developer is interacting with us via + // our attribute-state-less DlCanvas methods, but this avoids surprises + // for those who may have been using the stateful Dispatcher methods. + SetAttributesFromPaint(current_paint, + DisplayListOpFlags::kSaveLayerWithPaintFlags); + const SkRect bounds = display_list->bounds(); - bool accumulated; switch (accumulator()->type()) { case BoundsAccumulatorType::kRect: - accumulated = AccumulateOpBounds(bounds, kDrawDisplayListFlags); + AccumulateOpBounds(bounds, kDrawDisplayListFlags); break; case BoundsAccumulatorType::kRTree: auto rtree = display_list->rtree(); if (rtree) { std::list rects = rtree->searchAndConsolidateRects(bounds, false); - accumulated = false; for (const SkRect& rect : rects) { // TODO (https://github.com/flutter/flutter/issues/114919): Attributes // are not necessarily `kDrawDisplayListFlags`. - if (AccumulateOpBounds(rect, kDrawDisplayListFlags)) { - accumulated = true; - } + AccumulateOpBounds(rect, kDrawDisplayListFlags); } } else { - accumulated = AccumulateOpBounds(bounds, kDrawDisplayListFlags); + AccumulateOpBounds(bounds, kDrawDisplayListFlags); } break; } - if (!accumulated) { - return; - } - - DlPaint current_paint = current_; - Push(0, 1, display_list, - opacity < SK_Scalar1 ? opacity : SK_Scalar1); - is_ui_thread_safe_ = is_ui_thread_safe_ && display_list->isUIThreadSafe(); - // Not really necessary if the developer is interacting with us via - // our attribute-state-less DlCanvas methods, but this avoids surprises - // for those who may have been using the stateful Dispatcher methods. - SetAttributesFromPaint(current_paint, - DisplayListOpFlags::kSaveLayerWithPaintFlags); - // The non-nested op count accumulated in the |Push| method will include // this call to |drawDisplayList| for non-nested op count metrics. // But, for nested op count metrics we want the |drawDisplayList| call itself @@ -1250,38 +1127,18 @@ void DisplayListBuilder::DrawDisplayList(const sk_sp display_list, nested_op_count_ += display_list->op_count(true) - 1; nested_bytes_ += display_list->bytes(true); UpdateLayerOpacityCompatibility(display_list->can_apply_group_opacity()); - // Nop DisplayLists are eliminated above so we either affect transparent - // pixels or we do not. We should not have [kNoEffect]. - UpdateLayerResult(display_list->modifies_transparent_black() - ? OpResult::kAffectsAll - : OpResult::kPreservesTransparency); } void DisplayListBuilder::drawTextBlob(const sk_sp blob, SkScalar x, SkScalar y) { - DisplayListAttributeFlags flags = kDrawTextBlobFlags; - OpResult result = PaintResult(current_, flags); - if (result == OpResult::kNoEffect) { - return; - } - bool unclipped = AccumulateOpBounds(blob->bounds().makeOffset(x, y), flags); - // TODO(https://github.com/flutter/flutter/issues/82202): Remove once the - // unit tests can use Fuchsia's font manager instead of the empty default. - // Until then we might encounter empty bounds for otherwise valid text and - // thus we ignore the results from AccumulateOpBounds. -#if defined(OS_FUCHSIA) - unclipped = true; -#endif // OS_FUCHSIA - if (unclipped) { - Push(0, 1, blob, x, y); - // There is no way to query if the glyphs of a text blob overlap and - // there are no current guarantees from either Skia or Impeller that - // they will protect overlapping glyphs from the effects of overdraw - // so we must make the conservative assessment that this DL layer is - // not compatible with group opacity inheritance. - UpdateLayerOpacityCompatibility(false); - UpdateLayerResult(result); - } + Push(0, 1, blob, x, y); + AccumulateOpBounds(blob->bounds().makeOffset(x, y), kDrawTextBlobFlags); + // There is no way to query if the glyphs of a text blob overlap and + // there are no current guarantees from either Skia or Impeller that + // they will protect overlapping glyphs from the effects of overdraw + // so we must make the conservative assessment that this DL layer is + // not compatible with group opacity inheritance. + UpdateLayerOpacityCompatibility(false); } void DisplayListBuilder::DrawTextBlob(const sk_sp& blob, SkScalar x, @@ -1295,19 +1152,14 @@ void DisplayListBuilder::DrawShadow(const SkPath& path, const SkScalar elevation, bool transparent_occluder, SkScalar dpr) { - OpResult result = PaintResult(DlPaint(color)); - if (result != OpResult::kNoEffect) { - SkRect shadow_bounds = - DlCanvas::ComputeShadowBounds(path, elevation, dpr, GetTransform()); - if (AccumulateOpBounds(shadow_bounds, kDrawShadowFlags)) { - transparent_occluder // - ? Push(0, 1, path, color, elevation, - dpr) - : Push(0, 1, path, color, elevation, dpr); - UpdateLayerOpacityCompatibility(false); - UpdateLayerResult(result); - } - } + transparent_occluder // + ? Push(0, 1, path, color, elevation, dpr) + : Push(0, 1, path, color, elevation, dpr); + + SkRect shadow_bounds = + DlCanvas::ComputeShadowBounds(path, elevation, dpr, GetTransform()); + AccumulateOpBounds(shadow_bounds, kDrawShadowFlags); + UpdateLayerOpacityCompatibility(false); } bool DisplayListBuilder::ComputeFilteredBounds(SkRect& bounds, @@ -1377,40 +1229,31 @@ bool DisplayListBuilder::AdjustBoundsForPaint(SkRect& bounds, return true; } -bool DisplayListBuilder::AccumulateUnbounded() { - SkRect clip = tracker_.device_cull_rect(); - if (clip.isEmpty()) { - return false; - } - accumulator()->accumulate(clip, op_index_); - return true; +void DisplayListBuilder::AccumulateUnbounded() { + accumulator()->accumulate(tracker_.device_cull_rect(), op_index_ - 1); } -bool DisplayListBuilder::AccumulateOpBounds(SkRect& bounds, +void DisplayListBuilder::AccumulateOpBounds(SkRect& bounds, DisplayListAttributeFlags flags) { if (AdjustBoundsForPaint(bounds, flags)) { - return AccumulateBounds(bounds); + AccumulateBounds(bounds); } else { - return AccumulateUnbounded(); + AccumulateUnbounded(); } } -bool DisplayListBuilder::AccumulateBounds(SkRect& bounds) { - if (!bounds.isEmpty()) { - tracker_.mapRect(&bounds); - if (bounds.intersect(tracker_.device_cull_rect())) { - accumulator()->accumulate(bounds, op_index_); - return true; - } +void DisplayListBuilder::AccumulateBounds(SkRect& bounds) { + tracker_.mapRect(&bounds); + if (bounds.intersect(tracker_.device_cull_rect())) { + accumulator()->accumulate(bounds, op_index_ - 1); } - return false; } bool DisplayListBuilder::paint_nops_on_transparency() { // SkImageFilter::canComputeFastBounds tests for transparency behavior // This test assumes that the blend mode checked down below will // NOP on transparent black. - if (current_.getImageFilterPtr() && - current_.getImageFilterPtr()->modifies_transparent_black()) { + if (current_.getImageFilter() && + current_.getImageFilter()->modifies_transparent_black()) { return false; } @@ -1420,8 +1263,8 @@ bool DisplayListBuilder::paint_nops_on_transparency() { // save layer untouched out to the edge of the output surface. // This test assumes that the blend mode checked down below will // NOP on transparent black. - if (current_.getColorFilterPtr() && - current_.getColorFilterPtr()->modifies_transparent_black()) { + if (current_.getColorFilter() && + current_.getColorFilter()->modifies_transparent_black()) { return false; } @@ -1478,130 +1321,4 @@ bool DisplayListBuilder::paint_nops_on_transparency() { break; } } - -DlColor DisplayListBuilder::GetEffectiveColor(const DlPaint& paint, - DisplayListAttributeFlags flags) { - DlColor color; - if (flags.applies_color()) { - const DlColorSource* source = paint.getColorSourcePtr(); - if (source) { - if (source->asColor()) { - color = source->asColor()->color(); - } else { - color = source->is_opaque() ? DlColor::kBlack() : kAnyColor; - } - } else { - color = paint.getColor(); - } - } else if (flags.applies_alpha()) { - // If the operation applies alpha, but not color, then the only impact - // of the alpha is to modulate the output towards transparency. - // We can not guarantee an opaque source even if the alpha is opaque - // since that would require knowing something about the colors that - // the alpha is modulating, but we can guarantee a transparent source - // if the alpha is 0. - color = (paint.getAlpha() == 0) ? DlColor::kTransparent() : kAnyColor; - } else { - color = kAnyColor; - } - if (flags.applies_image_filter()) { - auto filter = paint.getImageFilterPtr(); - if (filter) { - if (!color.isTransparent() || filter->modifies_transparent_black()) { - color = kAnyColor; - } - } - } - if (flags.applies_color_filter()) { - auto filter = paint.getColorFilterPtr(); - if (filter) { - if (!color.isTransparent() || filter->modifies_transparent_black()) { - color = kAnyColor; - } - } - } - return color; -} - -DisplayListBuilder::OpResult DisplayListBuilder::PaintResult( - const DlPaint& paint, - DisplayListAttributeFlags flags) { - if (current_layer_->is_nop_) { - return OpResult::kNoEffect; - } - if (flags.applies_blend()) { - switch (paint.getBlendMode()) { - // Nop blend mode (singular, there is only one) - case DlBlendMode::kDst: - return OpResult::kNoEffect; - - // Always clears pixels blend mode (singular, there is only one) - case DlBlendMode::kClear: - return OpResult::kPreservesTransparency; - - case DlBlendMode::kHue: - case DlBlendMode::kSaturation: - case DlBlendMode::kColor: - case DlBlendMode::kLuminosity: - case DlBlendMode::kColorBurn: - return GetEffectiveColor(paint, flags).isTransparent() - ? OpResult::kNoEffect - : OpResult::kAffectsAll; - - // kSrcIn modifies pixels towards transparency - case DlBlendMode::kSrcIn: - return OpResult::kPreservesTransparency; - - // These blend modes preserve destination alpha - case DlBlendMode::kSrcATop: - case DlBlendMode::kDstOut: - return GetEffectiveColor(paint, flags).isTransparent() - ? OpResult::kNoEffect - : OpResult::kPreservesTransparency; - - // Always destructive blend modes, potentially not affecting transparency - case DlBlendMode::kSrc: - case DlBlendMode::kSrcOut: - case DlBlendMode::kDstATop: - return GetEffectiveColor(paint, flags).isTransparent() - ? OpResult::kPreservesTransparency - : OpResult::kAffectsAll; - - // The kDstIn blend mode modifies the destination unless the - // source color is opaque. - case DlBlendMode::kDstIn: - return GetEffectiveColor(paint, flags).isOpaque() - ? OpResult::kNoEffect - : OpResult::kPreservesTransparency; - - // The next group of blend modes modifies the destination unless the - // source color is transparent. - case DlBlendMode::kSrcOver: - case DlBlendMode::kDstOver: - case DlBlendMode::kXor: - case DlBlendMode::kPlus: - case DlBlendMode::kScreen: - case DlBlendMode::kMultiply: - case DlBlendMode::kOverlay: - case DlBlendMode::kDarken: - case DlBlendMode::kLighten: - case DlBlendMode::kColorDodge: - case DlBlendMode::kHardLight: - case DlBlendMode::kSoftLight: - case DlBlendMode::kDifference: - case DlBlendMode::kExclusion: - return GetEffectiveColor(paint, flags).isTransparent() - ? OpResult::kNoEffect - : OpResult::kAffectsAll; - - // Modulate only leaves the pixel alone when the source is white. - case DlBlendMode::kModulate: - return GetEffectiveColor(paint, flags) == DlColor::kWhite() - ? OpResult::kNoEffect - : OpResult::kPreservesTransparency; - } - } - return OpResult::kAffectsAll; -} - } // namespace flutter diff --git a/display_list/dl_builder.h b/display_list/dl_builder.h index ab0bce0db3c38..1d9cb8eb12299 100644 --- a/display_list/dl_builder.h +++ b/display_list/dl_builder.h @@ -506,13 +506,15 @@ class DisplayListBuilder final : public virtual DlCanvas, class LayerInfo { public: - explicit LayerInfo( - size_t save_offset = 0, - bool has_layer = false, - const std::shared_ptr& filter = nullptr) + explicit LayerInfo(size_t save_offset = 0, + bool has_layer = false, + std::shared_ptr filter = nullptr) : save_offset_(save_offset), has_layer_(has_layer), - filter_(filter) {} + cannot_inherit_opacity_(false), + has_compatible_op_(false), + filter_(filter), + is_unbounded_(false) {} // The offset into the memory buffer where the saveLayer DLOp record // for this saveLayer() call is placed. This may be needed if the @@ -525,9 +527,6 @@ class DisplayListBuilder final : public virtual DlCanvas, bool has_layer() const { return has_layer_; } bool cannot_inherit_opacity() const { return cannot_inherit_opacity_; } bool has_compatible_op() const { return has_compatible_op_; } - bool affects_transparent_layer() const { - return affects_transparent_layer_; - } bool is_group_opacity_compatible() const { return !cannot_inherit_opacity_; @@ -550,12 +549,6 @@ class DisplayListBuilder final : public virtual DlCanvas, } } - // Records that the current layer contains an op that produces visible - // output on a transparent surface. - void add_visible_op() { - affects_transparent_layer_ = true; - } - // The filter to apply to the layer bounds when it is restored std::shared_ptr filter() { return filter_; } @@ -590,13 +583,11 @@ class DisplayListBuilder final : public virtual DlCanvas, private: size_t save_offset_; bool has_layer_; - bool cannot_inherit_opacity_ = false; - bool has_compatible_op_ = false; + bool cannot_inherit_opacity_; + bool has_compatible_op_; std::shared_ptr filter_; - bool is_unbounded_ = false; + bool is_unbounded_; bool has_deferred_save_op_ = false; - bool is_nop_ = false; - bool affects_transparent_layer_ = false; friend class DisplayListBuilder; }; @@ -710,40 +701,9 @@ class DisplayListBuilder final : public virtual DlCanvas, return accumulator_->rtree(); } - static DisplayListAttributeFlags FlagsForPointMode(PointMode mode); - - enum class OpResult { - kNoEffect, - kPreservesTransparency, - kAffectsAll, - }; - bool paint_nops_on_transparency(); - OpResult PaintResult(const DlPaint& paint, - DisplayListAttributeFlags flags = kDrawPaintFlags); - - void UpdateLayerResult(OpResult result) { - switch (result) { - case OpResult::kNoEffect: - case OpResult::kPreservesTransparency: - break; - case OpResult::kAffectsAll: - current_layer_->add_visible_op(); - break; - } - } - - // kAnyColor is a non-opaque and non-transparent color that will not - // trigger any short-circuit tests about the results of a blend. - static constexpr DlColor kAnyColor = DlColor::kMidGrey().withAlpha(0x80); - static_assert(!kAnyColor.isOpaque()); - static_assert(!kAnyColor.isTransparent()); - static DlColor GetEffectiveColor(const DlPaint& paint, - DisplayListAttributeFlags flags); // Computes the bounds of an operation adjusted for a given ImageFilter - // and returns whether the computation was possible. If the method - // returns false then the caller should assume the worst about the bounds. static bool ComputeFilteredBounds(SkRect& bounds, const DlImageFilter* filter); @@ -753,24 +713,24 @@ class DisplayListBuilder final : public virtual DlCanvas, // Records the fact that we encountered an op that either could not // estimate its bounds or that fills all of the destination space. - bool AccumulateUnbounded(); + void AccumulateUnbounded(); // Records the bounds for an op after modifying them according to the // supplied attribute flags and transforming by the current matrix. - bool AccumulateOpBounds(const SkRect& bounds, + void AccumulateOpBounds(const SkRect& bounds, DisplayListAttributeFlags flags) { SkRect safe_bounds = bounds; - return AccumulateOpBounds(safe_bounds, flags); + AccumulateOpBounds(safe_bounds, flags); } // Records the bounds for an op after modifying them according to the // supplied attribute flags and transforming by the current matrix // and clipping against the current clip. - bool AccumulateOpBounds(SkRect& bounds, DisplayListAttributeFlags flags); + void AccumulateOpBounds(SkRect& bounds, DisplayListAttributeFlags flags); // Records the given bounds after transforming by the current matrix // and clipping against the current clip. - bool AccumulateBounds(SkRect& bounds); + void AccumulateBounds(SkRect& bounds); DlPaint current_; }; diff --git a/display_list/dl_color.h b/display_list/dl_color.h index 92a39150d2f2e..d926e58c3b818 100644 --- a/display_list/dl_color.h +++ b/display_list/dl_color.h @@ -34,20 +34,20 @@ struct DlColor { uint32_t argb; - constexpr bool isOpaque() const { return getAlpha() == 0xFF; } - constexpr bool isTransparent() const { return getAlpha() == 0; } + bool isOpaque() const { return getAlpha() == 0xFF; } + bool isTransparent() const { return getAlpha() == 0; } - constexpr int getAlpha() const { return argb >> 24; } - constexpr int getRed() const { return (argb >> 16) & 0xFF; } - constexpr int getGreen() const { return (argb >> 8) & 0xFF; } - constexpr int getBlue() const { return argb & 0xFF; } + int getAlpha() const { return argb >> 24; } + int getRed() const { return (argb >> 16) & 0xFF; } + int getGreen() const { return (argb >> 8) & 0xFF; } + int getBlue() const { return argb & 0xFF; } - constexpr float getAlphaF() const { return toF(getAlpha()); } - constexpr float getRedF() const { return toF(getRed()); } - constexpr float getGreenF() const { return toF(getGreen()); } - constexpr float getBlueF() const { return toF(getBlue()); } + float getAlphaF() const { return toF(getAlpha()); } + float getRedF() const { return toF(getRed()); } + float getGreenF() const { return toF(getGreen()); } + float getBlueF() const { return toF(getBlue()); } - constexpr uint32_t premultipliedArgb() const { + uint32_t premultipliedArgb() const { if (isOpaque()) { return argb; } @@ -58,20 +58,20 @@ struct DlColor { toC(getBlueF() * f); } - constexpr DlColor withAlpha(uint8_t alpha) const { // + DlColor withAlpha(uint8_t alpha) const { // return (argb & 0x00FFFFFF) | (alpha << 24); } - constexpr DlColor withRed(uint8_t red) const { // + DlColor withRed(uint8_t red) const { // return (argb & 0xFF00FFFF) | (red << 16); } - constexpr DlColor withGreen(uint8_t green) const { // + DlColor withGreen(uint8_t green) const { // return (argb & 0xFFFF00FF) | (green << 8); } - constexpr DlColor withBlue(uint8_t blue) const { // + DlColor withBlue(uint8_t blue) const { // return (argb & 0xFFFFFF00) | (blue << 0); } - constexpr DlColor modulateOpacity(float opacity) const { + DlColor modulateOpacity(float opacity) const { return opacity <= 0 ? withAlpha(0) : opacity >= 1 ? *this : withAlpha(round(getAlpha() * opacity)); diff --git a/display_list/dl_paint.h b/display_list/dl_paint.h index 3d9220f57e3d6..77619a2567164 100644 --- a/display_list/dl_paint.h +++ b/display_list/dl_paint.h @@ -83,7 +83,6 @@ class DlPaint { color_.argb = alpha << 24 | (color_.argb & 0x00FFFFFF); return *this; } - SkScalar getOpacity() const { return color_.getAlphaF(); } DlPaint& setOpacity(SkScalar opacity) { setAlpha(SkScalarRoundToInt(opacity * 0xff)); return *this; diff --git a/display_list/testing/dl_rendering_unittests.cc b/display_list/testing/dl_rendering_unittests.cc index dfcf4d8757d41..64c4acf421435 100644 --- a/display_list/testing/dl_rendering_unittests.cc +++ b/display_list/testing/dl_rendering_unittests.cc @@ -9,7 +9,6 @@ #include "flutter/display_list/dl_op_flags.h" #include "flutter/display_list/dl_sampling_options.h" #include "flutter/display_list/skia/dl_sk_canvas.h" -#include "flutter/display_list/skia/dl_sk_conversions.h" #include "flutter/display_list/skia/dl_sk_dispatcher.h" #include "flutter/display_list/testing/dl_test_surface_provider.h" #include "flutter/display_list/utils/dl_comparable.h" @@ -284,26 +283,20 @@ using BackendType = DlSurfaceProvider::BackendType; class RenderResult { public: - explicit RenderResult(const sk_sp& surface, - bool take_snapshot = false) { + explicit RenderResult(const sk_sp& surface) { SkImageInfo info = surface->imageInfo(); info = SkImageInfo::MakeN32Premul(info.dimensions()); addr_ = malloc(info.computeMinByteSize() * info.height()); pixmap_.reset(info, addr_, info.minRowBytes()); - surface->readPixels(pixmap_, 0, 0); - if (take_snapshot) { - image_ = surface->makeImageSnapshot(); - } + EXPECT_TRUE(surface->readPixels(pixmap_, 0, 0)); } ~RenderResult() { free(addr_); } - sk_sp image() const { return image_; } int width() const { return pixmap_.width(); } int height() const { return pixmap_.height(); } const uint32_t* addr32(int x, int y) const { return pixmap_.addr32(x, y); } private: - sk_sp image_; SkPixmap pixmap_; void* addr_ = nullptr; }; @@ -920,14 +913,7 @@ class CanvasCompareTester { }; DlRenderer dl_safe_restore = [=](DlCanvas* cv, const DlPaint& p) { // Draw another primitive to disable peephole optimizations - // As the rendering op rejection in the DisplayList Builder - // gets smarter and smarter, this operation has had to get - // sneakier and sneakier about specifying an operation that - // won't practically show up in the output, but technically - // can't be culled. - cv->DrawRect( - SkRect::MakeXYWH(kRenderCenterX, kRenderCenterY, 0.0001, 0.0001), - DlPaint()); + cv->DrawRect(kRenderBounds.makeOffset(500, 500), DlPaint()); cv->Restore(); }; SkRenderer sk_opt_restore = [=](SkCanvas* cv, const SkPaint& p) { @@ -3800,6 +3786,7 @@ TEST_F(DisplayListCanvas, MatrixColorFilterOpacityCommuteCheck) { } #define FOR_EACH_BLEND_MODE_ENUM(FUNC) \ + FUNC(kSrc) \ FUNC(kClear) \ FUNC(kSrc) \ FUNC(kDst) \ @@ -3830,18 +3817,6 @@ TEST_F(DisplayListCanvas, MatrixColorFilterOpacityCommuteCheck) { FUNC(kColor) \ FUNC(kLuminosity) -// This function serves both to enhance error output below and to double -// check that the macro supplies all modes (otherwise it won't compile) -static std::string BlendModeToString(DlBlendMode mode) { - switch (mode) { -#define MODE_CASE(m) \ - case DlBlendMode::m: \ - return #m; - FOR_EACH_BLEND_MODE_ENUM(MODE_CASE) -#undef MODE_CASE - } -} - TEST_F(DisplayListCanvas, BlendColorFilterModifyTransparencyCheck) { std::vector> environments; for (auto& provider : CanvasCompareTester::kTestProviders) { @@ -3852,8 +3827,7 @@ TEST_F(DisplayListCanvas, BlendColorFilterModifyTransparencyCheck) { auto test_mode_color = [&environments](DlBlendMode mode, DlColor color) { std::stringstream desc_str; - std::string mode_string = BlendModeToString(mode); - desc_str << "blend[" << mode_string << ", " << color << "]"; + desc_str << "blend[" << mode << ", " << color << "]"; std::string desc = desc_str.str(); DlBlendColorFilter filter(color, mode); if (filter.modifies_transparent_black()) { @@ -3914,8 +3888,7 @@ TEST_F(DisplayListCanvas, BlendColorFilterOpacityCommuteCheck) { auto test_mode_color = [&environments](DlBlendMode mode, DlColor color) { std::stringstream desc_str; - std::string mode_string = BlendModeToString(mode); - desc_str << "blend[" << mode_string << ", " << color << "]"; + desc_str << "blend[" << mode << ", " << color << "]"; std::string desc = desc_str.str(); DlBlendColorFilter filter(color, mode); if (filter.can_commute_with_opacity()) { @@ -3974,359 +3947,7 @@ TEST_F(DisplayListCanvas, BlendColorFilterOpacityCommuteCheck) { #undef TEST_MODE } -class DisplayListNopTest : public DisplayListCanvas { - // The following code uses the acronym MTB for "modifies_transparent_black" - - protected: - DisplayListNopTest() : DisplayListCanvas() { - test_src_colors = { - DlColor::kBlack().withAlpha(0), // transparent black - DlColor::kBlack().withAlpha(0x7f), // half transparent black - DlColor::kWhite().withAlpha(0x7f), // half transparent white - DlColor::kBlack(), // opaque black - DlColor::kWhite(), // opaque white - DlColor::kRed(), // opaque red - DlColor::kGreen(), // opaque green - DlColor::kBlue(), // opaque blue - DlColor::kDarkGrey(), // dark grey - DlColor::kLightGrey(), // light grey - }; - - // We test against a color cube of 3x3x3 colors [55,aa,ff] - // plus transparency as the first color/pixel - test_dst_colors.push_back(DlColor::kTransparent()); - const int step = 0x55; - static_assert(step * 3 == 255); - for (int a = step; a < 256; a += step) { - for (int r = step; r < 256; r += step) { - for (int g = step; g < 256; g += step) { - for (int b = step; b < 256; b += step) { - test_dst_colors.push_back(DlColor(a << 24 | r << 16 | g << 8 | b)); - } - } - } - } - - static constexpr float color_filter_matrix_nomtb[] = { - 0.0001, 0.0001, 0.0001, 0.9997, 0.0, // - 0.0001, 0.0001, 0.0001, 0.9997, 0.0, // - 0.0001, 0.0001, 0.0001, 0.9997, 0.0, // - 0.0001, 0.0001, 0.0001, 0.9997, 0.0, // - }; - static constexpr float color_filter_matrix_mtb[] = { - 0.0001, 0.0001, 0.0001, 0.9997, 0.0, // - 0.0001, 0.0001, 0.0001, 0.9997, 0.0, // - 0.0001, 0.0001, 0.0001, 0.9997, 0.0, // - 0.0001, 0.0001, 0.0001, 0.9997, 0.1, // - }; - color_filter_nomtb = DlMatrixColorFilter::Make(color_filter_matrix_nomtb); - color_filter_mtb = DlMatrixColorFilter::Make(color_filter_matrix_mtb); - EXPECT_FALSE(color_filter_nomtb->modifies_transparent_black()); - EXPECT_TRUE(color_filter_mtb->modifies_transparent_black()); - - test_data = - get_output(test_dst_colors.size(), 1, true, [this](SkCanvas* canvas) { - int x = 0; - for (DlColor color : test_dst_colors) { - SkPaint paint; - paint.setColor(color); - paint.setBlendMode(SkBlendMode::kSrc); - canvas->drawRect(SkRect::MakeXYWH(x, 0, 1, 1), paint); - x++; - } - }); - - // For image-on-image tests, the src and dest images will have repeated - // rows/columns that have every color, but laid out at right angles to - // each other so we see an interaction with every test color against - // every other test color. - int data_count = test_data->image()->width(); - test_image_dst_data = get_output( - data_count, data_count, true, [this, data_count](SkCanvas* canvas) { - ASSERT_EQ(test_data->width(), data_count); - ASSERT_EQ(test_data->height(), 1); - for (int y = 0; y < data_count; y++) { - canvas->drawImage(test_data->image().get(), 0, y); - } - }); - test_image_src_data = get_output( - data_count, data_count, true, [this, data_count](SkCanvas* canvas) { - ASSERT_EQ(test_data->width(), data_count); - ASSERT_EQ(test_data->height(), 1); - canvas->translate(data_count, 0); - canvas->rotate(90); - for (int y = 0; y < data_count; y++) { - canvas->drawImage(test_data->image().get(), 0, y); - } - }); - // Double check that the pixel data is laid out in orthogonal stripes - for (int y = 0; y < data_count; y++) { - for (int x = 0; x < data_count; x++) { - EXPECT_EQ(*test_image_dst_data->addr32(x, y), *test_data->addr32(x, 0)); - EXPECT_EQ(*test_image_src_data->addr32(x, y), *test_data->addr32(y, 0)); - } - } - } - - // These flags are 0 by default until they encounter a counter-example - // result and get set. - static constexpr int kWasNotNop = 0x1; // Some tested pixel was modified - static constexpr int kWasMTB = 0x2; // A transparent pixel was modified - - std::vector test_src_colors; - std::vector test_dst_colors; - - std::shared_ptr color_filter_nomtb; - std::shared_ptr color_filter_mtb; - - // A 1-row image containing every color in test_dst_colors - std::unique_ptr test_data; - - // A square image containing test_data duplicated in each row - std::unique_ptr test_image_dst_data; - - // A square image containing test_data duplicated in each column - std::unique_ptr test_image_src_data; - - std::unique_ptr get_output( - int w, - int h, - bool snapshot, - const std::function& renderer) { - auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(w, h)); - SkCanvas* canvas = surface->getCanvas(); - renderer(canvas); - canvas->flush(); - surface->flushAndSubmit(true); - return std::make_unique(surface, snapshot); - } - - int check_color_result(DlColor dst_color, - DlColor result_color, - const sk_sp& dl, - const std::string& desc) { - int ret = 0; - bool is_error = false; - if (dst_color.isTransparent() && !result_color.isTransparent()) { - ret |= kWasMTB; - is_error = !dl->modifies_transparent_black(); - } - if (result_color != dst_color) { - ret |= kWasNotNop; - is_error = (dl->op_count() == 0u); - } - if (is_error) { - FML_LOG(ERROR) << std::hex << dst_color << " filters to " << result_color - << desc; - } - return ret; - } - - int check_image_result(const std::unique_ptr& dst_data, - const std::unique_ptr& result_data, - const sk_sp& dl, - const std::string& desc) { - EXPECT_EQ(dst_data->width(), result_data->width()); - EXPECT_EQ(dst_data->height(), result_data->height()); - int all_flags = 0; - for (int y = 0; y < dst_data->height(); y++) { - const uint32_t* dst_pixels = dst_data->addr32(0, y); - const uint32_t* result_pixels = result_data->addr32(0, y); - for (int x = 0; x < dst_data->width(); x++) { - all_flags |= - check_color_result(dst_pixels[x], result_pixels[x], dl, desc); - } - } - return all_flags; - } - - void report_results(int all_flags, - const sk_sp& dl, - const std::string& desc) { - if (!dl->modifies_transparent_black()) { - EXPECT_TRUE((all_flags & kWasMTB) == 0); - } else if ((all_flags & kWasMTB) == 0) { - FML_LOG(INFO) << "combination does not affect transparency: " << desc; - } - if (dl->op_count() == 0u) { - EXPECT_TRUE((all_flags & kWasNotNop) == 0); - } else if ((all_flags & kWasNotNop) == 0) { - FML_LOG(INFO) << "combination could be classified as a nop: " << desc; - } - }; - - void test_mode_color_via_filter(DlBlendMode mode, DlColor color) { - std::stringstream desc_stream; - desc_stream << " using SkColorFilter::filterColor() with: "; - desc_stream << BlendModeToString(mode); - desc_stream << "/" << color; - std::string desc = desc_stream.str(); - DisplayListBuilder builder({0.0f, 0.0f, 100.0f, 100.0f}); - DlPaint paint = DlPaint(color).setBlendMode(mode); - builder.DrawRect({0.0f, 0.0f, 10.0f, 10.0f}, paint); - auto dl = builder.Build(); - if (dl->modifies_transparent_black()) { - ASSERT_TRUE(dl->op_count() != 0u); - } - - auto sk_mode = static_cast(mode); - auto sk_color_filter = SkColorFilters::Blend(color, sk_mode); - int all_flags = 0; - if (sk_color_filter) { - for (DlColor dst_color : test_dst_colors) { - DlColor result = sk_color_filter->filterColor(dst_color); - all_flags |= check_color_result(dst_color, result, dl, desc); - } - if ((all_flags & kWasMTB) != 0) { - EXPECT_FALSE(sk_color_filter->isAlphaUnchanged()); - } - } - report_results(all_flags, dl, desc); - }; - - void test_mode_color_via_rendering(DlBlendMode mode, DlColor color) { - std::stringstream desc_stream; - desc_stream << " rendering with: "; - desc_stream << BlendModeToString(mode); - desc_stream << "/" << color; - std::string desc = desc_stream.str(); - auto test_image = test_data->image(); - SkRect test_bounds = - SkRect::MakeWH(test_image->width(), test_image->height()); - DisplayListBuilder builder(test_bounds); - DlPaint dl_paint = DlPaint(color).setBlendMode(mode); - builder.DrawRect(test_bounds, dl_paint); - auto dl = builder.Build(); - bool dl_is_elided = dl->op_count() == 0u; - bool dl_affects_transparent_pixels = dl->modifies_transparent_black(); - ASSERT_TRUE(!dl_is_elided || !dl_affects_transparent_pixels); - - auto sk_mode = static_cast(mode); - SkPaint sk_paint; - sk_paint.setBlendMode(sk_mode); - sk_paint.setColor(color); - for (auto& provider : CanvasCompareTester::kTestProviders) { - auto result_surface = provider->MakeOffscreenSurface( - test_image->width(), test_image->height(), - DlSurfaceProvider::kN32Premul_PixelFormat); - SkCanvas* result_canvas = result_surface->sk_surface()->getCanvas(); - result_canvas->clear(SK_ColorTRANSPARENT); - result_canvas->drawImage(test_image.get(), 0, 0); - result_canvas->drawRect(test_bounds, sk_paint); - result_canvas->flush(); - result_surface->sk_surface()->flushAndSubmit(true); - auto result_pixels = - std::make_unique(result_surface->sk_surface()); - - int all_flags = check_image_result(test_data, result_pixels, dl, desc); - report_results(all_flags, dl, desc); - } - }; - - void test_attributes_image(DlBlendMode mode, - DlColor color, - DlColorFilter* color_filter, - DlImageFilter* image_filter) { - // if (true) { return; } - std::stringstream desc_stream; - desc_stream << " rendering with: "; - desc_stream << BlendModeToString(mode); - desc_stream << "/" << color; - std::string cf_mtb = color_filter - ? color_filter->modifies_transparent_black() - ? "modifies transparency" - : "preserves transparency" - : "no filter"; - desc_stream << ", CF: " << cf_mtb; - std::string if_mtb = image_filter - ? image_filter->modifies_transparent_black() - ? "modifies transparency" - : "preserves transparency" - : "no filter"; - desc_stream << ", IF: " << if_mtb; - std::string desc = desc_stream.str(); - - DisplayListBuilder builder({0.0f, 0.0f, 100.0f, 100.0f}); - DlPaint paint = DlPaint(color) // - .setBlendMode(mode) // - .setColorFilter(color_filter) // - .setImageFilter(image_filter); - builder.DrawImage(DlImage::Make(test_image_src_data->image()), {0, 0}, - DlImageSampling::kNearestNeighbor, &paint); - auto dl = builder.Build(); - - int w = test_image_src_data->width(); - int h = test_image_src_data->height(); - auto sk_mode = static_cast(mode); - SkPaint sk_paint; - sk_paint.setBlendMode(sk_mode); - sk_paint.setColor(color); - sk_paint.setColorFilter(ToSk(color_filter)); - sk_paint.setImageFilter(ToSk(image_filter)); - for (auto& provider : CanvasCompareTester::kTestProviders) { - auto result_surface = provider->MakeOffscreenSurface( - w, h, DlSurfaceProvider::kN32Premul_PixelFormat); - SkCanvas* result_canvas = result_surface->sk_surface()->getCanvas(); - result_canvas->clear(SK_ColorTRANSPARENT); - result_canvas->drawImage(test_image_dst_data->image(), 0, 0); - result_canvas->drawImage(test_image_src_data->image(), 0, 0, - SkSamplingOptions(), &sk_paint); - result_canvas->flush(); - result_surface->sk_surface()->flushAndSubmit(true); - auto result_pixels = - std::make_unique(result_surface->sk_surface()); - - int all_flags = - check_image_result(test_image_dst_data, result_pixels, dl, desc); - report_results(all_flags, dl, desc); - } - }; -}; - -TEST_F(DisplayListNopTest, BlendModeAndColorViaColorFilter) { - auto test_mode_filter = [this](DlBlendMode mode) { - for (DlColor color : test_src_colors) { - test_mode_color_via_filter(mode, color); - } - }; - -#define TEST_MODE(V) test_mode_filter(DlBlendMode::V); - FOR_EACH_BLEND_MODE_ENUM(TEST_MODE) -#undef TEST_MODE -} - -TEST_F(DisplayListNopTest, BlendModeAndColorByRendering) { - auto test_mode_render = [this](DlBlendMode mode) { - // First check rendering a variety of colors onto image - for (DlColor color : test_src_colors) { - test_mode_color_via_rendering(mode, color); - } - }; - -#define TEST_MODE(V) test_mode_render(DlBlendMode::V); - FOR_EACH_BLEND_MODE_ENUM(TEST_MODE) -#undef TEST_MODE -} - -TEST_F(DisplayListNopTest, BlendModeAndColorAndFiltersByRendering) { - auto test_mode_render = [this](DlBlendMode mode) { - auto image_filter_nomtb = DlColorFilterImageFilter(color_filter_nomtb); - auto image_filter_mtb = DlColorFilterImageFilter(color_filter_mtb); - for (DlColor color : test_src_colors) { - test_attributes_image(mode, color, nullptr, nullptr); - test_attributes_image(mode, color, color_filter_nomtb.get(), nullptr); - test_attributes_image(mode, color, color_filter_mtb.get(), nullptr); - test_attributes_image(mode, color, nullptr, &image_filter_nomtb); - test_attributes_image(mode, color, nullptr, &image_filter_mtb); - } - }; - -#define TEST_MODE(V) test_mode_render(DlBlendMode::V); - FOR_EACH_BLEND_MODE_ENUM(TEST_MODE) -#undef TEST_MODE -} - -#undef FOR_EACH_BLEND_MODE_ENUM +#undef FOR_EACH_ENUM } // namespace testing } // namespace flutter diff --git a/display_list/testing/dl_test_snippets.cc b/display_list/testing/dl_test_snippets.cc index 0a53f0337afd9..4479f63c1d678 100644 --- a/display_list/testing/dl_test_snippets.cc +++ b/display_list/testing/dl_test_snippets.cc @@ -517,7 +517,7 @@ std::vector CreateAllRenderingOps() { }}, {1, 16, 1, 24, [](DlOpReceiver& r) { - r.drawColor(SK_ColorBLUE, DlBlendMode::kDstOut); + r.drawColor(SK_ColorBLUE, DlBlendMode::kDstIn); }}, {1, 16, 1, 24, [](DlOpReceiver& r) { diff --git a/display_list/testing/dl_test_snippets.h b/display_list/testing/dl_test_snippets.h index 98b40599b41cf..94f7995d81eb5 100644 --- a/display_list/testing/dl_test_snippets.h +++ b/display_list/testing/dl_test_snippets.h @@ -151,9 +151,9 @@ static const DlBlurImageFilter kTestBlurImageFilter4(5.0, static const DlDilateImageFilter kTestDilateImageFilter1(5.0, 5.0); static const DlDilateImageFilter kTestDilateImageFilter2(6.0, 5.0); static const DlDilateImageFilter kTestDilateImageFilter3(5.0, 6.0); -static const DlErodeImageFilter kTestErodeImageFilter1(4.0, 4.0); -static const DlErodeImageFilter kTestErodeImageFilter2(4.0, 3.0); -static const DlErodeImageFilter kTestErodeImageFilter3(3.0, 4.0); +static const DlErodeImageFilter kTestErodeImageFilter1(5.0, 5.0); +static const DlErodeImageFilter kTestErodeImageFilter2(6.0, 5.0); +static const DlErodeImageFilter kTestErodeImageFilter3(5.0, 6.0); static const DlMatrixImageFilter kTestMatrixImageFilter1( SkMatrix::RotateDeg(45), kNearestSampling); diff --git a/display_list/utils/dl_matrix_clip_tracker.h b/display_list/utils/dl_matrix_clip_tracker.h index d50ab8935c469..c6efaaf78c9d1 100644 --- a/display_list/utils/dl_matrix_clip_tracker.h +++ b/display_list/utils/dl_matrix_clip_tracker.h @@ -38,7 +38,6 @@ class DisplayListMatrixClipTracker { bool content_culled(const SkRect& content_bounds) const { return current_->content_culled(content_bounds); } - bool is_cull_rect_empty() const { return current_->is_cull_rect_empty(); } void save(); void restore(); @@ -87,10 +86,9 @@ class DisplayListMatrixClipTracker { virtual SkMatrix matrix_3x3() const = 0; virtual SkM44 matrix_4x4() const = 0; - SkRect device_cull_rect() const { return cull_rect_; } + virtual SkRect device_cull_rect() const { return cull_rect_; } virtual SkRect local_cull_rect() const = 0; virtual bool content_culled(const SkRect& content_bounds) const; - bool is_cull_rect_empty() const { return cull_rect_.isEmpty(); } virtual void translate(SkScalar tx, SkScalar ty) = 0; virtual void scale(SkScalar sx, SkScalar sy) = 0; diff --git a/flow/diff_context_unittests.cc b/flow/diff_context_unittests.cc index d8b78a94070c0..e981258ef1a03 100644 --- a/flow/diff_context_unittests.cc +++ b/flow/diff_context_unittests.cc @@ -10,7 +10,7 @@ namespace testing { TEST_F(DiffContextTest, ClipAlignment) { MockLayerTree t1; t1.root()->Add(CreateDisplayListLayer( - CreateDisplayList(SkRect::MakeLTRB(30, 30, 50, 50)))); + CreateDisplayList(SkRect::MakeLTRB(30, 30, 50, 50), 1))); auto damage = DiffLayerTree(t1, MockLayerTree(), SkIRect::MakeEmpty(), 0, 0); EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(30, 30, 50, 50)); EXPECT_EQ(damage.buffer_damage, SkIRect::MakeLTRB(30, 30, 50, 50)); diff --git a/flow/layers/container_layer_unittests.cc b/flow/layers/container_layer_unittests.cc index 206be009966a7..42317ff9541a2 100644 --- a/flow/layers/container_layer_unittests.cc +++ b/flow/layers/container_layer_unittests.cc @@ -564,9 +564,9 @@ using ContainerLayerDiffTest = DiffContextTest; // Insert PictureLayer amongst container layers TEST_F(ContainerLayerDiffTest, PictureLayerInsertion) { - auto pic1 = CreateDisplayList(SkRect::MakeLTRB(0, 0, 50, 50)); - auto pic2 = CreateDisplayList(SkRect::MakeLTRB(100, 0, 150, 50)); - auto pic3 = CreateDisplayList(SkRect::MakeLTRB(200, 0, 250, 50)); + auto pic1 = CreateDisplayList(SkRect::MakeLTRB(0, 0, 50, 50), 1); + auto pic2 = CreateDisplayList(SkRect::MakeLTRB(100, 0, 150, 50), 1); + auto pic3 = CreateDisplayList(SkRect::MakeLTRB(200, 0, 250, 50), 1); MockLayerTree t1; @@ -616,9 +616,9 @@ TEST_F(ContainerLayerDiffTest, PictureLayerInsertion) { // Insert picture layer amongst other picture layers TEST_F(ContainerLayerDiffTest, PictureInsertion) { - auto pic1 = CreateDisplayList(SkRect::MakeLTRB(0, 0, 50, 50)); - auto pic2 = CreateDisplayList(SkRect::MakeLTRB(100, 0, 150, 50)); - auto pic3 = CreateDisplayList(SkRect::MakeLTRB(200, 0, 250, 50)); + auto pic1 = CreateDisplayList(SkRect::MakeLTRB(0, 0, 50, 50), 1); + auto pic2 = CreateDisplayList(SkRect::MakeLTRB(100, 0, 150, 50), 1); + auto pic3 = CreateDisplayList(SkRect::MakeLTRB(200, 0, 250, 50), 1); MockLayerTree t1; t1.root()->Add(CreateDisplayListLayer(pic1)); diff --git a/flow/layers/display_list_layer_unittests.cc b/flow/layers/display_list_layer_unittests.cc index 2791577666b8d..fccfe7b4ab044 100644 --- a/flow/layers/display_list_layer_unittests.cc +++ b/flow/layers/display_list_layer_unittests.cc @@ -355,7 +355,7 @@ TEST_F(DisplayListLayerTest, RasterCachePreservesRTree) { using DisplayListLayerDiffTest = DiffContextTest; TEST_F(DisplayListLayerDiffTest, SimpleDisplayList) { - auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60)); + auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1); MockLayerTree tree1; tree1.root()->Add(CreateDisplayListLayer(display_list)); @@ -375,7 +375,7 @@ TEST_F(DisplayListLayerDiffTest, SimpleDisplayList) { } TEST_F(DisplayListLayerDiffTest, FractionalTranslation) { - auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60)); + auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1); MockLayerTree tree1; tree1.root()->Add( @@ -388,7 +388,7 @@ TEST_F(DisplayListLayerDiffTest, FractionalTranslation) { } TEST_F(DisplayListLayerDiffTest, FractionalTranslationWithRasterCache) { - auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60)); + auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1); MockLayerTree tree1; tree1.root()->Add( @@ -402,25 +402,21 @@ TEST_F(DisplayListLayerDiffTest, FractionalTranslationWithRasterCache) { TEST_F(DisplayListLayerDiffTest, DisplayListCompare) { MockLayerTree tree1; - auto display_list1 = - CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), DlColor::kGreen()); + auto display_list1 = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1); tree1.root()->Add(CreateDisplayListLayer(display_list1)); auto damage = DiffLayerTree(tree1, MockLayerTree()); EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); MockLayerTree tree2; - // same DL, same offset - auto display_list2 = - CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), DlColor::kGreen()); + auto display_list2 = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1); tree2.root()->Add(CreateDisplayListLayer(display_list2)); damage = DiffLayerTree(tree2, tree1); EXPECT_EQ(damage.frame_damage, SkIRect::MakeEmpty()); MockLayerTree tree3; - auto display_list3 = - CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), DlColor::kGreen()); + auto display_list3 = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1); // add offset tree3.root()->Add( CreateDisplayListLayer(display_list3, SkPoint::Make(10, 10))); @@ -430,8 +426,7 @@ TEST_F(DisplayListLayerDiffTest, DisplayListCompare) { MockLayerTree tree4; // different color - auto display_list4 = - CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), DlColor::kRed()); + auto display_list4 = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 2); tree4.root()->Add( CreateDisplayListLayer(display_list4, SkPoint::Make(10, 10))); diff --git a/flow/layers/opacity_layer_unittests.cc b/flow/layers/opacity_layer_unittests.cc index 71ccdc15c8476..ca1f1067e87c3 100644 --- a/flow/layers/opacity_layer_unittests.cc +++ b/flow/layers/opacity_layer_unittests.cc @@ -659,7 +659,7 @@ using OpacityLayerDiffTest = DiffContextTest; TEST_F(OpacityLayerDiffTest, FractionalTranslation) { auto picture = CreateDisplayListLayer( - CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60))); + CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1)); auto layer = CreateOpacityLater({picture}, 128, SkPoint::Make(0.5, 0.5)); MockLayerTree tree1; @@ -672,7 +672,7 @@ TEST_F(OpacityLayerDiffTest, FractionalTranslation) { TEST_F(OpacityLayerDiffTest, FractionalTranslationWithRasterCache) { auto picture = CreateDisplayListLayer( - CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60))); + CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1)); auto layer = CreateOpacityLater({picture}, 128, SkPoint::Make(0.5, 0.5)); MockLayerTree tree1; diff --git a/flow/testing/diff_context_test.cc b/flow/testing/diff_context_test.cc index c4c68bb7ab271..20153a0140d5c 100644 --- a/flow/testing/diff_context_test.cc +++ b/flow/testing/diff_context_test.cc @@ -30,7 +30,7 @@ Damage DiffContextTest::DiffLayerTree(MockLayerTree& layer_tree, } sk_sp DiffContextTest::CreateDisplayList(const SkRect& bounds, - DlColor color) { + SkColor color) { DisplayListBuilder builder; builder.DrawRect(bounds, DlPaint().setColor(color)); return builder.Build(); diff --git a/flow/testing/diff_context_test.h b/flow/testing/diff_context_test.h index f22561552fdd0..69beb41d83470 100644 --- a/flow/testing/diff_context_test.h +++ b/flow/testing/diff_context_test.h @@ -47,8 +47,7 @@ class DiffContextTest : public LayerTest { // Create display list consisting of filled rect with given color; Being able // to specify different color is useful to test deep comparison of pictures - sk_sp CreateDisplayList(const SkRect& bounds, - DlColor color = DlColor::kBlack()); + sk_sp CreateDisplayList(const SkRect& bounds, uint32_t color); std::shared_ptr CreateDisplayListLayer( const sk_sp& display_list, diff --git a/impeller/aiks/BUILD.gn b/impeller/aiks/BUILD.gn index b0fe875cfef7d..1e09105d1dc8f 100644 --- a/impeller/aiks/BUILD.gn +++ b/impeller/aiks/BUILD.gn @@ -50,6 +50,9 @@ impeller_component("aiks_unittests") { sources = [ "aiks_unittests.cc", "canvas_unittests.cc", + "testing/context_mock.h", + "testing/context_spy.cc", + "testing/context_spy.h", ] deps = [ ":aiks", @@ -69,7 +72,12 @@ impeller_component("aiks_unittests_golden") { "IMPELLER_ENABLE_VALIDATION=1", ] - sources = [ "aiks_unittests.cc" ] + sources = [ + "aiks_unittests.cc", + "testing/context_mock.h", + "testing/context_spy.cc", + "testing/context_spy.h", + ] deps = [ ":aiks", ":aiks_playground", diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 05ebee6ccb8f9..709dc2eb9de95 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -16,6 +16,7 @@ #include "impeller/aiks/canvas.h" #include "impeller/aiks/image.h" #include "impeller/aiks/paint_pass_delegate.h" +#include "impeller/aiks/testing/context_spy.h" #include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" #include "impeller/entity/contents/scene_contents.h" @@ -1943,7 +1944,7 @@ TEST_P(AiksTest, PaintWithFilters) { ASSERT_TRUE(paint.HasColorFilter()); - paint.color_filter = std::nullopt; + paint.color_filter = nullptr; ASSERT_FALSE(paint.HasColorFilter()); } @@ -1962,7 +1963,7 @@ TEST_P(AiksTest, OpacityPeepHoleApplicationTest) { auto delegate = std::make_shared(paint, rect); ASSERT_FALSE(delegate->CanCollapseIntoParentPass(entity_pass.get())); - paint.color_filter = std::nullopt; + paint.color_filter = nullptr; paint.image_filter = [](const FilterInput::Ref& input, const Matrix& effect_transform, bool is_subpass) { return FilterContents::MakeGaussianBlur( @@ -1974,7 +1975,7 @@ TEST_P(AiksTest, OpacityPeepHoleApplicationTest) { delegate = std::make_shared(paint, rect); ASSERT_FALSE(delegate->CanCollapseIntoParentPass(entity_pass.get())); - paint.image_filter = std::nullopt; + paint.image_filter = nullptr; paint.color = Color::Red(); // Paint has no alpha, can't elide; @@ -1999,9 +2000,105 @@ TEST_P(AiksTest, DrawPaintAbsorbsClears) { {.color = Color::CornflowerBlue(), .blend_mode = BlendMode::kSource}); Picture picture = canvas.EndRecordingAsPicture(); - - ASSERT_EQ(picture.pass->GetElementCount(), 0u); ASSERT_EQ(picture.pass->GetClearColor(), Color::CornflowerBlue()); + + std::shared_ptr spy = ContextSpy::Make(); + std::shared_ptr real_context = GetContext(); + std::shared_ptr mock_context = spy->MakeContext(real_context); + AiksContext renderer(mock_context); + std::shared_ptr image = picture.ToImage(renderer, {300, 300}); + + ASSERT_EQ(spy->render_passes_.size(), 1llu); + std::shared_ptr render_pass = spy->render_passes_[0]; + ASSERT_EQ(render_pass->GetCommands().size(), 0llu); +} + +TEST_P(AiksTest, DrawRectAbsorbsClears) { + Canvas canvas; + canvas.DrawRect({0, 0, 300, 300}, + {.color = Color::Red(), .blend_mode = BlendMode::kSource}); + canvas.DrawRect({0, 0, 300, 300}, {.color = Color::CornflowerBlue(), + .blend_mode = BlendMode::kSource}); + + std::shared_ptr spy = ContextSpy::Make(); + Picture picture = canvas.EndRecordingAsPicture(); + std::shared_ptr real_context = GetContext(); + std::shared_ptr mock_context = spy->MakeContext(real_context); + AiksContext renderer(mock_context); + std::shared_ptr image = picture.ToImage(renderer, {300, 300}); + + ASSERT_EQ(spy->render_passes_.size(), 1llu); + std::shared_ptr render_pass = spy->render_passes_[0]; + ASSERT_EQ(render_pass->GetCommands().size(), 0llu); +} + +TEST_P(AiksTest, DrawRectAbsorbsClearsNegativeRRect) { + Canvas canvas; + canvas.DrawRRect({0, 0, 300, 300}, 5.0, + {.color = Color::Red(), .blend_mode = BlendMode::kSource}); + canvas.DrawRRect( + {0, 0, 300, 300}, 5.0, + {.color = Color::CornflowerBlue(), .blend_mode = BlendMode::kSource}); + + std::shared_ptr spy = ContextSpy::Make(); + Picture picture = canvas.EndRecordingAsPicture(); + std::shared_ptr real_context = GetContext(); + std::shared_ptr mock_context = spy->MakeContext(real_context); + AiksContext renderer(mock_context); + std::shared_ptr image = picture.ToImage(renderer, {300, 300}); + + ASSERT_EQ(spy->render_passes_.size(), 1llu); + std::shared_ptr render_pass = spy->render_passes_[0]; + ASSERT_EQ(render_pass->GetCommands().size(), 2llu); +} + +TEST_P(AiksTest, DrawRectAbsorbsClearsNegativeRotation) { + Canvas canvas; + canvas.Translate(Vector3(150.0, 150.0, 0.0)); + canvas.Rotate(Degrees(45.0)); + canvas.Translate(Vector3(-150.0, -150.0, 0.0)); + canvas.DrawRect({0, 0, 300, 300}, + {.color = Color::Red(), .blend_mode = BlendMode::kSource}); + + std::shared_ptr spy = ContextSpy::Make(); + Picture picture = canvas.EndRecordingAsPicture(); + std::shared_ptr real_context = GetContext(); + std::shared_ptr mock_context = spy->MakeContext(real_context); + AiksContext renderer(mock_context); + std::shared_ptr image = picture.ToImage(renderer, {300, 300}); + + ASSERT_EQ(spy->render_passes_.size(), 1llu); + std::shared_ptr render_pass = spy->render_passes_[0]; + ASSERT_EQ(render_pass->GetCommands().size(), 1llu); +} + +TEST_P(AiksTest, DrawRectAbsorbsClearsNegative) { + Canvas canvas; + canvas.DrawRect({0, 0, 300, 300}, + {.color = Color::Red(), .blend_mode = BlendMode::kSource}); + canvas.DrawRect({0, 0, 300, 300}, {.color = Color::CornflowerBlue(), + .blend_mode = BlendMode::kSource}); + + std::shared_ptr spy = ContextSpy::Make(); + Picture picture = canvas.EndRecordingAsPicture(); + std::shared_ptr real_context = GetContext(); + std::shared_ptr mock_context = spy->MakeContext(real_context); + AiksContext renderer(mock_context); + std::shared_ptr image = picture.ToImage(renderer, {301, 301}); + + ASSERT_EQ(spy->render_passes_.size(), 1llu); + std::shared_ptr render_pass = spy->render_passes_[0]; + ASSERT_EQ(render_pass->GetCommands().size(), 2llu); +} + +TEST_P(AiksTest, CollapsedDrawPaintInSubpass) { + Canvas canvas; + canvas.DrawPaint( + {.color = Color::Yellow(), .blend_mode = BlendMode::kSource}); + canvas.SaveLayer({.blend_mode = BlendMode::kMultiply}); + canvas.DrawPaint({.color = Color::Red(), .blend_mode = BlendMode::kSource}); + + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } TEST_P(AiksTest, ForegroundBlendSubpassCollapseOptimization) { @@ -2098,7 +2195,7 @@ static Picture BlendModeTest(BlendMode blend_mode, /// canvas.Save(); - for (auto& color : source_colors) { + for (const auto& color : source_colors) { canvas.Save(); { canvas.ClipRect(Rect::MakeXYWH(50, 50, 100, 100)); @@ -2134,7 +2231,7 @@ static Picture BlendModeTest(BlendMode blend_mode, // fully transparent black. SourceOver blend the result onto the parent pass. canvas.SaveLayer({}); // canvas.DrawPaint({.color = destination_color}); - for (auto& color : source_colors) { + for (const auto& color : source_colors) { // Simply write the CPU blended color to the pass. canvas.DrawRect({50, 50, 100, 100}, {.color = destination_color.Blend(color, blend_mode), diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 204f8425d4d31..df3d5fc540bba 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -58,10 +58,9 @@ void Canvas::Save() { Save(false); } -void Canvas::Save( - bool create_subpass, - BlendMode blend_mode, - std::optional backdrop_filter) { +void Canvas::Save(bool create_subpass, + BlendMode blend_mode, + EntityPass::BackdropFilterProc backdrop_filter) { auto entry = CanvasStackEntry{}; entry.xformation = xformation_stack_.back().xformation; entry.cull_rect = xformation_stack_.back().cull_rect; @@ -172,16 +171,6 @@ void Canvas::DrawPath(const Path& path, const Paint& paint) { } void Canvas::DrawPaint(const Paint& paint) { - if (xformation_stack_.size() == 1 && // If we're recording the root pass, - GetCurrentPass().GetElementCount() == 0 && // and this is the first item, - (paint.blend_mode == BlendMode::kSourceOver || - paint.blend_mode == BlendMode::kSource) && - paint.color.alpha >= 1.0f) { - // Then we can absorb this drawPaint as the clear color of the pass. - GetCurrentPass().SetClearColor(paint.color); - return; - } - Entity entity; entity.SetTransformation(GetCurrentTransformation()); entity.SetStencilDepth(GetStencilDepth()); @@ -492,10 +481,9 @@ size_t Canvas::GetStencilDepth() const { return xformation_stack_.back().stencil_depth; } -void Canvas::SaveLayer( - const Paint& paint, - std::optional bounds, - const std::optional& backdrop_filter) { +void Canvas::SaveLayer(const Paint& paint, + std::optional bounds, + const Paint::ImageFilterProc& backdrop_filter) { Save(true, paint.blend_mode, backdrop_filter); auto& new_layer_pass = GetCurrentPass(); @@ -509,7 +497,7 @@ void Canvas::SaveLayer( std::make_unique(paint, bounds)); } - if (bounds.has_value() && !backdrop_filter.has_value()) { + if (bounds.has_value() && !backdrop_filter) { // Render target switches due to a save layer can be elided. In such cases // where passes are collapsed into their parent, the clipping effect to // the size of the render target that would have been allocated will be diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index 6fb5484f0dfa3..57a23671abf3f 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -68,8 +68,7 @@ class Canvas { void SaveLayer(const Paint& paint, std::optional bounds = std::nullopt, - const std::optional& backdrop_filter = - std::nullopt); + const Paint::ImageFilterProc& backdrop_filter = nullptr); bool Restore(); @@ -182,8 +181,7 @@ class Canvas { void Save(bool create_subpass, BlendMode = BlendMode::kSourceOver, - std::optional backdrop_filter = - std::nullopt); + EntityPass::BackdropFilterProc backdrop_filter = nullptr); void RestoreClip(); diff --git a/impeller/aiks/paint.cc b/impeller/aiks/paint.cc index 3a921289ccdd9..c9dfc31d1dacf 100644 --- a/impeller/aiks/paint.cc +++ b/impeller/aiks/paint.cc @@ -74,9 +74,9 @@ std::shared_ptr Paint::WithImageFilter( std::shared_ptr input, const Matrix& effect_transform, bool is_subpass) const { - if (image_filter.has_value()) { - const ImageFilterProc& filter = image_filter.value(); - input = filter(FilterInput::Make(input), effect_transform, is_subpass); + if (image_filter) { + input = + image_filter(FilterInput::Make(input), effect_transform, is_subpass); } return input; } @@ -89,9 +89,8 @@ std::shared_ptr Paint::WithColorFilter( if (color_source.GetType() == ColorSource::Type::kImage) { return input; } - if (color_filter.has_value()) { - const ColorFilterProc& filter = color_filter.value(); - auto color_filter_contents = filter(FilterInput::Make(input)); + if (color_filter) { + auto color_filter_contents = color_filter(FilterInput::Make(input)); if (color_filter_contents) { color_filter_contents->SetAbsorbOpacity(absorb_opacity); } @@ -166,7 +165,7 @@ std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( } bool Paint::HasColorFilter() const { - return color_filter.has_value(); + return !!color_filter; } } // namespace impeller diff --git a/impeller/aiks/paint.h b/impeller/aiks/paint.h index b1f793905c8de..c355cf26a0037 100644 --- a/impeller/aiks/paint.h +++ b/impeller/aiks/paint.h @@ -61,8 +61,8 @@ struct Paint { BlendMode blend_mode = BlendMode::kSourceOver; bool invert_colors = false; - std::optional image_filter; - std::optional color_filter; + ImageFilterProc image_filter = nullptr; + ColorFilterProc color_filter = nullptr; std::optional mask_blur_descriptor; /// @brief Wrap this paint's configured filters to the given contents. diff --git a/impeller/aiks/paint_pass_delegate.cc b/impeller/aiks/paint_pass_delegate.cc index baf550d3fe127..8f6867b379396 100644 --- a/impeller/aiks/paint_pass_delegate.cc +++ b/impeller/aiks/paint_pass_delegate.cc @@ -80,7 +80,7 @@ bool OpacityPeepholePassDelegate::CanCollapseIntoParentPass( // OpacityPeepholePassDelegate will only get used if the pass's blend mode is // SourceOver, so no need to check here. if (paint_.color.alpha <= 0.0 || paint_.color.alpha >= 1.0 || - paint_.image_filter.has_value() || paint_.color_filter.has_value()) { + paint_.image_filter || paint_.color_filter) { return false; } diff --git a/impeller/aiks/testing/context_mock.h b/impeller/aiks/testing/context_mock.h new file mode 100644 index 0000000000000..2650105de4a70 --- /dev/null +++ b/impeller/aiks/testing/context_mock.h @@ -0,0 +1,88 @@ +// 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. + +#pragma once + +#include +#include + +#include "gmock/gmock.h" +#include "impeller/renderer/command_buffer.h" +#include "impeller/renderer/context.h" +#include "impeller/renderer/render_target.h" + +namespace impeller { +namespace testing { + +class CommandBufferMock : public CommandBuffer { + public: + CommandBufferMock(std::weak_ptr context) + : CommandBuffer(context) {} + + MOCK_CONST_METHOD0(IsValid, bool()); + + MOCK_CONST_METHOD1(SetLabel, void(const std::string& label)); + + MOCK_METHOD1(SubmitCommandsAsync, + bool(std::shared_ptr render_pass)); + + MOCK_METHOD1(OnCreateRenderPass, + std::shared_ptr(RenderTarget render_target)); + + static std::shared_ptr ForwardOnCreateRenderPass( + CommandBuffer* command_buffer, + RenderTarget render_target) { + return command_buffer->OnCreateRenderPass(render_target); + } + + MOCK_CONST_METHOD0(OnCreateBlitPass, std::shared_ptr()); + static std::shared_ptr ForwardOnCreateBlitPass( + CommandBuffer* command_buffer) { + return command_buffer->OnCreateBlitPass(); + } + + MOCK_METHOD1(OnSubmitCommands, bool(CompletionCallback callback)); + static bool ForwardOnSubmitCommands(CommandBuffer* command_buffer, + CompletionCallback callback) { + return command_buffer->OnSubmitCommands(callback); + } + + MOCK_METHOD0(OnWaitUntilScheduled, void()); + static void ForwardOnWaitUntilScheduled(CommandBuffer* command_buffer) { + return command_buffer->OnWaitUntilScheduled(); + } + + MOCK_CONST_METHOD0(OnCreateComputePass, std::shared_ptr()); + static std::shared_ptr ForwardOnCreateComputePass( + CommandBuffer* command_buffer) { + return command_buffer->OnCreateComputePass(); + } +}; + +class ContextMock : public Context { + public: + MOCK_CONST_METHOD0(DescribeGpuModel, std::string()); + + MOCK_CONST_METHOD0(IsValid, bool()); + + MOCK_CONST_METHOD0(GetCapabilities, + const std::shared_ptr&()); + + MOCK_METHOD1(UpdateOffscreenLayerPixelFormat, bool(PixelFormat format)); + + MOCK_CONST_METHOD0(GetResourceAllocator, std::shared_ptr()); + + MOCK_CONST_METHOD0(GetShaderLibrary, std::shared_ptr()); + + MOCK_CONST_METHOD0(GetSamplerLibrary, std::shared_ptr()); + + MOCK_CONST_METHOD0(GetPipelineLibrary, std::shared_ptr()); + + MOCK_CONST_METHOD0(CreateCommandBuffer, std::shared_ptr()); + + MOCK_METHOD0(Shutdown, void()); +}; + +} // namespace testing +} // namespace impeller diff --git a/impeller/aiks/testing/context_spy.cc b/impeller/aiks/testing/context_spy.cc new file mode 100644 index 0000000000000..f467773f1d7f6 --- /dev/null +++ b/impeller/aiks/testing/context_spy.cc @@ -0,0 +1,111 @@ +// 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 "impeller/aiks/testing/context_spy.h" + +namespace impeller { +namespace testing { + +std::shared_ptr ContextSpy::Make() { + return std::shared_ptr(new ContextSpy()); +} + +std::shared_ptr ContextSpy::MakeContext( + const std::shared_ptr& real_context) { + std::shared_ptr mock_context = + std::make_shared<::testing::NiceMock>(); + std::shared_ptr shared_this = shared_from_this(); + + ON_CALL(*mock_context, IsValid).WillByDefault([real_context]() { + return real_context->IsValid(); + }); + + ON_CALL(*mock_context, GetCapabilities) + .WillByDefault( + [real_context]() -> const std::shared_ptr& { + return real_context->GetCapabilities(); + }); + + ON_CALL(*mock_context, UpdateOffscreenLayerPixelFormat) + .WillByDefault([real_context](PixelFormat format) { + return real_context->UpdateOffscreenLayerPixelFormat(format); + }); + + ON_CALL(*mock_context, GetResourceAllocator).WillByDefault([real_context]() { + return real_context->GetResourceAllocator(); + }); + + ON_CALL(*mock_context, GetShaderLibrary).WillByDefault([real_context]() { + return real_context->GetShaderLibrary(); + }); + + ON_CALL(*mock_context, GetSamplerLibrary).WillByDefault([real_context]() { + return real_context->GetSamplerLibrary(); + }); + + ON_CALL(*mock_context, GetPipelineLibrary).WillByDefault([real_context]() { + return real_context->GetPipelineLibrary(); + }); + + ON_CALL(*mock_context, CreateCommandBuffer) + .WillByDefault([real_context, shared_this]() { + auto real_buffer = real_context->CreateCommandBuffer(); + auto spy = std::make_shared<::testing::NiceMock>( + real_context); + + ON_CALL(*spy, IsValid).WillByDefault([real_buffer]() { + return real_buffer->IsValid(); + }); + + ON_CALL(*spy, SetLabel) + .WillByDefault([real_buffer](const std::string& label) { + return real_buffer->SetLabel(label); + }); + + ON_CALL(*spy, SubmitCommandsAsync) + .WillByDefault([real_buffer]( + std::shared_ptr render_pass) { + return real_buffer->SubmitCommandsAsync(std::move(render_pass)); + }); + + ON_CALL(*spy, OnCreateRenderPass) + .WillByDefault( + [real_buffer, shared_this](const RenderTarget& render_target) { + std::shared_ptr result = + CommandBufferMock::ForwardOnCreateRenderPass( + real_buffer.get(), render_target); + shared_this->render_passes_.push_back(result); + return result; + }); + + ON_CALL(*spy, OnCreateBlitPass).WillByDefault([real_buffer]() { + return CommandBufferMock::ForwardOnCreateBlitPass(real_buffer.get()); + }); + + ON_CALL(*spy, OnSubmitCommands) + .WillByDefault( + [real_buffer](CommandBuffer::CompletionCallback callback) { + return CommandBufferMock::ForwardOnSubmitCommands( + real_buffer.get(), std::move(callback)); + }); + + ON_CALL(*spy, OnWaitUntilScheduled).WillByDefault([real_buffer]() { + return CommandBufferMock::ForwardOnWaitUntilScheduled( + real_buffer.get()); + }); + + ON_CALL(*spy, OnCreateComputePass).WillByDefault([real_buffer]() { + return CommandBufferMock::ForwardOnCreateComputePass( + real_buffer.get()); + }); + + return spy; + }); + + return mock_context; +} + +} // namespace testing + +} // namespace impeller diff --git a/impeller/aiks/testing/context_spy.h b/impeller/aiks/testing/context_spy.h new file mode 100644 index 0000000000000..9d32f2e136880 --- /dev/null +++ b/impeller/aiks/testing/context_spy.h @@ -0,0 +1,30 @@ +// 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. + +#pragma once + +#include +#include "impeller/aiks/testing/context_mock.h" + +namespace impeller { +namespace testing { + +/// Forwards calls to a real Context but can store information about how +/// the Context was used. +class ContextSpy : public std::enable_shared_from_this { + public: + static std::shared_ptr Make(); + + std::shared_ptr MakeContext( + const std::shared_ptr& real_context); + + std::vector> render_passes_; + + private: + ContextSpy() = default; +}; + +} // namespace testing + +} // namespace impeller diff --git a/impeller/core/device_buffer.cc b/impeller/core/device_buffer.cc index 0498ee3e894bc..741a4d7ee2386 100644 --- a/impeller/core/device_buffer.cc +++ b/impeller/core/device_buffer.cc @@ -39,8 +39,6 @@ std::shared_ptr DeviceBuffer::AsTexture( return texture; } -void DeviceBuffer::Flush() {} - const DeviceBufferDescriptor& DeviceBuffer::GetDeviceBufferDescriptor() const { return desc_; } diff --git a/impeller/core/device_buffer.h b/impeller/core/device_buffer.h index 739d46ca224a8..507a4157d53be 100644 --- a/impeller/core/device_buffer.h +++ b/impeller/core/device_buffer.h @@ -32,8 +32,6 @@ class DeviceBuffer : public Buffer, BufferView AsBufferView() const; - virtual void Flush(); - virtual std::shared_ptr AsTexture( Allocator& allocator, const TextureDescriptor& descriptor, diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index ec9fa3021a37f..041423ce770a1 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -474,10 +474,10 @@ void DlDispatcher::setColorSource(const flutter::DlColorSource* source) { } } -static std::optional ToColorFilterProc( +static Paint::ColorFilterProc ToColorFilterProc( const flutter::DlColorFilter* filter) { if (filter == nullptr) { - return std::nullopt; + return nullptr; } switch (filter->type()) { case flutter::DlColorFilterType::kBlend: { @@ -507,7 +507,7 @@ static std::optional ToColorFilterProc( return ColorFilterContents::MakeLinearToSrgbFilter({std::move(input)}); }; } - return std::nullopt; + return nullptr; } // |flutter::DlOpReceiver| @@ -565,10 +565,10 @@ void DlDispatcher::setMaskFilter(const flutter::DlMaskFilter* filter) { } } -static std::optional ToImageFilterProc( +static Paint::ImageFilterProc ToImageFilterProc( const flutter::DlImageFilter* filter) { if (filter == nullptr) { - return std::nullopt; + return nullptr; } switch (filter->type()) { @@ -592,7 +592,7 @@ static std::optional ToImageFilterProc( auto dilate = filter->asDilate(); FML_DCHECK(dilate); if (dilate->radius_x() < 0 || dilate->radius_y() < 0) { - return std::nullopt; + return nullptr; } auto radius_x = Radius(dilate->radius_x()); auto radius_y = Radius(dilate->radius_y()); @@ -609,7 +609,7 @@ static std::optional ToImageFilterProc( auto erode = filter->asErode(); FML_DCHECK(erode); if (erode->radius_x() < 0 || erode->radius_y() < 0) { - return std::nullopt; + return nullptr; } auto radius_x = Radius(erode->radius_x()); auto radius_y = Radius(erode->radius_y()); @@ -641,17 +641,16 @@ static std::optional ToImageFilterProc( auto inner = compose->inner(); auto outer_proc = ToImageFilterProc(outer.get()); auto inner_proc = ToImageFilterProc(inner.get()); - if (!outer_proc.has_value()) { + if (!outer_proc) { return inner_proc; } - if (!inner_proc.has_value()) { + if (!inner_proc) { return outer_proc; } - FML_DCHECK(outer_proc.has_value() && inner_proc.has_value()); - return [outer_filter = outer_proc.value(), - inner_filter = inner_proc.value()](FilterInput::Ref input, - const Matrix& effect_transform, - bool is_subpass) { + FML_DCHECK(outer_proc && inner_proc); + return [outer_filter = outer_proc, inner_filter = inner_proc]( + FilterInput::Ref input, const Matrix& effect_transform, + bool is_subpass) { auto contents = inner_filter(std::move(input), effect_transform, is_subpass); contents = outer_filter(FilterInput::Make(contents), effect_transform, @@ -665,10 +664,10 @@ static std::optional ToImageFilterProc( FML_DCHECK(color_filter_image_filter); auto color_filter_proc = ToColorFilterProc(color_filter_image_filter->color_filter().get()); - if (!color_filter_proc.has_value()) { - return std::nullopt; + if (!color_filter_proc) { + return nullptr; } - return [color_filter = color_filter_proc.value()]( + return [color_filter = color_filter_proc]( FilterInput::Ref input, const Matrix& effect_transform, bool is_subpass) { return color_filter(std::move(input)); }; break; @@ -680,13 +679,13 @@ static std::optional ToImageFilterProc( FML_DCHECK(internal_filter); auto image_filter_proc = ToImageFilterProc(internal_filter.get()); - if (!image_filter_proc.has_value()) { - return std::nullopt; + if (!image_filter_proc) { + return nullptr; } auto matrix = ToMatrix(local_matrix_filter->matrix()); - return [matrix, filter_proc = image_filter_proc.value()]( + return [matrix, filter_proc = image_filter_proc]( FilterInput::Ref input, const Matrix& effect_transform, bool is_subpass) { std::shared_ptr filter = diff --git a/impeller/display_list/dl_unittests.cc b/impeller/display_list/dl_unittests.cc index 01a81d3441d40..22f118fd0a3ec 100644 --- a/impeller/display_list/dl_unittests.cc +++ b/impeller/display_list/dl_unittests.cc @@ -830,12 +830,18 @@ TEST_P(DisplayListTest, CanDrawShadow) { } TEST_P(DisplayListTest, TransparentShadowProducesCorrectColor) { + flutter::DisplayListBuilder builder; + { + builder.Save(); + builder.Scale(1.618, 1.618); + builder.DrawShadow(SkPath{}.addRect(SkRect::MakeXYWH(0, 0, 200, 100)), + SK_ColorTRANSPARENT, 15, false, 1); + builder.Restore(); + } + auto dl = builder.Build(); + DlDispatcher dispatcher; - dispatcher.save(); - dispatcher.scale(1.618, 1.618); - dispatcher.drawShadow(SkPath{}.addRect(SkRect::MakeXYWH(0, 0, 200, 100)), - SK_ColorTRANSPARENT, 15, false, 1); - dispatcher.restore(); + dispatcher.drawDisplayList(dl, 1); auto picture = dispatcher.EndRecordingAsPicture(); std::shared_ptr rrect_blur; diff --git a/impeller/entity/contents/atlas_contents.cc b/impeller/entity/contents/atlas_contents.cc index 930012b592282..b88fee0c20561 100644 --- a/impeller/entity/contents/atlas_contents.cc +++ b/impeller/entity/contents/atlas_contents.cc @@ -389,11 +389,10 @@ bool AtlasColorContents::Render(const ContentContext& renderer, std::vector texture_coords; std::vector transforms; std::vector colors; - if (subatlas_.has_value()) { - auto subatlas = subatlas_.value(); - texture_coords = subatlas->sub_texture_coords; - colors = subatlas->sub_colors; - transforms = subatlas->sub_transforms; + if (subatlas_) { + texture_coords = subatlas_->sub_texture_coords; + colors = subatlas_->sub_colors; + transforms = subatlas_->sub_transforms; } else { texture_coords = parent_.GetTextureCoordinates(); transforms = parent_.GetTransforms(); diff --git a/impeller/entity/contents/atlas_contents.h b/impeller/entity/contents/atlas_contents.h index 44a31e12be215..76e102e17924a 100644 --- a/impeller/entity/contents/atlas_contents.h +++ b/impeller/entity/contents/atlas_contents.h @@ -149,7 +149,7 @@ class AtlasColorContents final : public Contents { const AtlasContents& parent_; Scalar alpha_ = 1.0; Rect coverage_; - std::optional> subatlas_ = std::nullopt; + std::shared_ptr subatlas_; FML_DISALLOW_COPY_AND_ASSIGN(AtlasColorContents); }; diff --git a/impeller/entity/contents/contents.h b/impeller/entity/contents/contents.h index 9d42fb55fcd03..09d45a5b67b7c 100644 --- a/impeller/entity/contents/contents.h +++ b/impeller/entity/contents/contents.h @@ -117,6 +117,11 @@ class Contents { /// Use of this method is invalid if CanAcceptOpacity returns false. virtual void SetInheritedOpacity(Scalar opacity); + virtual std::optional AsBackgroundColor(const Entity& entity, + ISize target_size) const { + return {}; + } + private: std::optional coverage_hint_; std::optional color_source_size_; diff --git a/impeller/entity/contents/solid_color_contents.cc b/impeller/entity/contents/solid_color_contents.cc index 1c5b032cd4a37..8814e177b8e58 100644 --- a/impeller/entity/contents/solid_color_contents.cc +++ b/impeller/entity/contents/solid_color_contents.cc @@ -101,4 +101,19 @@ std::unique_ptr SolidColorContents::Make(const Path& path, return contents; } +std::optional SolidColorContents::AsBackgroundColor( + const Entity& entity, + ISize target_size) const { + if (!(GetColor().IsOpaque() && + (entity.GetBlendMode() == BlendMode::kSource || + entity.GetBlendMode() == BlendMode::kSourceOver))) { + return {}; + } + + Rect target_rect = Rect::MakeSize(target_size); + return GetGeometry()->CoversArea(entity.GetTransformation(), target_rect) + ? GetColor() + : std::optional(); +} + } // namespace impeller diff --git a/impeller/entity/contents/solid_color_contents.h b/impeller/entity/contents/solid_color_contents.h index d3cbb35300d99..497d08d49f86f 100644 --- a/impeller/entity/contents/solid_color_contents.h +++ b/impeller/entity/contents/solid_color_contents.h @@ -49,6 +49,9 @@ class SolidColorContents final : public ColorSourceContents { const Entity& entity, RenderPass& pass) const override; + std::optional AsBackgroundColor(const Entity& entity, + ISize target_size) const override; + private: Color color_; diff --git a/impeller/entity/contents/tiled_texture_contents.cc b/impeller/entity/contents/tiled_texture_contents.cc index d2d9ee02f3d8d..2f2874dd3350f 100644 --- a/impeller/entity/contents/tiled_texture_contents.cc +++ b/impeller/entity/contents/tiled_texture_contents.cc @@ -55,19 +55,16 @@ void TiledTextureContents::SetSamplerDescriptor(SamplerDescriptor desc) { sampler_descriptor_ = std::move(desc); } -void TiledTextureContents::SetColorFilter( - std::optional color_filter) { +void TiledTextureContents::SetColorFilter(ColorFilterProc color_filter) { color_filter_ = std::move(color_filter); } -std::optional> -TiledTextureContents::CreateFilterTexture( +std::shared_ptr TiledTextureContents::CreateFilterTexture( const ContentContext& renderer) const { - if (!color_filter_.has_value()) { - return std::nullopt; + if (!color_filter_) { + return nullptr; } - const ColorFilterProc& filter = color_filter_.value(); - auto color_filter_contents = filter(FilterInput::Make(texture_)); + auto color_filter_contents = color_filter_(FilterInput::Make(texture_)); auto snapshot = color_filter_contents->RenderToSnapshot( renderer, // renderer Entity(), // entity @@ -78,7 +75,7 @@ TiledTextureContents::CreateFilterTexture( if (snapshot.has_value()) { return snapshot.value().texture; } - return std::nullopt; + return nullptr; } SamplerDescriptor TiledTextureContents::CreateDescriptor( @@ -107,7 +104,7 @@ bool TiledTextureContents::IsOpaque() const { y_tile_mode_ == Entity::TileMode::kDecal) { return false; } - if (color_filter_.has_value()) { + if (color_filter_) { return false; } return texture_->IsOpaque(); @@ -170,13 +167,13 @@ bool TiledTextureContents::Render(const ContentContext& renderer, cmd, host_buffer.EmplaceUniform(frag_info)); } - if (color_filter_.has_value()) { + if (color_filter_) { auto filtered_texture = CreateFilterTexture(renderer); - if (!filtered_texture.has_value()) { + if (!filtered_texture) { return false; } FS::BindTextureSampler( - cmd, filtered_texture.value(), + cmd, filtered_texture, renderer.GetContext()->GetSamplerLibrary()->GetSampler( CreateDescriptor(renderer.GetDeviceCapabilities()))); } else { diff --git a/impeller/entity/contents/tiled_texture_contents.h b/impeller/entity/contents/tiled_texture_contents.h index 589f5e2b08b2b..f027c057915a3 100644 --- a/impeller/entity/contents/tiled_texture_contents.h +++ b/impeller/entity/contents/tiled_texture_contents.h @@ -51,7 +51,7 @@ class TiledTextureContents final : public ColorSourceContents { /// /// This may not be a performance improvement if the image is tiled into a /// much smaller size that its original texture size. - void SetColorFilter(std::optional color_filter); + void SetColorFilter(ColorFilterProc color_filter); // |Contents| std::optional RenderToSnapshot( @@ -63,7 +63,7 @@ class TiledTextureContents final : public ColorSourceContents { const std::string& label = "Tiled Texture Snapshot") const override; private: - std::optional> CreateFilterTexture( + std::shared_ptr CreateFilterTexture( const ContentContext& renderer) const; SamplerDescriptor CreateDescriptor(const Capabilities& capabilities) const; @@ -74,7 +74,7 @@ class TiledTextureContents final : public ColorSourceContents { SamplerDescriptor sampler_descriptor_ = {}; Entity::TileMode x_tile_mode_ = Entity::TileMode::kClamp; Entity::TileMode y_tile_mode_ = Entity::TileMode::kClamp; - std::optional color_filter_; + ColorFilterProc color_filter_ = nullptr; FML_DISALLOW_COPY_AND_ASSIGN(TiledTextureContents); }; diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 0c02217bfc9f0..3ba003272212f 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -36,6 +36,20 @@ namespace impeller { +namespace { +std::optional AsBackgroundColor(const EntityPass::Element& element, + ISize target_size) { + if (const Entity* entity = std::get_if(&element)) { + std::optional entity_color = + entity->GetContents()->AsBackgroundColor(*entity, target_size); + if (entity_color.has_value()) { + return entity_color.value(); + } + } + return {}; +} +} // namespace + EntityPass::EntityPass() = default; EntityPass::~EntityPass() = default; @@ -141,7 +155,7 @@ EntityPass* EntityPass::AddSubpass(std::unique_ptr pass) { FML_DCHECK(pass->superpass_ == nullptr); pass->superpass_ = this; - if (pass->backdrop_filter_proc_.has_value()) { + if (pass->backdrop_filter_proc_) { backdrop_filter_reads_from_pass_texture_ += 1; } if (pass->blend_mode_ > Entity::kLastPipelineBlendMode) { @@ -235,9 +249,9 @@ bool EntityPass::Render(ContentContext& renderer, // and then blit the results onto the onscreen texture. If using this branch, // there's no need to set up a stencil attachment on the root render target. if (!supports_onscreen_backdrop_reads && reads_from_onscreen_backdrop) { - auto offscreen_target = - CreateRenderTarget(renderer, root_render_target.GetRenderTargetSize(), - true, clear_color_.Premultiply()); + auto offscreen_target = CreateRenderTarget( + renderer, root_render_target.GetRenderTargetSize(), true, + GetClearColor(render_target.GetRenderTargetSize()).Premultiply()); if (!OnRender(renderer, // renderer offscreen_target.GetRenderTarget() @@ -342,7 +356,8 @@ bool EntityPass::Render(ContentContext& renderer, } // Set up the clear color of the root pass. - color0.clear_color = clear_color_.Premultiply(); + color0.clear_color = + GetClearColor(render_target.GetRenderTargetSize()).Premultiply(); root_render_target.SetColorAttachment(color0, 0); EntityPassTarget pass_target( @@ -398,7 +413,7 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( return EntityPass::EntityResult::Skip(); } - if (!subpass->backdrop_filter_proc_.has_value() && + if (!subpass->backdrop_filter_proc_ && subpass->delegate_->CanCollapseIntoParentPass(subpass)) { // Directly render into the parent target and move on. if (!subpass->OnRender( @@ -421,10 +436,10 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( } std::shared_ptr backdrop_filter_contents = nullptr; - if (subpass->backdrop_filter_proc_.has_value()) { + if (subpass->backdrop_filter_proc_) { auto texture = pass_context.GetTexture(); // Render the backdrop texture before any of the pass elements. - const auto& proc = subpass->backdrop_filter_proc_.value(); + const auto& proc = subpass->backdrop_filter_proc_; backdrop_filter_contents = proc(FilterInput::Make(std::move(texture)), subpass->xformation_, /*is_subpass*/ true); @@ -478,7 +493,7 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( renderer, // renderer subpass_size, // size subpass->GetTotalPassReads(renderer) > 0, // readable - Color::BlackTransparent()); // clear_color + subpass->GetClearColor(subpass_size)); // clear_color if (!subpass_target.IsValid()) { VALIDATION_LOG << "Subpass render target is invalid."; @@ -559,7 +574,7 @@ bool EntityPass::OnRender( return false; } - if (!(clear_color_ == Color::BlackTransparent())) { + if (!(GetClearColor(root_pass_size) == Color::BlackTransparent())) { // Force the pass context to create at least one new pass if the clear color // is present. The `EndPass` first ensures that the clear color will get // applied even if this EntityPass is getting collapsed into the parent @@ -685,7 +700,7 @@ bool EntityPass::OnRender( return true; }; - if (backdrop_filter_proc_.has_value()) { + if (backdrop_filter_proc_) { if (!backdrop_filter_contents) { VALIDATION_LOG << "EntityPass contains a backdrop filter, but no backdrop filter " @@ -704,7 +719,19 @@ bool EntityPass::OnRender( render_element(backdrop_entity); } + bool is_collapsing_clear_colors = true; for (const auto& element : elements_) { + // Skip elements that are incorporated into the clear color. + if (is_collapsing_clear_colors) { + std::optional entity_color = + AsBackgroundColor(element, root_pass_size); + if (entity_color.has_value()) { + continue; + } else { + is_collapsing_clear_colors = false; + } + } + EntityResult result = GetEntityForElement(element, // element renderer, // renderer @@ -892,15 +919,20 @@ void EntityPass::SetBlendMode(BlendMode blend_mode) { flood_clip_ = Entity::IsBlendModeDestructive(blend_mode); } -void EntityPass::SetClearColor(Color clear_color) { - clear_color_ = clear_color; -} - -Color EntityPass::GetClearColor() const { - return clear_color_; +Color EntityPass::GetClearColor(ISize target_size) const { + Color result = Color::BlackTransparent(); + for (const Element& element : elements_) { + std::optional entity_color = AsBackgroundColor(element, target_size); + if (entity_color.has_value()) { + result = entity_color.value(); + } else { + break; + } + } + return result; } -void EntityPass::SetBackdropFilter(std::optional proc) { +void EntityPass::SetBackdropFilter(BackdropFilterProc proc) { if (superpass_) { VALIDATION_LOG << "Backdrop filters cannot be set on EntityPasses that " "have already been appended to another pass."; diff --git a/impeller/entity/entity_pass.h b/impeller/entity/entity_pass.h index 673e162c57881..ad83df5bbf284 100644 --- a/impeller/entity/entity_pass.h +++ b/impeller/entity/entity_pass.h @@ -86,11 +86,9 @@ class EntityPass { void SetBlendMode(BlendMode blend_mode); - void SetClearColor(Color clear_color); + Color GetClearColor(ISize size = ISize::Infinite()) const; - Color GetClearColor() const; - - void SetBackdropFilter(std::optional proc); + void SetBackdropFilter(BackdropFilterProc proc); void SetEnableOffscreenCheckerboard(bool enabled); @@ -210,7 +208,6 @@ class EntityPass { size_t stencil_depth_ = 0u; BlendMode blend_mode_ = BlendMode::kSourceOver; bool flood_clip_ = false; - Color clear_color_ = Color::BlackTransparent(); bool enable_offscreen_debug_checkerboard_ = false; /// These values are incremented whenever something is added to the pass that @@ -226,7 +223,7 @@ class EntityPass { uint32_t GetTotalPassReads(ContentContext& renderer) const; - std::optional backdrop_filter_proc_ = std::nullopt; + BackdropFilterProc backdrop_filter_proc_ = nullptr; std::unique_ptr delegate_ = EntityPassDelegate::MakeDefault(); diff --git a/impeller/entity/geometry/cover_geometry.cc b/impeller/entity/geometry/cover_geometry.cc index f2eb6c68140f7..f927c2d7299ba 100644 --- a/impeller/entity/geometry/cover_geometry.cc +++ b/impeller/entity/geometry/cover_geometry.cc @@ -54,4 +54,9 @@ std::optional CoverGeometry::GetCoverage(const Matrix& transform) const { return Rect::MakeMaximum(); } +bool CoverGeometry::CoversArea(const Matrix& transform, + const Rect& rect) const { + return true; +} + } // namespace impeller diff --git a/impeller/entity/geometry/cover_geometry.h b/impeller/entity/geometry/cover_geometry.h index 8bf20e1cc2643..737a46a22ab0d 100644 --- a/impeller/entity/geometry/cover_geometry.h +++ b/impeller/entity/geometry/cover_geometry.h @@ -16,6 +16,9 @@ class CoverGeometry : public Geometry { ~CoverGeometry(); + // |Geometry| + bool CoversArea(const Matrix& transform, const Rect& rect) const override; + private: // |Geometry| GeometryResult GetPositionBuffer(const ContentContext& renderer, diff --git a/impeller/entity/geometry/geometry.h b/impeller/entity/geometry/geometry.h index 95bf6799ad034..fa428aca24643 100644 --- a/impeller/entity/geometry/geometry.h +++ b/impeller/entity/geometry/geometry.h @@ -87,6 +87,12 @@ class Geometry { virtual GeometryVertexType GetVertexType() const = 0; virtual std::optional GetCoverage(const Matrix& transform) const = 0; + + /// @return `true` if this geometry will completely cover all fragments in + /// `rect` when the `transform` is applied to it. + virtual bool CoversArea(const Matrix& transform, const Rect& rect) const { + return false; + } }; } // namespace impeller diff --git a/impeller/entity/geometry/rect_geometry.cc b/impeller/entity/geometry/rect_geometry.cc index 0c34b8b36fd68..6328b40768c07 100644 --- a/impeller/entity/geometry/rect_geometry.cc +++ b/impeller/entity/geometry/rect_geometry.cc @@ -47,4 +47,12 @@ std::optional RectGeometry::GetCoverage(const Matrix& transform) const { return rect_.TransformBounds(transform); } +bool RectGeometry::CoversArea(const Matrix& transform, const Rect& rect) const { + if (!transform.IsTranslationScaleOnly()) { + return false; + } + Rect coverage = rect_.TransformBounds(transform); + return coverage.Contains(rect); +} + } // namespace impeller diff --git a/impeller/entity/geometry/rect_geometry.h b/impeller/entity/geometry/rect_geometry.h index 1833d70d279b9..4880aa65a0ded 100644 --- a/impeller/entity/geometry/rect_geometry.h +++ b/impeller/entity/geometry/rect_geometry.h @@ -14,6 +14,9 @@ class RectGeometry : public Geometry { ~RectGeometry(); + // |Geometry| + bool CoversArea(const Matrix& transform, const Rect& rect) const override; + private: // |Geometry| GeometryResult GetPositionBuffer(const ContentContext& renderer, diff --git a/impeller/entity/shaders/blending/advanced_blend.vert b/impeller/entity/shaders/blending/advanced_blend.vert index 7def43db01f6f..5a5535ab869d6 100644 --- a/impeller/entity/shaders/blending/advanced_blend.vert +++ b/impeller/entity/shaders/blending/advanced_blend.vert @@ -12,12 +12,12 @@ uniform FrameInfo { } frame_info; -in highp vec2 vertices; -in highp vec2 dst_texture_coords; -in highp vec2 src_texture_coords; +in vec2 vertices; +in vec2 dst_texture_coords; +in vec2 src_texture_coords; -out highp vec2 v_dst_texture_coords; -out highp vec2 v_src_texture_coords; +out vec2 v_dst_texture_coords; +out vec2 v_src_texture_coords; void main() { gl_Position = frame_info.mvp * vec4(vertices, 0.0, 1.0); diff --git a/impeller/entity/shaders/blending/blend.vert b/impeller/entity/shaders/blending/blend.vert index 444e0a5cd2b27..f8a08ecee3b37 100644 --- a/impeller/entity/shaders/blending/blend.vert +++ b/impeller/entity/shaders/blending/blend.vert @@ -11,10 +11,10 @@ uniform FrameInfo { } frame_info; -in highp vec2 vertices; -in highp vec2 texture_coords; +in vec2 vertices; +in vec2 texture_coords; -out highp vec2 v_texture_coords; +out vec2 v_texture_coords; void main() { gl_Position = frame_info.mvp * vec4(vertices, 0.0, 1.0); diff --git a/impeller/entity/shaders/border_mask_blur.vert b/impeller/entity/shaders/border_mask_blur.vert index ffab3d68b85b0..0dbc6fd4bfad4 100644 --- a/impeller/entity/shaders/border_mask_blur.vert +++ b/impeller/entity/shaders/border_mask_blur.vert @@ -11,10 +11,10 @@ uniform FrameInfo { } frame_info; -in highp vec2 position; -in highp vec2 texture_coords; +in vec2 position; +in vec2 texture_coords; -out highp vec2 v_texture_coords; +out vec2 v_texture_coords; void main() { gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); diff --git a/impeller/entity/shaders/color_matrix_color_filter.vert b/impeller/entity/shaders/color_matrix_color_filter.vert index fd6914a9fbdd4..5a631d8b1f039 100644 --- a/impeller/entity/shaders/color_matrix_color_filter.vert +++ b/impeller/entity/shaders/color_matrix_color_filter.vert @@ -11,9 +11,9 @@ uniform FrameInfo { } frame_info; -in highp vec2 position; +in vec2 position; -out highp vec2 v_texture_coords; +out vec2 v_texture_coords; void main() { gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); diff --git a/impeller/entity/shaders/gaussian_blur/gaussian_blur.vert b/impeller/entity/shaders/gaussian_blur/gaussian_blur.vert index 1a3bad09e35d4..6e1b89964a668 100644 --- a/impeller/entity/shaders/gaussian_blur/gaussian_blur.vert +++ b/impeller/entity/shaders/gaussian_blur/gaussian_blur.vert @@ -12,12 +12,12 @@ uniform FrameInfo { } frame_info; -in highp vec2 vertices; -in highp vec2 texture_coords; -in highp vec2 src_texture_coords; +in vec2 vertices; +in vec2 texture_coords; +in vec2 src_texture_coords; -out highp vec2 v_texture_coords; -out highp vec2 v_src_texture_coords; +out vec2 v_texture_coords; +out vec2 v_src_texture_coords; void main() { gl_Position = frame_info.mvp * vec4(vertices, 0.0, 1.0); diff --git a/impeller/entity/shaders/glyph_atlas.vert b/impeller/entity/shaders/glyph_atlas.vert index 4c63866a60349..d21f75a10dd27 100644 --- a/impeller/entity/shaders/glyph_atlas.vert +++ b/impeller/entity/shaders/glyph_atlas.vert @@ -4,26 +4,24 @@ #include -precision highp float; - uniform FrameInfo { - highp mat4 mvp; - highp mat4 entity_transform; - highp vec2 atlas_size; - highp vec2 offset; + mat4 mvp; + mat4 entity_transform; + vec2 atlas_size; + vec2 offset; float is_translation_scale; } frame_info; // XYWH. -in highp vec4 atlas_glyph_bounds; +in vec4 atlas_glyph_bounds; // XYWH -in highp vec4 glyph_bounds; +in vec4 glyph_bounds; -in highp vec2 unit_position; -in highp vec2 glyph_position; +in vec2 unit_position; +in vec2 glyph_position; -out highp vec2 v_uv; +out vec2 v_uv; mat4 basis(mat4 m) { return mat4(m[0][0], m[0][1], m[0][2], 0.0, // diff --git a/impeller/entity/shaders/gradient_fill.vert b/impeller/entity/shaders/gradient_fill.vert index 6176063308192..824f496ea8c22 100644 --- a/impeller/entity/shaders/gradient_fill.vert +++ b/impeller/entity/shaders/gradient_fill.vert @@ -11,9 +11,9 @@ uniform FrameInfo { } frame_info; -in highp vec2 position; +in vec2 position; -out highp vec2 v_position; +out vec2 v_position; void main() { gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); diff --git a/impeller/entity/shaders/linear_to_srgb_filter.vert b/impeller/entity/shaders/linear_to_srgb_filter.vert index fd6914a9fbdd4..5a631d8b1f039 100644 --- a/impeller/entity/shaders/linear_to_srgb_filter.vert +++ b/impeller/entity/shaders/linear_to_srgb_filter.vert @@ -11,9 +11,9 @@ uniform FrameInfo { } frame_info; -in highp vec2 position; +in vec2 position; -out highp vec2 v_texture_coords; +out vec2 v_texture_coords; void main() { gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); diff --git a/impeller/entity/shaders/morphology_filter.vert b/impeller/entity/shaders/morphology_filter.vert index ffab3d68b85b0..0dbc6fd4bfad4 100644 --- a/impeller/entity/shaders/morphology_filter.vert +++ b/impeller/entity/shaders/morphology_filter.vert @@ -11,10 +11,10 @@ uniform FrameInfo { } frame_info; -in highp vec2 position; -in highp vec2 texture_coords; +in vec2 position; +in vec2 texture_coords; -out highp vec2 v_texture_coords; +out vec2 v_texture_coords; void main() { gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); diff --git a/impeller/entity/shaders/position_color.vert b/impeller/entity/shaders/position_color.vert index 63a5518030af0..d6b35c464f7d9 100644 --- a/impeller/entity/shaders/position_color.vert +++ b/impeller/entity/shaders/position_color.vert @@ -10,12 +10,12 @@ uniform FrameInfo { } frame_info; -in highp vec2 position; +in vec2 position; in vec4 color; -out vec4 v_color; +out f16vec4 v_color; void main() { gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); - v_color = color; + v_color = f16vec4(color); } diff --git a/impeller/entity/shaders/rrect_blur.vert b/impeller/entity/shaders/rrect_blur.vert index 647d37f8f52f7..87382f6b4dcbe 100644 --- a/impeller/entity/shaders/rrect_blur.vert +++ b/impeller/entity/shaders/rrect_blur.vert @@ -9,9 +9,9 @@ uniform FrameInfo { } frame_info; -in highp vec2 position; +in vec2 position; -out highp vec2 v_position; +out vec2 v_position; void main() { gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); diff --git a/impeller/entity/shaders/runtime_effect.vert b/impeller/entity/shaders/runtime_effect.vert index 35244e876a74b..77b92d221142c 100644 --- a/impeller/entity/shaders/runtime_effect.vert +++ b/impeller/entity/shaders/runtime_effect.vert @@ -9,11 +9,11 @@ uniform FrameInfo { } frame_info; -in highp vec2 position; +in vec2 position; // Note: The GLES backend uses name matching for attribute locations. This name // must match the name of the attribute input in: // impeller/compiler/shader_lib/flutter/runtime_effect.glsl -out highp vec2 _fragCoord; +out vec2 _fragCoord; void main() { gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); diff --git a/impeller/entity/shaders/solid_fill.vert b/impeller/entity/shaders/solid_fill.vert index 877c5ff304571..4d8e67e74a2ef 100644 --- a/impeller/entity/shaders/solid_fill.vert +++ b/impeller/entity/shaders/solid_fill.vert @@ -9,7 +9,7 @@ uniform FrameInfo { } frame_info; -in highp vec2 position; +in vec2 position; void main() { gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); diff --git a/impeller/entity/shaders/srgb_to_linear_filter.vert b/impeller/entity/shaders/srgb_to_linear_filter.vert index fd6914a9fbdd4..5a631d8b1f039 100644 --- a/impeller/entity/shaders/srgb_to_linear_filter.vert +++ b/impeller/entity/shaders/srgb_to_linear_filter.vert @@ -11,9 +11,9 @@ uniform FrameInfo { } frame_info; -in highp vec2 position; +in vec2 position; -out highp vec2 v_texture_coords; +out vec2 v_texture_coords; void main() { gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); diff --git a/impeller/entity/shaders/texture_fill.vert b/impeller/entity/shaders/texture_fill.vert index 61aec522fef46..0dbc6fd4bfad4 100644 --- a/impeller/entity/shaders/texture_fill.vert +++ b/impeller/entity/shaders/texture_fill.vert @@ -11,10 +11,10 @@ uniform FrameInfo { } frame_info; -in highp vec2 position; +in vec2 position; in vec2 texture_coords; -out highp vec2 v_texture_coords; +out vec2 v_texture_coords; void main() { gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); diff --git a/impeller/entity/shaders/yuv_to_rgb_filter.vert b/impeller/entity/shaders/yuv_to_rgb_filter.vert index fd6914a9fbdd4..5a631d8b1f039 100644 --- a/impeller/entity/shaders/yuv_to_rgb_filter.vert +++ b/impeller/entity/shaders/yuv_to_rgb_filter.vert @@ -11,9 +11,9 @@ uniform FrameInfo { } frame_info; -in highp vec2 position; +in vec2 position; -out highp vec2 v_texture_coords; +out vec2 v_texture_coords; void main() { gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); diff --git a/impeller/geometry/color.cc b/impeller/geometry/color.cc index 79ed191c8446d..2efe123c906f4 100644 --- a/impeller/geometry/color.cc +++ b/impeller/geometry/color.cc @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -128,7 +129,7 @@ Color::Color(const ColorHSB& hsbColor) : Color(hsbColor.ToRGBA()) {} Color::Color(const Vector4& value) : red(value.x), green(value.y), blue(value.z), alpha(value.w) {} -static constexpr Color Min(Color c, float threshold) { +static constexpr inline Color Min(Color c, float threshold) { return Color(std::min(c.red, threshold), std::min(c.green, threshold), std::min(c.blue, threshold), std::min(c.alpha, threshold)); } @@ -136,66 +137,90 @@ static constexpr Color Min(Color c, float threshold) { // The following HSV utilities correspond to the W3C blend definitions // implemented in: impeller/compiler/shader_lib/impeller/blending.glsl -static constexpr Scalar Luminosity(Vector3 color) { - return color.x * 0.3 + color.y * 0.59 + color.z * 0.11; +static constexpr inline Scalar Luminosity(Vector3 color) { + return color.x * 0.3f + color.y * 0.59f + color.z * 0.11f; } -static constexpr Vector3 ClipColor(Vector3 color) { +static constexpr inline Vector3 ClipColor(Vector3 color) { Scalar lum = Luminosity(color); Scalar mn = std::min(std::min(color.x, color.y), color.z); Scalar mx = std::max(std::max(color.x, color.y), color.z); - if (mn < 0.0) { + // `lum - mn` and `mx - lum` will always be >= 0 in the following conditions, + // so adding a tiny value is enough to make these divisions safe. + if (mn < 0.0f) { color = lum + (((color - lum) * lum) / (lum - mn + kEhCloseEnough)); } if (mx > 1.0) { - color = lum + (((color - lum) * (1.0 - lum)) / (mx - lum + kEhCloseEnough)); + color = + lum + (((color - lum) * (1.0f - lum)) / (mx - lum + kEhCloseEnough)); } - return Vector3(); + return color; } -static constexpr Vector3 SetLuminosity(Vector3 color, Scalar luminosity) { +static constexpr inline Vector3 SetLuminosity(Vector3 color, + Scalar luminosity) { Scalar relative_lum = luminosity - Luminosity(color); return ClipColor(color + relative_lum); } -static constexpr Scalar Saturation(Vector3 color) { +static constexpr inline Scalar Saturation(Vector3 color) { return std::max(std::max(color.x, color.y), color.z) - std::min(std::min(color.x, color.y), color.z); } -static constexpr Vector3 SetSaturation(Vector3 color, Scalar saturation) { +static constexpr inline Vector3 SetSaturation(Vector3 color, + Scalar saturation) { Scalar mn = std::min(std::min(color.x, color.y), color.z); Scalar mx = std::max(std::max(color.x, color.y), color.z); return (mn < mx) ? ((color - mn) * saturation) / (mx - mn) : Vector3(); } -static constexpr Vector3 ComponentChoose(Vector3 a, - Vector3 b, - Vector3 value, - Scalar cutoff) { +static constexpr inline Vector3 ComponentChoose(Vector3 a, + Vector3 b, + Vector3 value, + Scalar cutoff) { return Vector3(value.x > cutoff ? b.x : a.x, // value.y > cutoff ? b.y : a.y, // value.z > cutoff ? b.z : a.z // ); } -static constexpr Vector3 ToRGB(Color color) { +static constexpr inline Vector3 ToRGB(Color color) { return {color.red, color.green, color.blue}; } -static constexpr Color FromRGB(Vector3 color, Scalar alpha) { +static constexpr inline Color FromRGB(Vector3 color, Scalar alpha) { return {color.x, color.y, color.z, alpha}; } -Color Color::Blend(const Color& src, BlendMode blend_mode) const { - const Color& dst = *this; +static constexpr inline Color DoColorBlend( + Color d, + Color s, + const std::function& blend_rgb_func) { + d = d.Premultiply(); + s = s.Premultiply(); + const Vector3 rgb = blend_rgb_func(ToRGB(d), ToRGB(s)); + const Color blended = Color::Lerp(s, FromRGB(rgb, d.alpha), d.alpha); + return Color::Lerp(d, blended, s.alpha).Unpremultiply(); +} - static auto apply_rgb_srcover_alpha = [&](auto f) -> Color { - return Color(f(src.red, dst.red), f(src.green, dst.green), - f(src.blue, dst.blue), - dst.alpha * (1 - src.alpha) + src.alpha // srcOver alpha - ); - }; +static constexpr inline Color DoColorBlendComponents( + Color d, + Color s, + const std::function& blend_func) { + d = d.Premultiply(); + s = s.Premultiply(); + const Color blended = Color::Lerp(s, + Color(blend_func(d.red, s.red), // + blend_func(d.green, s.green), // + blend_func(d.blue, s.blue), // + d.alpha), + d.alpha); + return Color::Lerp(d, blended, s.alpha).Unpremultiply(); +} + +Color Color::Blend(Color src, BlendMode blend_mode) const { + Color dst = *this; switch (blend_mode) { case BlendMode::kClear: @@ -246,127 +271,95 @@ Color Color::Blend(const Color& src, BlendMode blend_mode) const { // r = s*d return (src.Premultiply() * dst.Premultiply()).Unpremultiply(); case BlendMode::kScreen: { - // r = s + d - s*d - auto s = src.Premultiply(); - auto d = dst.Premultiply(); - return (s + d - s * d).Unpremultiply(); + return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 { + return s + d - s * d; + }); } case BlendMode::kOverlay: - return apply_rgb_srcover_alpha([&](auto s, auto d) { - if (d * 2 <= dst.alpha) { - return 2 * s * d; - } - return src.alpha * dst.alpha - 2 * (dst.alpha - d) * (src.alpha - s); - }); - case BlendMode::kDarken: { - return apply_rgb_srcover_alpha([&](auto s, auto d) { - return (1 - dst.alpha) * s + (1 - src.alpha) * d + std::min(s, d); + return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 { + // The same as HardLight, but with the source and destination reversed. + Vector3 screen_src = 2.0 * d - 1.0; + Vector3 screen = screen_src + s - screen_src * s; + return ComponentChoose(s * (2.0 * d), // + screen, // + d, // + 0.5); }); - } + case BlendMode::kDarken: + return DoColorBlend( + dst, src, [](Vector3 d, Vector3 s) -> Vector3 { return d.Min(s); }); case BlendMode::kLighten: - return apply_rgb_srcover_alpha([&](auto s, auto d) { - return (1 - dst.alpha) * s + (1 - src.alpha) * d + std::max(s, d); - }); + return DoColorBlend( + dst, src, [](Vector3 d, Vector3 s) -> Vector3 { return d.Max(s); }); case BlendMode::kColorDodge: - return apply_rgb_srcover_alpha([&](auto s, auto d) { - if (d == 0) { - return s * (1 - src.alpha); + return DoColorBlendComponents(dst, src, [](Scalar d, Scalar s) -> Scalar { + if (d < kEhCloseEnough) { + return 0.0f; } - if (s == src.alpha) { - return s + dst.alpha * (1 - src.alpha); + if (1.0 - s < kEhCloseEnough) { + return 1.0f; } - return src.alpha * - std::min(dst.alpha, d * src.alpha / (src.alpha - s)) + - s * (1 - dst.alpha + dst.alpha * (1 - src.alpha)); + return std::min(1.0f, d / (1.0f - s)); }); case BlendMode::kColorBurn: - return apply_rgb_srcover_alpha([&](auto s, auto d) { - if (s == 0) { - return dst.alpha * (1 - src.alpha); + return DoColorBlendComponents(dst, src, [](Scalar d, Scalar s) -> Scalar { + if (1.0 - d < kEhCloseEnough) { + return 1.0f; } - if (d == dst.alpha) { - return d + s * (1 - dst.alpha); + if (s < kEhCloseEnough) { + return 0.0f; } - // s.a * (d.a - min(d.a, (d.a - s) * s.a/s)) + s * (1-d.a) + d.a * (1 - - // s.a) - return src.alpha * - (dst.alpha - - std::min(dst.alpha, (dst.alpha - d) * src.alpha / s)) + - s * (1 - dst.alpha) + dst.alpha * (1 - src.alpha); + return 1.0f - std::min(1.0f, (1.0f - d) / s); }); case BlendMode::kHardLight: - return apply_rgb_srcover_alpha([&](auto s, auto d) { - if (src.alpha >= s * (1 - dst.alpha) + d * (1 - src.alpha) + 2 * s) { - return 2 * s * d; - } - // s.a * d.a - 2 * (d.a - d) * (s.a - s) - return src.alpha * dst.alpha - 2 * (dst.alpha - d) * (src.alpha - s); + return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 { + Vector3 screen_src = 2.0 * s - 1.0; + Vector3 screen = screen_src + d - screen_src * d; + return ComponentChoose(d * (2.0 * s), // + screen, // + s, // + 0.5); + }); + case BlendMode::kSoftLight: + return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 { + Vector3 D = ComponentChoose(((16.0 * d - 12.0) * d + 4.0) * d, // + Vector3(std::sqrt(d.x), std::sqrt(d.y), + std::sqrt(d.z)), // + d, // + 0.25); + return ComponentChoose(d - (1.0 - 2.0 * s) * d * (1.0 - d), // + d + (2.0 * s - 1.0) * (D - d), // + s, // + 0.5); }); - case BlendMode::kSoftLight: { - Vector3 dst_rgb = ToRGB(dst); - Vector3 src_rgb = ToRGB(src); - Vector3 d = ComponentChoose( - ((16.0 * dst_rgb - 12.0) * dst_rgb + 4.0) * dst_rgb, // - Vector3(std::sqrt(dst_rgb.x), std::sqrt(dst_rgb.y), - std::sqrt(dst_rgb.z)), // - dst_rgb, // - 0.25); - Color blended = FromRGB( - ComponentChoose( - dst_rgb - (1.0 - 2.0 * src_rgb) * dst_rgb * (1.0 - dst_rgb), // - dst_rgb + (2.0 * src_rgb - 1.0) * (d - dst_rgb), // - src_rgb, // - 0.5), - dst.alpha); - return blended + dst * (1 - blended.alpha); - } case BlendMode::kDifference: - return apply_rgb_srcover_alpha([&](auto s, auto d) { - // s + d - 2 * min(s * d.a, d * s.a); - return s + d - 2 * std::min(s * dst.alpha, d * src.alpha); + return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 { + return (d - s).Abs(); }); case BlendMode::kExclusion: - return apply_rgb_srcover_alpha([&](auto s, auto d) { - // s + d - 2 * s * d - return s + d - 2 * s * d; + return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 { + return d + s - 2.0f * d * s; }); case BlendMode::kMultiply: - return apply_rgb_srcover_alpha([&](auto s, auto d) { - // s * (1 - d.a) + d * (1 - s.a) + (s * d) - return s * (1 - dst.alpha) + d * (1 - src.alpha) + (s * d); - }); + return DoColorBlend( + dst, src, [](Vector3 d, Vector3 s) -> Vector3 { return d * s; }); case BlendMode::kHue: { - Vector3 dst_rgb = ToRGB(dst); - Vector3 src_rgb = ToRGB(src); - Color blended = - FromRGB(SetLuminosity(SetSaturation(src_rgb, Saturation(dst_rgb)), - Luminosity(dst_rgb)), - dst.alpha); - return blended + dst * (1 - blended.alpha); - } - case BlendMode::kSaturation: { - Vector3 dst_rgb = ToRGB(dst); - Vector3 src_rgb = ToRGB(src); - Color blended = - FromRGB(SetLuminosity(SetSaturation(dst_rgb, Saturation(src_rgb)), - Luminosity(dst_rgb)), - dst.alpha); - return blended + dst * (1 - blended.alpha); - } - case BlendMode::kColor: { - Vector3 dst_rgb = ToRGB(dst); - Vector3 src_rgb = ToRGB(src); - Color blended = - FromRGB(SetLuminosity(src_rgb, Luminosity(dst_rgb)), dst.alpha); - return blended + dst * (1 - blended.alpha); - } - case BlendMode::kLuminosity: { - Vector3 dst_rgb = ToRGB(dst); - Vector3 src_rgb = ToRGB(src); - Color blended = - FromRGB(SetLuminosity(dst_rgb, Luminosity(src_rgb)), dst.alpha); - return blended + dst * (1 - blended.alpha); + return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 { + return SetLuminosity(SetSaturation(s, Saturation(d)), Luminosity(d)); + }); } + case BlendMode::kSaturation: + return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 { + return SetLuminosity(SetSaturation(d, Saturation(s)), Luminosity(d)); + }); + case BlendMode::kColor: + return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 { + return SetLuminosity(s, Luminosity(d)); + }); + case BlendMode::kLuminosity: + return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 { + return SetLuminosity(d, Luminosity(s)); + }); } } diff --git a/impeller/geometry/color.h b/impeller/geometry/color.h index 77bb9790d7664..02c89627d94d4 100644 --- a/impeller/geometry/color.h +++ b/impeller/geometry/color.h @@ -222,7 +222,7 @@ struct Color { /** * @brief Return a color that is linearly interpolated between colors a - * and b, according to the value of t. + * and b, according to the value of t. * * @param a The lower color. * @param b The upper color. @@ -230,9 +230,7 @@ struct Color { * @return constexpr Color */ constexpr static Color Lerp(Color a, Color b, Scalar t) { - Scalar tt = 1.0f - t; - return {a.red * tt + b.red * t, a.green * tt + b.green * t, - a.blue * tt + b.blue * t, a.alpha * tt + b.alpha * t}; + return a + (b - a) * t; } constexpr Color Clamp01() const { @@ -853,7 +851,7 @@ struct Color { /// /// If either the source or destination are premultiplied, the result /// will be incorrect. - Color Blend(const Color& source, BlendMode blend_mode) const; + Color Blend(Color source, BlendMode blend_mode) const; /// @brief A color filter that transforms colors through a 4x5 color matrix. /// diff --git a/impeller/geometry/vector.h b/impeller/geometry/vector.h index d2506fd890930..a644dd54173df 100644 --- a/impeller/geometry/vector.h +++ b/impeller/geometry/vector.h @@ -52,6 +52,10 @@ struct Vector3 { return ((x * other.x) + (y * other.y) + (z * other.z)); } + constexpr Vector3 Abs() const { + return {std::fabs(x), std::fabs(y), std::fabs(z)}; + } + constexpr Vector3 Cross(const Vector3& other) const { return { (y * other.z) - (z * other.y), // diff --git a/impeller/golden_tests/golden_playground_test.h b/impeller/golden_tests/golden_playground_test.h index 05fc5d09fe217..a165fdd103189 100644 --- a/impeller/golden_tests/golden_playground_test.h +++ b/impeller/golden_tests/golden_playground_test.h @@ -52,14 +52,16 @@ class GoldenPlaygroundTest ISize GetWindowSize() const; private: - struct GoldenPlaygroundTestImpl; - // This is only a shared_ptr so it can work with a forward declared type. - std::shared_ptr pimpl_; - #if FML_OS_MACOSX + // This must be placed first so that the autorelease pool is not destroyed + // until the GoldenPlaygroundTestImpl has been destructed. fml::ScopedNSAutoreleasePool autorelease_pool_; #endif + struct GoldenPlaygroundTestImpl; + // This is only a shared_ptr so it can work with a forward declared type. + std::shared_ptr pimpl_; + FML_DISALLOW_COPY_AND_ASSIGN(GoldenPlaygroundTest); }; diff --git a/impeller/golden_tests/golden_tests.cc b/impeller/golden_tests/golden_tests.cc index 24a229e9a452b..c99d9abc05852 100644 --- a/impeller/golden_tests/golden_tests.cc +++ b/impeller/golden_tests/golden_tests.cc @@ -6,6 +6,7 @@ #include +#include "flutter/fml/platform/darwin/scoped_nsautorelease_pool.h" #include "impeller/aiks/canvas.h" #include "impeller/entity/contents/conical_gradient_contents.h" #include "impeller/geometry/path_builder.h" @@ -59,6 +60,10 @@ class GoldenTests : public ::testing::Test { } private: + // This must be placed before any other members that may use the + // autorelease pool. + fml::ScopedNSAutoreleasePool autorelease_pool_; + std::unique_ptr screenshoter_; }; diff --git a/impeller/renderer/backend/gles/context_gles.cc b/impeller/renderer/backend/gles/context_gles.cc index 4f590e2b2d729..34b095d46ab48 100644 --- a/impeller/renderer/backend/gles/context_gles.cc +++ b/impeller/renderer/backend/gles/context_gles.cc @@ -76,6 +76,7 @@ ContextGLES::ContextGLES(std::unique_ptr gl, .SetSupportsReadFromResolve(false) .SetSupportsReadFromOnscreenTexture(false) .SetSupportsDecalTileMode(false) + .SetSupportsMemorylessTextures(false) .Build(); } diff --git a/impeller/renderer/backend/metal/context_mtl.mm b/impeller/renderer/backend/metal/context_mtl.mm index 223762608b153..db2c1fef0cc21 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -64,6 +64,7 @@ static bool DeviceSupportsComputeSubgroups(id device) { .SetSupportsComputeSubgroups(DeviceSupportsComputeSubgroups(device)) .SetSupportsReadFromResolve(true) .SetSupportsReadFromOnscreenTexture(true) + .SetSupportsMemorylessTextures(true) .Build(); } diff --git a/impeller/renderer/backend/metal/vertex_descriptor_mtl.mm b/impeller/renderer/backend/metal/vertex_descriptor_mtl.mm index b5948830f9abf..6bac6687880c6 100644 --- a/impeller/renderer/backend/metal/vertex_descriptor_mtl.mm +++ b/impeller/renderer/backend/metal/vertex_descriptor_mtl.mm @@ -174,8 +174,8 @@ static MTLVertexFormat ReadStageInputFormat(const ShaderStageIOSlot& input) { const std::vector& layouts) { auto descriptor = descriptor_ = [MTLVertexDescriptor vertexDescriptor]; - // TODO: its odd that we offset buffers from the max index on metal - // but not on GLES or Vulkan. We should probably consistently start + // TODO(jonahwilliams): its odd that we offset buffers from the max index on + // metal but not on GLES or Vulkan. We should probably consistently start // these at zero? for (size_t i = 0; i < inputs.size(); i++) { const auto& input = inputs[i]; diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index f02dae6f1672c..bb5b2f7b93cf5 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -16,106 +16,16 @@ namespace impeller { -static constexpr VkMemoryPropertyFlags ToVKMemoryPropertyFlags( - StorageMode mode) { - switch (mode) { - case StorageMode::kHostVisible: - // See https://github.com/flutter/flutter/issues/128556 . Some devices do - // not have support for coherent host memory so we don't request it here. - return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; - case StorageMode::kDevicePrivate: - return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - case StorageMode::kDeviceTransient: - return VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; - } - FML_UNREACHABLE(); -} - -static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode, - bool is_texture, - size_t size) { - VmaAllocationCreateFlags flags = 0; - switch (mode) { - case StorageMode::kHostVisible: - if (is_texture) { - if (size >= kImageSizeThresholdForDedicatedMemoryAllocation) { - flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; - } else { - flags |= {}; - } - } else { - flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; - flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT; - } - return flags; - case StorageMode::kDevicePrivate: - if (is_texture && - size >= kImageSizeThresholdForDedicatedMemoryAllocation) { - flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; - } - return flags; - case StorageMode::kDeviceTransient: - return flags; - } - FML_UNREACHABLE(); -} - -vk::Flags VmaBufferUsageFlags(UsageHint usage) { - switch (usage) { - case UsageHint::kRasterWorkload: - return vk::BufferUsageFlagBits::eVertexBuffer | - vk::BufferUsageFlagBits::eIndexBuffer | - vk::BufferUsageFlagBits::eUniformBuffer | - vk::BufferUsageFlagBits::eStorageBuffer | - vk::BufferUsageFlagBits::eTransferSrc | - vk::BufferUsageFlagBits::eTransferDst; - case UsageHint::kImageUpload: - return vk::BufferUsageFlagBits::eTransferSrc; - } - FML_UNREACHABLE(); -} - -static bool CreateBufferPool(VmaAllocator allocator, - UsageHint usage, - VmaPool* pool) { - vk::BufferCreateInfo buffer_info; - buffer_info.usage = VmaBufferUsageFlags(usage); - buffer_info.size = 1u; // doesn't matter - buffer_info.sharingMode = vk::SharingMode::eExclusive; - auto buffer_info_native = - static_cast(buffer_info); - - VmaAllocationCreateInfo allocation_info = {}; - allocation_info.usage = VMA_MEMORY_USAGE_AUTO; - allocation_info.preferredFlags = - ToVKMemoryPropertyFlags(StorageMode::kHostVisible); - allocation_info.flags = - VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | - VMA_ALLOCATION_CREATE_MAPPED_BIT; - - uint32_t memTypeIndex; - VkResult res = vmaFindMemoryTypeIndexForBufferInfo( - allocator, &buffer_info_native, &allocation_info, &memTypeIndex); - - VmaPoolCreateInfo poolCreateInfo = {}; - poolCreateInfo.memoryTypeIndex = memTypeIndex; - - auto result = vk::Result{vmaCreatePool(allocator, &poolCreateInfo, pool)}; - if (result != vk::Result::eSuccess) { - VALIDATION_LOG << "Could not create memory allocator"; - return false; - } - return true; -} - AllocatorVK::AllocatorVK(std::weak_ptr context, uint32_t vulkan_api_version, const vk::PhysicalDevice& physical_device, const std::shared_ptr& device_holder, const vk::Instance& instance, PFN_vkGetInstanceProcAddr get_instance_proc_address, - PFN_vkGetDeviceProcAddr get_device_proc_address) + PFN_vkGetDeviceProcAddr get_device_proc_address, + const CapabilitiesVK& capabilities) : context_(std::move(context)), device_holder_(device_holder) { + TRACE_EVENT0("impeller", "CreateAllocatorVK"); vk_ = fml::MakeRefCounted(get_instance_proc_address); auto instance_handle = vulkan::VulkanHandle(instance); @@ -231,10 +141,12 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, } allocator_ = allocator; + supports_memoryless_textures_ = capabilities.SupportsMemorylessTextures(); is_valid_ = true; } AllocatorVK::~AllocatorVK() { + TRACE_EVENT0("impeller", "DestroyAllocatorVK"); if (allocator_) { if (raster_buffer_pool_) { ::vmaDestroyPool(allocator_, raster_buffer_pool_); @@ -259,9 +171,11 @@ ISize AllocatorVK::GetMaxTextureSizeSupported() const { return max_texture_size_; } -static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(PixelFormat format, - TextureUsageMask usage, - StorageMode mode) { +static constexpr vk::ImageUsageFlags ToVKImageUsageFlags( + PixelFormat format, + TextureUsageMask usage, + StorageMode mode, + bool supports_memoryless_textures) { vk::ImageUsageFlags vk_usage; switch (mode) { @@ -269,7 +183,9 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(PixelFormat format, case StorageMode::kDevicePrivate: break; case StorageMode::kDeviceTransient: - vk_usage |= vk::ImageUsageFlagBits::eTransientAttachment; + if (supports_memoryless_textures) { + vk_usage |= vk::ImageUsageFlagBits::eTransientAttachment; + } break; } @@ -317,13 +233,76 @@ static constexpr VmaMemoryUsage ToVMAMemoryUsage() { return VMA_MEMORY_USAGE_AUTO; } +static constexpr VkMemoryPropertyFlags ToVKTextureMemoryPropertyFlags( + StorageMode mode, + bool supports_memoryless_textures) { + switch (mode) { + case StorageMode::kHostVisible: + return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + case StorageMode::kDevicePrivate: + return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + case StorageMode::kDeviceTransient: + if (supports_memoryless_textures) { + return VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT | + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + FML_UNREACHABLE(); +} + +static constexpr VkMemoryPropertyFlags ToVKBufferMemoryPropertyFlags( + StorageMode mode) { + switch (mode) { + case StorageMode::kHostVisible: + return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + case StorageMode::kDevicePrivate: + return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + case StorageMode::kDeviceTransient: + return VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; + } + FML_UNREACHABLE(); +} + +static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode, + bool is_texture, + size_t size) { + VmaAllocationCreateFlags flags = 0; + switch (mode) { + case StorageMode::kHostVisible: + if (is_texture) { + if (size >= kImageSizeThresholdForDedicatedMemoryAllocation) { + flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; + } else { + flags |= {}; + } + } else { + flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; + flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT; + } + return flags; + case StorageMode::kDevicePrivate: + if (is_texture && + size >= kImageSizeThresholdForDedicatedMemoryAllocation) { + flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; + } + return flags; + case StorageMode::kDeviceTransient: + return flags; + } + FML_UNREACHABLE(); +} + class AllocatedTextureSourceVK final : public TextureSourceVK { public: AllocatedTextureSourceVK(const TextureDescriptor& desc, VmaAllocator allocator, - VmaPool pool, - vk::Device device) + vk::Device device, + bool supports_memoryless_textures) : TextureSourceVK(desc) { + TRACE_EVENT0("impeller", "CreateDeviceTexture"); vk::ImageCreateInfo image_info; image_info.flags = ToVKImageCreateFlags(desc.type); image_info.imageType = vk::ImageType::e2D; @@ -339,21 +318,18 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { image_info.tiling = vk::ImageTiling::eOptimal; image_info.initialLayout = vk::ImageLayout::eUndefined; image_info.usage = - ToVKImageUsageFlags(desc.format, desc.usage, desc.storage_mode); + ToVKImageUsageFlags(desc.format, desc.usage, desc.storage_mode, + supports_memoryless_textures); image_info.sharingMode = vk::SharingMode::eExclusive; VmaAllocationCreateInfo alloc_nfo = {}; alloc_nfo.usage = ToVMAMemoryUsage(); - alloc_nfo.preferredFlags = ToVKMemoryPropertyFlags(desc.storage_mode); - - auto image_upload = desc.usage_hint == UsageHint::kImageUpload; - alloc_nfo.flags = ToVmaAllocationCreateFlags( - desc.storage_mode, /*is_texture=*/true, - image_upload ? 0u : desc.GetByteSizeOfBaseMipLevel()); - if (image_upload) { - alloc_nfo.pool = pool; - } + alloc_nfo.preferredFlags = ToVKTextureMemoryPropertyFlags( + desc.storage_mode, supports_memoryless_textures); + alloc_nfo.flags = + ToVmaAllocationCreateFlags(desc.storage_mode, /*is_texture=*/true, + desc.GetByteSizeOfBaseMipLevel()); auto create_info_native = static_cast(image_info); @@ -418,6 +394,7 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { } ~AllocatedTextureSourceVK() { + TRACE_EVENT0("impeller", "DestroyDeviceTexture"); image_view_.reset(); if (image_) { ::vmaDestroyImage( @@ -455,12 +432,12 @@ std::shared_ptr AllocatorVK::OnCreateTexture( if (!device_holder) { return nullptr; } - auto source = - std::make_shared(desc, // - allocator_, // - image_upload_texture_pool_, // - device_holder->GetDevice() // - ); + auto source = std::make_shared( + desc, // + allocator_, // + device_holder->GetDevice(), // + supports_memoryless_textures_ // + ); if (!source->IsValid()) { return nullptr; } @@ -480,18 +457,10 @@ std::shared_ptr AllocatorVK::OnCreateBuffer( VmaAllocationCreateInfo allocation_info = {}; allocation_info.usage = ToVMAMemoryUsage(); - allocation_info.preferredFlags = ToVKMemoryPropertyFlags(desc.storage_mode); - if (desc.usage_hint == UsageHint::kRasterWorkload) { - allocation_info.flags = ToVmaAllocationCreateFlags( - desc.storage_mode, /*is_texture=*/false, desc.size); - } else { - allocation_info.flags = - VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | - VMA_ALLOCATION_CREATE_MAPPED_BIT; - } - auto image_upload = desc.usage_hint == UsageHint::kImageUpload; - allocation_info.pool = - image_upload ? image_upload_buffer_pool_ : raster_buffer_pool_; + allocation_info.preferredFlags = + ToVKBufferMemoryPropertyFlags(desc.storage_mode); + allocation_info.flags = ToVmaAllocationCreateFlags( + desc.storage_mode, /*is_texture=*/false, desc.size); VkBuffer buffer = {}; VmaAllocation buffer_allocation = {}; diff --git a/impeller/renderer/backend/vulkan/allocator_vk.h b/impeller/renderer/backend/vulkan/allocator_vk.h index 6c8cc4befa101..c453a3b8a33a4 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.h +++ b/impeller/renderer/backend/vulkan/allocator_vk.h @@ -35,6 +35,7 @@ class AllocatorVK final : public Allocator { std::weak_ptr device_holder_; ISize max_texture_size_; bool is_valid_ = false; + bool supports_memoryless_textures_ = false; AllocatorVK(std::weak_ptr context, uint32_t vulkan_api_version, @@ -42,7 +43,8 @@ class AllocatorVK final : public Allocator { const std::shared_ptr& device_holder, const vk::Instance& instance, PFN_vkGetInstanceProcAddr get_instance_proc_address, - PFN_vkGetDeviceProcAddr get_device_proc_address); + PFN_vkGetDeviceProcAddr get_device_proc_address, + const CapabilitiesVK& capabilities); // |Allocator| bool IsValid() const; diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.cc b/impeller/renderer/backend/vulkan/capabilities_vk.cc index 84585b84ec33f..a09c13b568e43 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.cc +++ b/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -348,6 +348,21 @@ bool CapabilitiesVK::SetPhysicalDevice(const vk::PhysicalDevice& device) { .supportedOperations & vk::SubgroupFeatureFlagBits::eArithmetic); + { + // Query texture support. + // TODO(jonahwilliams): + // https://github.com/flutter/flutter/issues/129784 + vk::PhysicalDeviceMemoryProperties memory_properties; + device.getMemoryProperties(&memory_properties); + + for (auto i = 0u; i < memory_properties.memoryTypeCount; i++) { + if (memory_properties.memoryTypes[i].propertyFlags & + vk::MemoryPropertyFlagBits::eLazilyAllocated) { + supports_memoryless_textures_ = true; + } + } + } + // Determine the optional device extensions this physical device supports. { optional_device_extensions_.clear(); @@ -422,6 +437,11 @@ bool CapabilitiesVK::SupportsDecalTileMode() const { return true; } +// |Capabilities| +bool CapabilitiesVK::SupportsMemorylessTextures() const { + return supports_memoryless_textures_; +} + // |Capabilities| PixelFormat CapabilitiesVK::GetDefaultColorFormat() const { return color_format_; diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.h b/impeller/renderer/backend/vulkan/capabilities_vk.h index 98614011206ff..ffa96d46bc98e 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.h +++ b/impeller/renderer/backend/vulkan/capabilities_vk.h @@ -90,6 +90,9 @@ class CapabilitiesVK final : public Capabilities, // |Capabilities| bool SupportsDecalTileMode() const override; + // |Capabilities| + bool SupportsMemorylessTextures() const override; + // |Capabilities| PixelFormat GetDefaultColorFormat() const override; @@ -104,6 +107,7 @@ class CapabilitiesVK final : public Capabilities, PixelFormat depth_stencil_format_ = PixelFormat::kUnknown; vk::PhysicalDeviceProperties device_properties_; bool supports_compute_subgroups_ = false; + bool supports_memoryless_textures_ = false; bool is_valid_ = false; bool HasExtension(const std::string& ext) const; diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index 3af8a62fbbce3..0b1fc69001e33 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -332,7 +332,8 @@ void ContextVK::Setup(Settings settings) { device_holder, // device_holder->instance.get(), // dispatcher.vkGetInstanceProcAddr, // - dispatcher.vkGetDeviceProcAddr // + dispatcher.vkGetDeviceProcAddr, // + *caps // )); if (!allocator->IsValid()) { diff --git a/impeller/renderer/backend/vulkan/device_buffer_vk.cc b/impeller/renderer/backend/vulkan/device_buffer_vk.cc index e88a2cbc13868..8f1911b10d4b7 100644 --- a/impeller/renderer/backend/vulkan/device_buffer_vk.cc +++ b/impeller/renderer/backend/vulkan/device_buffer_vk.cc @@ -4,7 +4,8 @@ #include "impeller/renderer/backend/vulkan/device_buffer_vk.h" -#include "fml/logging.h" +#include "flutter/fml/logging.h" +#include "flutter/fml/trace_event.h" #include "vulkan/vulkan_handles.hpp" namespace impeller { @@ -23,6 +24,7 @@ DeviceBufferVK::DeviceBufferVK(DeviceBufferDescriptor desc, buffer_(buffer) {} DeviceBufferVK::~DeviceBufferVK() { + TRACE_EVENT0("impeller", "DestroyDeviceBuffer"); if (buffer_) { ::vmaDestroyBuffer(allocator_, static_cast(buffer_), @@ -37,6 +39,7 @@ uint8_t* DeviceBufferVK::OnGetContents() const { bool DeviceBufferVK::OnCopyHostBuffer(const uint8_t* source, Range source_range, size_t offset) { + TRACE_EVENT0("impeller", "CopyToDeviceBuffer"); uint8_t* dest = OnGetContents(); if (!dest) { @@ -46,17 +49,10 @@ bool DeviceBufferVK::OnCopyHostBuffer(const uint8_t* source, if (source) { ::memmove(dest + offset, source + source_range.offset, source_range.length); } - // See https://github.com/flutter/flutter/issues/128556 . Some devices do not - // have support for coherent host memory and require an explicit flush. - ::vmaFlushAllocation(allocator_, allocation_, offset, source_range.length); return true; } -void DeviceBufferVK::Flush() { - ::vmaFlushAllocation(allocator_, allocation_, 0, VK_WHOLE_SIZE); -} - bool DeviceBufferVK::SetLabel(const std::string& label) { auto context = context_.lock(); if (!context || !buffer_) { diff --git a/impeller/renderer/backend/vulkan/device_buffer_vk.h b/impeller/renderer/backend/vulkan/device_buffer_vk.h index 25d910beff98f..229a1b6b04325 100644 --- a/impeller/renderer/backend/vulkan/device_buffer_vk.h +++ b/impeller/renderer/backend/vulkan/device_buffer_vk.h @@ -28,11 +28,6 @@ class DeviceBufferVK final : public DeviceBuffer, vk::Buffer GetBuffer() const; - // If the contents of this buffer have been written to with - // `OnGetContents`, then calling flush may be necessary if the memory is - // non-coherent. - void Flush() override; - private: friend class AllocatorVK; diff --git a/impeller/renderer/backend/vulkan/surface_vk.cc b/impeller/renderer/backend/vulkan/surface_vk.cc index 3f1006e331fd6..ab1100664d470 100644 --- a/impeller/renderer/backend/vulkan/surface_vk.cc +++ b/impeller/renderer/backend/vulkan/surface_vk.cc @@ -12,12 +12,18 @@ namespace impeller { std::unique_ptr SurfaceVK::WrapSwapchainImage( const std::shared_ptr& context, - const std::shared_ptr& swapchain_image, + std::shared_ptr& swapchain_image, SwapCallback swap_callback) { if (!context || !swapchain_image || !swap_callback) { return nullptr; } + // Some Vulkan devices may not support memoryless (lazily allocated) textures. + // In this case we will cache the MSAA texture on the swapchain image to avoid + // thrasing the VMA heap. + bool supports_memoryless = + context->GetCapabilities()->SupportsMemorylessTextures(); + TextureDescriptor msaa_tex_desc; msaa_tex_desc.storage_mode = StorageMode::kDeviceTransient; msaa_tex_desc.type = TextureType::kTexture2DMultisample; @@ -26,12 +32,20 @@ std::unique_ptr SurfaceVK::WrapSwapchainImage( msaa_tex_desc.size = swapchain_image->GetSize(); msaa_tex_desc.usage = static_cast(TextureUsage::kRenderTarget); - auto msaa_tex = context->GetResourceAllocator()->CreateTexture(msaa_tex_desc); - if (!msaa_tex) { - VALIDATION_LOG << "Could not allocate MSAA color texture."; - return nullptr; + std::shared_ptr msaa_tex; + if (supports_memoryless || !swapchain_image->HasMSAATexture()) { + msaa_tex = context->GetResourceAllocator()->CreateTexture(msaa_tex_desc); + msaa_tex->SetLabel("ImpellerOnscreenColorMSAA"); + if (!msaa_tex) { + VALIDATION_LOG << "Could not allocate MSAA color texture."; + return nullptr; + } + if (!supports_memoryless) { + swapchain_image->SetMSAATexture(msaa_tex); + } + } else { + msaa_tex = swapchain_image->GetMSAATexture(); } - msaa_tex->SetLabel("ImpellerOnscreenColorMSAA"); TextureDescriptor resolve_tex_desc; resolve_tex_desc.type = TextureType::kTexture2D; diff --git a/impeller/renderer/backend/vulkan/surface_vk.h b/impeller/renderer/backend/vulkan/surface_vk.h index b6824f55cf100..6138a8e44d3c1 100644 --- a/impeller/renderer/backend/vulkan/surface_vk.h +++ b/impeller/renderer/backend/vulkan/surface_vk.h @@ -19,7 +19,7 @@ class SurfaceVK final : public Surface { static std::unique_ptr WrapSwapchainImage( const std::shared_ptr& context, - const std::shared_ptr& swapchain_image, + std::shared_ptr& swapchain_image, SwapCallback swap_callback); // |Surface| diff --git a/impeller/renderer/backend/vulkan/swapchain_image_vk.cc b/impeller/renderer/backend/vulkan/swapchain_image_vk.cc index 392c76b645a9b..dee06c7568e46 100644 --- a/impeller/renderer/backend/vulkan/swapchain_image_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain_image_vk.cc @@ -35,6 +35,18 @@ bool SwapchainImageVK::IsValid() const { return is_valid_; } +std::shared_ptr SwapchainImageVK::GetMSAATexture() const { + return msaa_tex_; +} + +bool SwapchainImageVK::HasMSAATexture() const { + return msaa_tex_ != nullptr; +} + +void SwapchainImageVK::SetMSAATexture(std::shared_ptr msaa_tex) { + msaa_tex_ = std::move(msaa_tex); +} + PixelFormat SwapchainImageVK::GetPixelFormat() const { return desc_.format; } diff --git a/impeller/renderer/backend/vulkan/swapchain_image_vk.h b/impeller/renderer/backend/vulkan/swapchain_image_vk.h index 6cf1943b8729e..115cfa1824bdb 100644 --- a/impeller/renderer/backend/vulkan/swapchain_image_vk.h +++ b/impeller/renderer/backend/vulkan/swapchain_image_vk.h @@ -30,12 +30,19 @@ class SwapchainImageVK final : public TextureSourceVK { // |TextureSourceVK| vk::Image GetImage() const override; + std::shared_ptr GetMSAATexture() const; + + bool HasMSAATexture() const; + // |TextureSourceVK| vk::ImageView GetImageView() const override; + void SetMSAATexture(std::shared_ptr msaa_tex); + private: vk::Image image_ = VK_NULL_HANDLE; vk::UniqueImageView image_view_ = {}; + std::shared_ptr msaa_tex_; bool is_valid_ = false; FML_DISALLOW_COPY_AND_ASSIGN(SwapchainImageVK); diff --git a/impeller/renderer/capabilities.cc b/impeller/renderer/capabilities.cc index 9e2c9201bb603..d0c9f62348066 100644 --- a/impeller/renderer/capabilities.cc +++ b/impeller/renderer/capabilities.cc @@ -76,6 +76,10 @@ class StandardCapabilities final : public Capabilities { return default_stencil_format_; } + bool SupportsMemorylessTextures() const override { + return supports_memoryless_textures_; + } + private: StandardCapabilities(bool has_threading_restrictions, bool supports_offscreen_msaa, @@ -88,6 +92,7 @@ class StandardCapabilities final : public Capabilities { bool supports_read_from_onscreen_texture, bool supports_read_from_resolve, bool supports_decal_tile_mode, + bool supports_memoryless_textures, PixelFormat default_color_format, PixelFormat default_stencil_format) : has_threading_restrictions_(has_threading_restrictions), @@ -102,6 +107,7 @@ class StandardCapabilities final : public Capabilities { supports_read_from_onscreen_texture), supports_read_from_resolve_(supports_read_from_resolve), supports_decal_tile_mode_(supports_decal_tile_mode), + supports_memoryless_textures_(supports_memoryless_textures), default_color_format_(default_color_format), default_stencil_format_(default_stencil_format) {} @@ -118,6 +124,7 @@ class StandardCapabilities final : public Capabilities { bool supports_read_from_onscreen_texture_ = false; bool supports_read_from_resolve_ = false; bool supports_decal_tile_mode_ = false; + bool supports_memoryless_textures_ = false; PixelFormat default_color_format_ = PixelFormat::kUnknown; PixelFormat default_stencil_format_ = PixelFormat::kUnknown; @@ -202,6 +209,12 @@ CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsDecalTileMode(bool value) { return *this; } +CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsMemorylessTextures( + bool value) { + supports_memoryless_textures_ = value; + return *this; +} + std::unique_ptr CapabilitiesBuilder::Build() { return std::unique_ptr(new StandardCapabilities( // has_threading_restrictions_, // @@ -215,6 +228,7 @@ std::unique_ptr CapabilitiesBuilder::Build() { supports_read_from_onscreen_texture_, // supports_read_from_resolve_, // supports_decal_tile_mode_, // + supports_memoryless_textures_, // default_color_format_.value_or(PixelFormat::kUnknown), // default_stencil_format_.value_or(PixelFormat::kUnknown) // )); diff --git a/impeller/renderer/capabilities.h b/impeller/renderer/capabilities.h index 6fb1118dd7c95..87a7f9df08892 100644 --- a/impeller/renderer/capabilities.h +++ b/impeller/renderer/capabilities.h @@ -37,6 +37,8 @@ class Capabilities { virtual bool SupportsDecalTileMode() const = 0; + virtual bool SupportsMemorylessTextures() const = 0; + virtual PixelFormat GetDefaultColorFormat() const = 0; virtual PixelFormat GetDefaultStencilFormat() const = 0; @@ -79,6 +81,8 @@ class CapabilitiesBuilder { CapabilitiesBuilder& SetSupportsDecalTileMode(bool value); + CapabilitiesBuilder& SetSupportsMemorylessTextures(bool value); + std::unique_ptr Build(); private: @@ -93,6 +97,7 @@ class CapabilitiesBuilder { bool supports_read_from_onscreen_texture_ = false; bool supports_read_from_resolve_ = false; bool supports_decal_tile_mode_ = false; + bool supports_memoryless_textures_ = false; std::optional default_color_format_ = std::nullopt; std::optional default_stencil_format_ = std::nullopt; diff --git a/impeller/renderer/capabilities_unittests.cc b/impeller/renderer/capabilities_unittests.cc index 1dc9d17e3c678..9d8a9f386273d 100644 --- a/impeller/renderer/capabilities_unittests.cc +++ b/impeller/renderer/capabilities_unittests.cc @@ -29,6 +29,7 @@ CAPABILITY_TEST(SupportsComputeSubgroups, false); CAPABILITY_TEST(SupportsReadFromOnscreenTexture, false); CAPABILITY_TEST(SupportsReadFromResolve, false); CAPABILITY_TEST(SupportsDecalTileMode, false); +CAPABILITY_TEST(SupportsMemorylessTextures, false); } // namespace testing } // namespace impeller diff --git a/impeller/renderer/command_buffer.h b/impeller/renderer/command_buffer.h index 3a6abacbb2556..c7d167362c300 100644 --- a/impeller/renderer/command_buffer.h +++ b/impeller/renderer/command_buffer.h @@ -18,6 +18,10 @@ class Context; class RenderPass; class RenderTarget; +namespace testing { +class CommandBufferMock; +} + //------------------------------------------------------------------------------ /// @brief A collection of encoded commands to be submitted to the GPU for /// execution. A command buffer is obtained from a graphics @@ -38,6 +42,8 @@ class RenderTarget; /// different from the encoding order. /// class CommandBuffer { + friend class testing::CommandBufferMock; + public: enum class Status { kPending, diff --git a/impeller/renderer/render_pass.h b/impeller/renderer/render_pass.h index a5fac32292f8c..f76531eed84a7 100644 --- a/impeller/renderer/render_pass.h +++ b/impeller/renderer/render_pass.h @@ -57,6 +57,13 @@ class RenderPass { /// bool EncodeCommands() const; + //---------------------------------------------------------------------------- + /// @brief Accessor for the current Commands. + /// + /// @details Visible for testing. + /// + const std::vector& GetCommands() const { return commands_; } + protected: const std::weak_ptr context_; const RenderTarget render_target_; diff --git a/lib/ui/painting/image_decoder_impeller.cc b/lib/ui/painting/image_decoder_impeller.cc index 02a1d7572e796..b553f12ed2190 100644 --- a/lib/ui/painting/image_decoder_impeller.cc +++ b/lib/ui/painting/image_decoder_impeller.cc @@ -208,10 +208,10 @@ DecompressResult ImageDecoderImpeller::DecompressTexture( if (bitmap->dimensions() == target_size) { auto buffer = bitmap_allocator->GetDeviceBuffer(); - if (!buffer.has_value()) { + if (!buffer) { return DecompressResult{.decode_error = "Unable to get device buffer"}; } - return DecompressResult{.device_buffer = buffer.value(), + return DecompressResult{.device_buffer = buffer, .sk_bitmap = bitmap, .image_info = bitmap->info()}; } @@ -240,10 +240,10 @@ DecompressResult ImageDecoderImpeller::DecompressTexture( scaled_bitmap->setImmutable(); auto buffer = scaled_allocator->GetDeviceBuffer(); - if (!buffer.has_value()) { + if (!buffer) { return DecompressResult{.decode_error = "Unable to get device buffer"}; } - return DecompressResult{.device_buffer = buffer.value(), + return DecompressResult{.device_buffer = buffer, .sk_bitmap = scaled_bitmap, .image_info = scaled_bitmap->info()}; } @@ -509,11 +509,8 @@ ImpellerAllocator::ImpellerAllocator( std::shared_ptr allocator) : allocator_(std::move(allocator)) {} -std::optional> -ImpellerAllocator::GetDeviceBuffer() const { - if (buffer_.has_value()) { - buffer_.value()->Flush(); - } +std::shared_ptr ImpellerAllocator::GetDeviceBuffer() + const { return buffer_; } diff --git a/lib/ui/painting/image_decoder_impeller.h b/lib/ui/painting/image_decoder_impeller.h index 595acd652f055..f3e350bd30a37 100644 --- a/lib/ui/painting/image_decoder_impeller.h +++ b/lib/ui/painting/image_decoder_impeller.h @@ -29,12 +29,11 @@ class ImpellerAllocator : public SkBitmap::Allocator { // |Allocator| bool allocPixelRef(SkBitmap* bitmap) override; - std::optional> GetDeviceBuffer() - const; + std::shared_ptr GetDeviceBuffer() const; private: std::shared_ptr allocator_; - std::optional> buffer_; + std::shared_ptr buffer_; }; struct DecompressResult { diff --git a/lib/web_ui/lib/initialization.dart b/lib/web_ui/lib/initialization.dart index bf6b5f299306c..f3f0208a0981a 100644 --- a/lib/web_ui/lib/initialization.dart +++ b/lib/web_ui/lib/initialization.dart @@ -28,89 +28,59 @@ part of ui; /// /// This is only available on the Web, as native Flutter configures the /// environment in the native embedder. +// TODO(mdebbar): Deprecate this and remove it. +// https://github.com/flutter/flutter/issues/127395 Future webOnlyInitializePlatform() async { await engine.initializeEngine(); } -/// Initializes essential bits of the engine before it fully initializes. -/// When [didCreateEngineInitializer] is set, it delegates engine initialization -/// and app startup to the programmer. -/// Else, it immediately triggers the full engine + app bootstrap. -/// -/// This method is called by the flutter_tools package, from the entrypoint that -/// it generates around the main method provided by the programmer. See: -/// * https://github.com/flutter/flutter/blob/2bd3e0d914854aa8c12e933f25c5fd8532ae5571/packages/flutter_tools/lib/src/build_system/targets/web.dart#L135-L163 -/// * https://github.com/flutter/flutter/blob/61fb2de52c7bdac19b7f2f74eaf3f11237e1e91d/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart#L460-L485 -/// -/// This function first calls [engine.initializeEngineServices] so the engine -/// can prepare the js-interop layer that is used by web apps (instead of the -/// old `ui.webOnlyFoo` methods/getters). -/// -/// It then creates a JsObject that is passed to the [didCreateEngineInitializer] -/// JS callback, to delegate bootstrapping the app to the programmer. -/// -/// If said callback is not defined, this assumes that the Flutter Web app is -/// initializing "automatically", as was normal before this feature was -/// introduced. This will immediately run the initEngine and runApp methods -/// (via [engine.AppBootstrap.now]). -/// -/// This is the only bit of `dart:ui` that should be directly called by Flutter -/// web apps. Everything else should go through the JS-interop layer created in -/// `engine.warmup`. -/// -/// This method should NOT trigger the download of any additional resources -/// (except when the app is in "autoStart" mode). +// TODO(mdebbar): Deprecate this and remove it. +// https://github.com/flutter/flutter/issues/127395 Future webOnlyWarmupEngine({ - Function? registerPlugins, - Function? runApp, -}) async { - // Create the object that knows how to bootstrap an app from JS and Dart. - final engine.AppBootstrap bootstrap = engine.AppBootstrap( - initializeEngine: ([engine.JsFlutterConfiguration? configuration]) async { - await engine.initializeEngineServices(jsConfiguration: configuration); - }, runApp: () async { - if (registerPlugins != null) { - registerPlugins(); - } - await engine.initializeEngineUi(); - if (runApp != null) { - runApp(); - } - }, + VoidCallback? registerPlugins, + VoidCallback? runApp, +}) { + assert(() { + engine.printWarning( + 'The webOnlyWarmupEngine API is deprecated and will be removed in a ' + 'future release. Please use `bootstrapEngine` from `dart:ui_web` instead.', + ); + return true; + }()); + return ui_web.bootstrapEngine( + registerPlugins: registerPlugins, + runApp: runApp, ); +} - final engine.FlutterLoader? loader = engine.flutter?.loader; - if (loader == null || loader.isAutoStart) { - // The user does not want control of the app, bootstrap immediately. - engine.domWindow.console.debug('Flutter Web Bootstrap: Auto.'); - await bootstrap.autoStart(); - } else { - // Yield control of the bootstrap procedure to the user. - engine.domWindow.console.debug('Flutter Web Bootstrap: Programmatic.'); - loader.didCreateEngineInitializer(bootstrap.prepareEngineInitializer()); - } +// TODO(mdebbar): Deprecate this and remove it. +// https://github.com/flutter/flutter/issues/127395 +bool get debugEmulateFlutterTesterEnvironment { + assert(() { + engine.printWarning( + 'The debugEmulateFlutterTesterEnvironment getter is deprecated and will ' + 'be removed in a future release. Please use ' + '`debugEmulateFlutterTesterEnvironment` from `dart:ui_web` instead.', + ); + return true; + }()); + return ui_web.debugEmulateFlutterTesterEnvironment; } -/// Emulates the `flutter test` environment. -/// -/// When set to true, the engine will emulate a specific screen size, and always -/// use the "Ahem" font to reduce test flakiness and dependence on the test -/// environment. -bool get debugEmulateFlutterTesterEnvironment => - _debugEmulateFlutterTesterEnvironment; +// TODO(mdebbar): Deprecate this and remove it. +// https://github.com/flutter/flutter/issues/127395 set debugEmulateFlutterTesterEnvironment(bool value) { - _debugEmulateFlutterTesterEnvironment = value; - if (_debugEmulateFlutterTesterEnvironment) { - const Size logicalSize = Size(800.0, 600.0); - engine.window.webOnlyDebugPhysicalSizeOverride = - logicalSize * window.devicePixelRatio; - } - engine.debugDisableFontFallbacks = value; + assert(() { + engine.printWarning( + 'The debugEmulateFlutterTesterEnvironment setter is deprecated and will ' + 'be removed in a future release. Please use ' + '`debugEmulateFlutterTesterEnvironment` from `dart:ui_web` instead.', + ); + return true; + }()); + ui_web.debugEmulateFlutterTesterEnvironment = value; } -bool _debugEmulateFlutterTesterEnvironment = false; - -/// Provides the asset manager. // TODO(mdebbar): Deprecate this and remove it. // https://github.com/flutter/flutter/issues/127395 ui_web.AssetManager get webOnlyAssetManager { @@ -124,12 +94,17 @@ ui_web.AssetManager get webOnlyAssetManager { return ui_web.assetManager; } -/// Sets the handler that forwards platform messages to web plugins. -/// -/// This function exists because unlike mobile, on the web plugins are also -/// implemented using Dart code, and that code needs a way to receive messages. -void webOnlySetPluginHandler(Future Function(String, ByteData?, PlatformMessageResponseCallback?) handler) { - engine.pluginMessageCallHandler = handler; +// TODO(mdebbar): Deprecate this and remove it. +// https://github.com/flutter/flutter/issues/127395 +void webOnlySetPluginHandler(PlatformMessageCallback handler) { + assert(() { + engine.printWarning( + 'The webOnlySetPluginHandler API is deprecated and will be removed in a ' + 'future release. Please use `setPluginHandler` from `dart:ui_web` instead.', + ); + return true; + }()); + ui_web.setPluginHandler(handler); } // TODO(mdebbar): Deprecate this and remove it. diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart index bd626064b580c..826c4cc8e735b 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -3596,7 +3596,8 @@ Future _downloadOneOf(Iterable urls) async { /// Returns a [Future] that completes with `true` if the CanvasKit JavaScript /// file was successfully downloaded, or `false` if it failed. Future _downloadCanvasKitJs(String url) { - final DomHTMLScriptElement canvasKitScript = createDomHTMLScriptElement(); + final DomHTMLScriptElement canvasKitScript = + createDomHTMLScriptElement(configuration.nonce); canvasKitScript.src = createTrustedScriptUrl(url); final Completer canvasKitLoadCompleter = Completer(); diff --git a/lib/web_ui/lib/src/engine/canvaskit/text.dart b/lib/web_ui/lib/src/engine/canvaskit/text.dart index f177031d6afcc..6fe5a29a48db3 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/text.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/text.dart @@ -7,12 +7,13 @@ import 'dart:typed_data'; import 'package:meta/meta.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; final bool _ckRequiresClientICU = canvasKit.ParagraphBuilder.RequiresClientICU(); final List _testFonts = ['FlutterTest', 'Ahem']; String? _effectiveFontFamily(String? fontFamily) { - return ui.debugEmulateFlutterTesterEnvironment && !_testFonts.contains(fontFamily) + return ui_web.debugEmulateFlutterTesterEnvironment && !_testFonts.contains(fontFamily) ? _testFonts.first : fontFamily; } @@ -231,7 +232,7 @@ class CkTextStyle implements ui.TextStyle { fontStyle, textBaseline, _effectiveFontFamily(fontFamily), - ui.debugEmulateFlutterTesterEnvironment ? null : fontFamilyFallback, + ui_web.debugEmulateFlutterTesterEnvironment ? null : fontFamilyFallback, fontSize, letterSpacing, wordSpacing, @@ -481,7 +482,7 @@ class CkStrutStyle implements ui.StrutStyle { ui.FontStyle? fontStyle, bool? forceStrutHeight, }) : _fontFamily = _effectiveFontFamily(fontFamily), - _fontFamilyFallback = ui.debugEmulateFlutterTesterEnvironment ? null : fontFamilyFallback, + _fontFamilyFallback = ui_web.debugEmulateFlutterTesterEnvironment ? null : fontFamilyFallback, _fontSize = fontSize, _height = height, _leadingDistribution = leadingDistribution, diff --git a/lib/web_ui/lib/src/engine/configuration.dart b/lib/web_ui/lib/src/engine/configuration.dart index 62b05c7a4fc0f..022dee08b97fb 100644 --- a/lib/web_ui/lib/src/engine/configuration.dart +++ b/lib/web_ui/lib/src/engine/configuration.dart @@ -269,6 +269,11 @@ class FlutterConfiguration { /// to render, or `null` if the user hasn't specified anything. DomElement? get hostElement => _configuration?.hostElement; + /// Returns a `nonce` to allowlist the inline styles that Flutter web needs. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce + String? get nonce => _configuration?.nonce; + /// Returns the [requestedRendererType] to be used with the current Flutter /// application, normally 'canvaskit' or 'auto'. /// @@ -320,6 +325,10 @@ extension JsFlutterConfigurationExtension on JsFlutterConfiguration { external DomElement? get hostElement; + @JS('nonce') + external JSString? get _nonce; + String? get nonce => _nonce?.toDart; + @JS('renderer') external JSString? get _renderer; String? get renderer => _renderer?.toDart; diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index 583ab2736fe0d..0b24dc5a8d45a 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -929,10 +929,20 @@ extension DomHTMLScriptElementExtension on DomHTMLScriptElement { external set _src(JSAny value); set src(Object /* String|TrustedScriptURL */ value) => _src = value.toJSAnyShallow; + + @JS('nonce') + external set _nonce(JSString? value); + set nonce(String? value) => _nonce = value?.toJS; } -DomHTMLScriptElement createDomHTMLScriptElement() => - domDocument.createElement('script') as DomHTMLScriptElement; +DomHTMLScriptElement createDomHTMLScriptElement(String? nonce) { + final DomHTMLScriptElement script = + domDocument.createElement('script') as DomHTMLScriptElement; + if (nonce != null) { + script.nonce = nonce; + } + return script; +} @JS() @staticInterop @@ -971,11 +981,25 @@ extension DomHTMLStyleElementExtension on DomHTMLStyleElement { external set _type(JSString? value); set type(String? value) => _type = value?.toJS; + @JS('nonce') + external set _nonce(JSString? value); + set nonce(String? value) => _nonce = value?.toJS; + + @JS('nonce') + external JSString? get _nonce; + String? get nonce => _nonce?.toDart; + external DomStyleSheet? get sheet; } -DomHTMLStyleElement createDomHTMLStyleElement() => - domDocument.createElement('style') as DomHTMLStyleElement; +DomHTMLStyleElement createDomHTMLStyleElement(String? nonce) { + final DomHTMLStyleElement style = + domDocument.createElement('style') as DomHTMLStyleElement; + if (nonce != null) { + style.nonce = nonce; + } + return style; +} @JS() @staticInterop diff --git a/lib/web_ui/lib/src/engine/embedder.dart b/lib/web_ui/lib/src/engine/embedder.dart index e949fdd0d2efd..623d6aa9bdd1c 100644 --- a/lib/web_ui/lib/src/engine/embedder.dart +++ b/lib/web_ui/lib/src/engine/embedder.dart @@ -188,7 +188,7 @@ class FlutterViewEmbedder { }); _glassPaneShadow = shadowRoot; - final DomHTMLStyleElement shadowRootStyleElement = createDomHTMLStyleElement(); + final DomHTMLStyleElement shadowRootStyleElement = createDomHTMLStyleElement(configuration.nonce); shadowRootStyleElement.id = 'flt-internals-stylesheet'; // The shadowRootStyleElement must be appended to the DOM, or its `sheet` will be null later. shadowRoot.appendChild(shadowRootStyleElement); @@ -198,7 +198,7 @@ class FlutterViewEmbedder { ); _textEditingHostNode = - createTextEditingHostNode(flutterViewElement, defaultCssFont); + createTextEditingHostNode(flutterViewElement, defaultCssFont, configuration.nonce); // Don't allow the scene to receive pointer events. _sceneHostElement = domDocument.createElement('flt-scene-host') @@ -434,10 +434,10 @@ FlutterViewEmbedder ensureFlutterViewEmbedderInitialized() => /// Creates a node to host text editing elements and applies a stylesheet /// to Flutter nodes that exist outside of the shadowDOM. -DomElement createTextEditingHostNode(DomElement root, String defaultFont) { +DomElement createTextEditingHostNode(DomElement root, String defaultFont, String? nonce) { final DomElement domElement = domDocument.createElement('flt-text-editing-host'); - final DomHTMLStyleElement styleElement = createDomHTMLStyleElement(); + final DomHTMLStyleElement styleElement = createDomHTMLStyleElement(nonce); styleElement.id = 'flt-text-editing-stylesheet'; root.appendChild(styleElement); diff --git a/lib/web_ui/lib/src/engine/html/scene_builder.dart b/lib/web_ui/lib/src/engine/html/scene_builder.dart index d8e8bb3d24586..e77e7d47928f9 100644 --- a/lib/web_ui/lib/src/engine/html/scene_builder.dart +++ b/lib/web_ui/lib/src/engine/html/scene_builder.dart @@ -5,6 +5,7 @@ import 'dart:typed_data'; import 'package:ui/ui.dart' as ui; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import '../../engine.dart' show kProfileApplyFrame, kProfilePrerollFrame; import '../dom.dart'; @@ -111,7 +112,7 @@ class SurfaceSceneBuilder implements ui.SceneBuilder { // Top level transform contains view configuration to scale // scene to devicepixelratio. Use identity instead since CSS uses // logical device pixels. - if (!ui.debugEmulateFlutterTesterEnvironment) { + if (!ui_web.debugEmulateFlutterTesterEnvironment) { assert(matrix4[0] == window.devicePixelRatio && matrix4[5] == window.devicePixelRatio); } @@ -383,7 +384,7 @@ class SurfaceSceneBuilder implements ui.SceneBuilder { void _addTexture(double dx, double dy, double width, double height, int textureId, ui.FilterQuality filterQuality) { // In test mode, allow this to be a no-op. - if (!ui.debugEmulateFlutterTesterEnvironment) { + if (!ui_web.debugEmulateFlutterTesterEnvironment) { throw UnimplementedError('Textures are not supported in Flutter Web'); } } diff --git a/lib/web_ui/lib/src/engine/initialization.dart b/lib/web_ui/lib/src/engine/initialization.dart index 7d265c424c17b..94340b6d22c7f 100644 --- a/lib/web_ui/lib/src/engine/initialization.dart +++ b/lib/web_ui/lib/src/engine/initialization.dart @@ -244,7 +244,7 @@ void _setAssetManager(ui_web.AssetManager assetManager) { Future _downloadAssetFonts() async { renderer.fontCollection.clear(); - if (ui.debugEmulateFlutterTesterEnvironment) { + if (ui_web.debugEmulateFlutterTesterEnvironment) { // Load the embedded test font before loading fonts from the assets so that // the embedded test font is the default (first) font. await renderer.fontCollection.loadFontFromList( diff --git a/lib/web_ui/lib/src/engine/platform_dispatcher.dart b/lib/web_ui/lib/src/engine/platform_dispatcher.dart index 40b8a0ed4faab..4a42c98838709 100644 --- a/lib/web_ui/lib/src/engine/platform_dispatcher.dart +++ b/lib/web_ui/lib/src/engine/platform_dispatcher.dart @@ -472,7 +472,7 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { // In widget tests we want to bypass processing of platform messages. bool returnImmediately = false; assert(() { - if (ui.debugEmulateFlutterTesterEnvironment) { + if (ui_web.debugEmulateFlutterTesterEnvironment) { returnImmediately = true; } return true; diff --git a/lib/web_ui/lib/src/engine/plugins.dart b/lib/web_ui/lib/src/engine/plugins.dart index 083816b1c29d3..151935f9fd491 100644 --- a/lib/web_ui/lib/src/engine/plugins.dart +++ b/lib/web_ui/lib/src/engine/plugins.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:typed_data'; - import 'package:ui/ui.dart' as ui; -Future Function(String, ByteData?, ui.PlatformMessageResponseCallback?)? pluginMessageCallHandler; +ui.PlatformMessageCallback? pluginMessageCallHandler; diff --git a/lib/web_ui/lib/src/engine/semantics/semantics.dart b/lib/web_ui/lib/src/engine/semantics/semantics.dart index c1f99639aafd4..8e3971b6dfc1b 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -7,6 +7,7 @@ import 'dart:typed_data'; import 'package:meta/meta.dart'; import 'package:ui/ui.dart' as ui; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import '../../engine.dart' show registerHotRestartListener; import '../alarm_clock.dart'; @@ -2116,7 +2117,7 @@ class EngineSemanticsOwner { /// Updates the semantics tree from data in the [uiUpdate]. void updateSemantics(ui.SemanticsUpdate uiUpdate) { if (!_semanticsEnabled) { - if (ui.debugEmulateFlutterTesterEnvironment) { + if (ui_web.debugEmulateFlutterTesterEnvironment) { // Running Flutter widget tests in a fake environment. Don't enable // engine semantics. Test semantics trees violate invariants in ways // production implementation isn't built to handle. For example, tests diff --git a/lib/web_ui/lib/src/engine/text/paragraph.dart b/lib/web_ui/lib/src/engine/text/paragraph.dart index 5e17a5a5b5b10..a6ccc5c4adad8 100644 --- a/lib/web_ui/lib/src/engine/text/paragraph.dart +++ b/lib/web_ui/lib/src/engine/text/paragraph.dart @@ -5,6 +5,7 @@ import 'dart:math' as math; import 'package:ui/ui.dart' as ui; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import '../browser_detection.dart'; import '../dom.dart'; @@ -473,7 +474,7 @@ class EngineTextStyle implements ui.TextStyle { // This makes widget tests predictable and less flaky. String result = fontFamily; assert(() { - if (ui.debugEmulateFlutterTesterEnvironment && !_testFonts.contains(fontFamily)) { + if (ui_web.debugEmulateFlutterTesterEnvironment && !_testFonts.contains(fontFamily)) { result = _testFonts.first; } return true; @@ -820,7 +821,7 @@ void applyTextStyleToElement({ } // For test environment use effectiveFontFamily since we need to // consistently use the correct test font. - if (ui.debugEmulateFlutterTesterEnvironment) { + if (ui_web.debugEmulateFlutterTesterEnvironment) { cssStyle.fontFamily = canonicalizeFontFamily(style.effectiveFontFamily)!; } else { cssStyle.fontFamily = canonicalizeFontFamily(style.fontFamily)!; diff --git a/lib/web_ui/lib/src/engine/text/ruler.dart b/lib/web_ui/lib/src/engine/text/ruler.dart index 23c1cb0644459..c3032705fb551 100644 --- a/lib/web_ui/lib/src/engine/text/ruler.dart +++ b/lib/web_ui/lib/src/engine/text/ruler.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:ui/ui.dart' as ui; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import '../browser_detection.dart'; import '../dom.dart'; @@ -144,7 +145,7 @@ class TextDimensions { if (browserEngine == BrowserEngine.firefox && // In the flutter tester environment, we use a predictable-size for font // measurement tests. - !ui.debugEmulateFlutterTesterEnvironment) { + !ui_web.debugEmulateFlutterTesterEnvironment) { // See subpixel rounding bug : // https://bugzilla.mozilla.org/show_bug.cgi?id=442139 // This causes bottom of letters such as 'y' to be cutoff and diff --git a/lib/web_ui/lib/ui_web/src/ui_web.dart b/lib/web_ui/lib/ui_web/src/ui_web.dart index 7327584344738..f8d21ca37768d 100644 --- a/lib/web_ui/lib/ui_web/src/ui_web.dart +++ b/lib/web_ui/lib/ui_web/src/ui_web.dart @@ -9,6 +9,9 @@ library ui_web; export 'ui_web/asset_manager.dart'; +export 'ui_web/initialization.dart'; export 'ui_web/navigation/platform_location.dart'; export 'ui_web/navigation/url_strategy.dart'; export 'ui_web/platform_view_registry.dart'; +export 'ui_web/plugins.dart'; +export 'ui_web/testing.dart'; diff --git a/lib/web_ui/lib/ui_web/src/ui_web/initialization.dart b/lib/web_ui/lib/ui_web/src/ui_web/initialization.dart new file mode 100644 index 0000000000000..5411f01d21798 --- /dev/null +++ b/lib/web_ui/lib/ui_web/src/ui_web/initialization.dart @@ -0,0 +1,57 @@ +// 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. + +import 'package:ui/src/engine.dart'; +import 'package:ui/ui.dart' as ui; + +/// Bootstraps the Flutter Web engine and app. +/// +/// If the app uses plugins, then the [registerPlugins] callback can be provided +/// to register those plugins. This is done typically by calling +/// `registerPlugins` from the auto-generated `web_plugin_registrant.dart` file. +/// +/// The [runApp] callback is invoked to run the app after the engine is fully +/// initialized. +/// +/// For more information, see what the `flutter_tools` does in the entrypoint +/// that it generates around the app's main method: +/// +/// * https://github.com/flutter/flutter/blob/95be76ab7e3dca2def54454313e97f94f4ac4582/packages/flutter_tools/lib/src/web/file_generators/main_dart.dart#L14-L43 +/// +/// By default, engine initialization and app startup occur immediately and back +/// to back. They can be programmatically controlled by setting +/// `FlutterLoader.didCreateEngineInitializer`. For more information, see how +/// `flutter.js` does it: +/// +/// * https://github.com/flutter/flutter/blob/95be76ab7e3dca2def54454313e97f94f4ac4582/packages/flutter_tools/lib/src/web/file_generators/js/flutter.js +Future bootstrapEngine({ + ui.VoidCallback? registerPlugins, + ui.VoidCallback? runApp, +}) async { + // Create the object that knows how to bootstrap an app from JS and Dart. + final AppBootstrap bootstrap = AppBootstrap( + initializeEngine: ([JsFlutterConfiguration? configuration]) async { + await initializeEngineServices(jsConfiguration: configuration); + }, runApp: () async { + if (registerPlugins != null) { + registerPlugins(); + } + await initializeEngineUi(); + if (runApp != null) { + runApp(); + } + }, + ); + + final FlutterLoader? loader = flutter?.loader; + if (loader == null || loader.isAutoStart) { + // The user does not want control of the app, bootstrap immediately. + domWindow.console.debug('Flutter Web Bootstrap: Auto.'); + await bootstrap.autoStart(); + } else { + // Yield control of the bootstrap procedure to the user. + domWindow.console.debug('Flutter Web Bootstrap: Programmatic.'); + loader.didCreateEngineInitializer(bootstrap.prepareEngineInitializer()); + } +} diff --git a/lib/web_ui/lib/ui_web/src/ui_web/navigation/url_strategy.dart b/lib/web_ui/lib/ui_web/src/ui_web/navigation/url_strategy.dart index 7932221eb331c..9760f005bf92f 100644 --- a/lib/web_ui/lib/ui_web/src/ui_web/navigation/url_strategy.dart +++ b/lib/web_ui/lib/ui_web/src/ui_web/navigation/url_strategy.dart @@ -8,9 +8,10 @@ import 'package:meta/meta.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import '../testing.dart'; import 'platform_location.dart'; -UrlStrategy _realDefaultUrlStrategy = ui.debugEmulateFlutterTesterEnvironment +UrlStrategy _realDefaultUrlStrategy = debugEmulateFlutterTesterEnvironment ? TestUrlStrategy.fromEntry(const TestHistoryEntry('default', null, '/')) : const HashUrlStrategy(); diff --git a/lib/web_ui/lib/ui_web/src/ui_web/plugins.dart b/lib/web_ui/lib/ui_web/src/ui_web/plugins.dart new file mode 100644 index 0000000000000..c3a5dcc45ba46 --- /dev/null +++ b/lib/web_ui/lib/ui_web/src/ui_web/plugins.dart @@ -0,0 +1,14 @@ +// 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. + +import 'package:ui/src/engine.dart'; +import 'package:ui/ui.dart' as ui; + +/// Sets the handler that forwards platform messages to web plugins. +/// +/// This function exists because unlike mobile, on the web plugins are also +/// implemented using Dart code, and that code needs a way to receive messages. +void setPluginHandler(ui.PlatformMessageCallback handler) { + pluginMessageCallHandler = handler; +} diff --git a/lib/web_ui/lib/ui_web/src/ui_web/testing.dart b/lib/web_ui/lib/ui_web/src/ui_web/testing.dart new file mode 100644 index 0000000000000..ae5b6e88e34e7 --- /dev/null +++ b/lib/web_ui/lib/ui_web/src/ui_web/testing.dart @@ -0,0 +1,27 @@ +// 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. + +import 'package:ui/src/engine.dart'; +import 'package:ui/ui.dart' as ui; + +/// Whether the Flutter engine is running in `flutter test` emulation mode. +/// +/// When true, the engine will emulate a specific screen size, and always +/// use the "Ahem" font to reduce test flakiness and dependence on the test +/// environment. +bool get debugEmulateFlutterTesterEnvironment => + _debugEmulateFlutterTesterEnvironment; + +/// Sets whether the Flutter engine is running in `flutter test` emulation mode. +set debugEmulateFlutterTesterEnvironment(bool value) { + _debugEmulateFlutterTesterEnvironment = value; + if (_debugEmulateFlutterTesterEnvironment) { + const ui.Size logicalSize = ui.Size(800.0, 600.0); + window.webOnlyDebugPhysicalSizeOverride = + logicalSize * window.devicePixelRatio; + } + debugDisableFontFallbacks = value; +} + +bool _debugEmulateFlutterTesterEnvironment = false; diff --git a/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart b/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart index 81a2c340ff7b3..d26c8dda16d9a 100644 --- a/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart +++ b/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart @@ -6,6 +6,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import 'common.dart'; @@ -16,7 +17,7 @@ void main() { const ui.Rect kDefaultRegion = ui.Rect.fromLTRB(0, 0, 500, 250); void testMain() { - ui.debugEmulateFlutterTesterEnvironment = true; + ui_web.debugEmulateFlutterTesterEnvironment = true; group('flutter_tester emulation', () { setUpCanvasKitTest(); diff --git a/lib/web_ui/test/canvaskit/fragment_program_test.dart b/lib/web_ui/test/canvaskit/fragment_program_test.dart index f0ef8c66c0de1..1907093f5a75c 100644 --- a/lib/web_ui/test/canvaskit/fragment_program_test.dart +++ b/lib/web_ui/test/canvaskit/fragment_program_test.dart @@ -186,7 +186,7 @@ void testMain() { }); test('FragmentProgram can be created from JSON IPLR bundle', () { - final Uint8List data = utf8.encode(kJsonIPLR) as Uint8List; + final Uint8List data = const Utf8Encoder().convert(kJsonIPLR); final CkFragmentProgram program = CkFragmentProgram.fromBytes('test', data); expect(program.effect, isNotNull); diff --git a/lib/web_ui/test/canvaskit/text_test.dart b/lib/web_ui/test/canvaskit/text_test.dart index d14ad7b75e83d..8d4af676480fe 100644 --- a/lib/web_ui/test/canvaskit/text_test.dart +++ b/lib/web_ui/test/canvaskit/text_test.dart @@ -6,6 +6,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import 'common.dart'; @@ -94,9 +95,9 @@ void testMain() { }); group('test fonts in flutterTester environment', () { - final bool resetValue = ui.debugEmulateFlutterTesterEnvironment; - ui.debugEmulateFlutterTesterEnvironment = true; - tearDownAll(() => ui.debugEmulateFlutterTesterEnvironment = resetValue); + final bool resetValue = ui_web.debugEmulateFlutterTesterEnvironment; + ui_web.debugEmulateFlutterTesterEnvironment = true; + tearDownAll(() => ui_web.debugEmulateFlutterTesterEnvironment = resetValue); const List testFonts = ['FlutterTest', 'Ahem']; test('The default test font is used when a non-test fontFamily is specified', () { diff --git a/lib/web_ui/test/common/test_initialization.dart b/lib/web_ui/test/common/test_initialization.dart index 427d47dcd3b02..2b1124ea1e4fe 100644 --- a/lib/web_ui/test/common/test_initialization.dart +++ b/lib/web_ui/test/common/test_initialization.dart @@ -7,6 +7,7 @@ import 'dart:js_util' as js_util; import 'package:test/test.dart'; import 'package:ui/src/engine.dart' as engine; import 'package:ui/ui.dart' as ui; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import 'fake_asset_manager.dart'; @@ -17,7 +18,7 @@ void setUpUnitTests({ late final FakeAssetScope debugFontsScope; setUpAll(() async { if (emulateTesterEnvironment) { - ui.debugEmulateFlutterTesterEnvironment = true; + ui_web.debugEmulateFlutterTesterEnvironment = true; } // Some of our tests rely on color emoji diff --git a/lib/web_ui/test/engine/channel_buffers_test.dart b/lib/web_ui/test/engine/channel_buffers_test.dart index 6fc91100aec92..2cd8cd2baa7d4 100644 --- a/lib/web_ui/test/engine/channel_buffers_test.dart +++ b/lib/web_ui/test/engine/channel_buffers_test.dart @@ -23,7 +23,7 @@ void main() { } ByteData _makeByteData(String str) { - final Uint8List list = utf8.encode(str) as Uint8List; + final Uint8List list = const Utf8Encoder().convert(str); final ByteBuffer buffer = list.buffer; return ByteData.view(buffer); } diff --git a/lib/web_ui/test/engine/dom_http_fetch_test.dart b/lib/web_ui/test/engine/dom_http_fetch_test.dart index 606753ba4636b..2433d67058cb6 100644 --- a/lib/web_ui/test/engine/dom_http_fetch_test.dart +++ b/lib/web_ui/test/engine/dom_http_fetch_test.dart @@ -8,7 +8,6 @@ import 'dart:typed_data'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; - import 'package:ui/ui.dart' as ui; void main() { diff --git a/lib/web_ui/test/engine/global_styles_test.dart b/lib/web_ui/test/engine/global_styles_test.dart index bfdcc31b1811a..ec801bd94839d 100644 --- a/lib/web_ui/test/engine/global_styles_test.dart +++ b/lib/web_ui/test/engine/global_styles_test.dart @@ -16,17 +16,25 @@ void testMain() { late DomHTMLStyleElement styleElement; setUp(() { - styleElement = createDomHTMLStyleElement(); + styleElement = createDomHTMLStyleElement(null); domDocument.body!.append(styleElement); applyGlobalCssRulesToSheet( styleElement, defaultCssFont: _kDefaultCssFont, ); }); + tearDown(() { styleElement.remove(); }); + test('createDomHTMLStyleElement sets a nonce value, when passed', () { + expect(styleElement.nonce, isEmpty); + + final DomHTMLStyleElement style = createDomHTMLStyleElement('a-nonce-value'); + expect(style.nonce, 'a-nonce-value'); + }); + test('(Self-test) hasCssRule can extract rules', () { final bool hasRule = hasCssRule(styleElement, selector: '.flt-text-editing::placeholder', declaration: 'opacity: 0'); diff --git a/lib/web_ui/test/engine/initialization_test.dart b/lib/web_ui/test/engine/initialization_test.dart index 2a10f1bc507d9..0068628b88d66 100644 --- a/lib/web_ui/test/engine/initialization_test.dart +++ b/lib/web_ui/test/engine/initialization_test.dart @@ -8,7 +8,7 @@ import 'package:js/js_util.dart' as js_util; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart' as engine; -import 'package:ui/ui.dart' as ui; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; @JS('_flutter') external set _loader(JSAny? loader); @@ -28,7 +28,7 @@ void main() { } void testMain() { - test('webOnlyWarmupEngine calls _flutter.loader.didCreateEngineInitializer callback', () async { + test('bootstrapEngine calls _flutter.loader.didCreateEngineInitializer callback', () async { Object? engineInitializer; void didCreateEngineInitializerMock(Object? obj) { @@ -41,7 +41,7 @@ void testMain() { // Reset the engine engine.debugResetEngineInitializationState(); - await ui.webOnlyWarmupEngine( + await ui_web.bootstrapEngine( registerPlugins: () {}, runApp: () {}, ); @@ -52,7 +52,7 @@ void testMain() { expect(js_util.hasProperty(engineInitializer!, 'autoStart'), isTrue, reason: 'Missing FlutterEngineInitializer method: autoStart.'); }); - test('webOnlyWarmupEngine does auto-start when _flutter.loader.didCreateEngineInitializer does not exist', () async { + test('bootstrapEngine does auto-start when _flutter.loader.didCreateEngineInitializer does not exist', () async { loader = null; bool pluginsRegistered = false; @@ -67,7 +67,7 @@ void testMain() { // Reset the engine engine.debugResetEngineInitializationState(); - await ui.webOnlyWarmupEngine( + await ui_web.bootstrapEngine( registerPlugins: registerPluginsMock, runApp: runAppMock, ); diff --git a/lib/web_ui/test/engine/platform_dispatcher/application_switcher_description_test.dart b/lib/web_ui/test/engine/platform_dispatcher/application_switcher_description_test.dart index 1dd6902e6aa88..140f990f354b0 100644 --- a/lib/web_ui/test/engine/platform_dispatcher/application_switcher_description_test.dart +++ b/lib/web_ui/test/engine/platform_dispatcher/application_switcher_description_test.dart @@ -6,6 +6,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; void main() { internalBootstrapBrowserTest(() => testMain); @@ -25,7 +26,7 @@ Future testMain() async { group('Title and Primary Color/Theme meta', () { test('is set on the document by platform message', () { // Run the unit test without emulating Flutter tester environment. - ui.debugEmulateFlutterTesterEnvironment = false; + ui_web.debugEmulateFlutterTesterEnvironment = false; // TODO(yjbanov): https://github.com/flutter/flutter/issues/39159 domDocument.title = ''; @@ -69,7 +70,7 @@ Future testMain() async { test('supports null title and primaryColor', () { // Run the unit test without emulating Flutter tester environment. - ui.debugEmulateFlutterTesterEnvironment = false; + ui_web.debugEmulateFlutterTesterEnvironment = false; const ui.Color expectedNullColor = ui.Color(0xFF000000); // TODO(yjbanov): https://github.com/flutter/flutter/issues/39159 diff --git a/lib/web_ui/test/engine/platform_dispatcher/system_ui_overlay_style_test.dart b/lib/web_ui/test/engine/platform_dispatcher/system_ui_overlay_style_test.dart index 8e040bfc43828..25e248d66aa8e 100644 --- a/lib/web_ui/test/engine/platform_dispatcher/system_ui_overlay_style_test.dart +++ b/lib/web_ui/test/engine/platform_dispatcher/system_ui_overlay_style_test.dart @@ -6,6 +6,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; void main() { internalBootstrapBrowserTest(() => testMain); @@ -38,7 +39,7 @@ void testMain() { group('SystemUIOverlayStyle', () { test('theme color is set / removed by platform message', () { // Run the unit test without emulating Flutter tester environment. - ui.debugEmulateFlutterTesterEnvironment = false; + ui_web.debugEmulateFlutterTesterEnvironment = false; expect(getCssThemeColor(), null); diff --git a/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart b/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart index a3bfcca3e633c..6c6de54d98300 100644 --- a/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart +++ b/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart @@ -11,6 +11,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import 'package:web_engine_tester/golden_tester.dart'; @@ -318,7 +319,7 @@ Future testMain() async { // Cyan text should be above everything. test('Paints text above and below image', () async { // Use a non-Ahem font so that text is visible. - debugEmulateFlutterTesterEnvironment = false; + ui_web.debugEmulateFlutterTesterEnvironment = false; final RecordingCanvas rc = RecordingCanvas(const Rect.fromLTRB(0, 0, 400, 300)); rc.save(); diff --git a/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart b/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart index 5fc4142f0dc02..6342f6d87de1c 100644 --- a/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart +++ b/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart @@ -6,6 +6,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import '../../common/test_initialization.dart'; import '../paragraph/helper.dart'; @@ -414,7 +415,7 @@ Future testMain() async { // Paragraphs and spans force the FlutterTest font in test mode. We need to // trick them into thinking they are not in test mode, so they use the // provided font family. - debugEmulateFlutterTesterEnvironment = false; + ui_web.debugEmulateFlutterTesterEnvironment = false; final EngineParagraphStyle style = EngineParagraphStyle(fontSize: 12.0, fontFamily: 'first'); final CanvasParagraphBuilder builder = CanvasParagraphBuilder(style); @@ -454,7 +455,7 @@ Future testMain() async { // measurements. ignorePositions: true, ); - debugEmulateFlutterTesterEnvironment = true; + ui_web.debugEmulateFlutterTesterEnvironment = true; }); // Regression test for https://github.com/flutter/flutter/issues/108431. diff --git a/lib/web_ui/test/html/text/layout_service_plain_test.dart b/lib/web_ui/test/html/text/layout_service_plain_test.dart index d08d88b15e493..affdae3bd8f91 100644 --- a/lib/web_ui/test/html/text/layout_service_plain_test.dart +++ b/lib/web_ui/test/html/text/layout_service_plain_test.dart @@ -6,6 +6,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import '../../common/test_initialization.dart'; import '../paragraph/helper.dart'; @@ -714,7 +715,7 @@ Future testMain() async { test('does not leak styles across spanometers', () { // This prevents the Ahem font from being forced in all paragraphs. - ui.debugEmulateFlutterTesterEnvironment = false; + ui_web.debugEmulateFlutterTesterEnvironment = false; final CanvasParagraph p1 = plain( EngineParagraphStyle( @@ -750,6 +751,6 @@ Future testMain() async { expect(textContext.font, contains('40px')); expect(textContext.font, contains('FontFamily2')); - ui.debugEmulateFlutterTesterEnvironment = true; + ui_web.debugEmulateFlutterTesterEnvironment = true; }); } diff --git a/lib/web_ui/test/html/text_test.dart b/lib/web_ui/test/html/text_test.dart index 72a624a6335c0..4bb45956812d3 100644 --- a/lib/web_ui/test/html/text_test.dart +++ b/lib/web_ui/test/html/text_test.dart @@ -9,6 +9,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import '../common/matchers.dart'; import '../common/test_initialization.dart'; @@ -236,7 +237,7 @@ Future testMain() async { test('adds Arial and sans-serif as fallback fonts', () { // Set this to false so it doesn't default to the test font. - debugEmulateFlutterTesterEnvironment = false; + ui_web.debugEmulateFlutterTesterEnvironment = false; final CanvasParagraph paragraph = plain(EngineParagraphStyle( fontFamily: 'SomeFont', @@ -247,14 +248,14 @@ Future testMain() async { expect(paragraph.toDomElement().children.single.style.fontFamily, 'SomeFont, $fallback, sans-serif'); - debugEmulateFlutterTesterEnvironment = true; + ui_web.debugEmulateFlutterTesterEnvironment = true; }, // TODO(mdebbar): https://github.com/flutter/flutter/issues/46638 skip: browserEngine == BrowserEngine.firefox); test('does not add fallback fonts to generic families', () { // Set this to false so it doesn't default to the default test font. - debugEmulateFlutterTesterEnvironment = false; + ui_web.debugEmulateFlutterTesterEnvironment = false; final CanvasParagraph paragraph = plain(EngineParagraphStyle( fontFamily: 'serif', @@ -264,12 +265,12 @@ Future testMain() async { paragraph.layout(constrain(double.infinity)); expect(paragraph.toDomElement().children.single.style.fontFamily, 'serif'); - debugEmulateFlutterTesterEnvironment = true; + ui_web.debugEmulateFlutterTesterEnvironment = true; }); test('can set font families that need to be quoted', () { // Set this to false so it doesn't default to the default test font. - debugEmulateFlutterTesterEnvironment = false; + ui_web.debugEmulateFlutterTesterEnvironment = false; final CanvasParagraph paragraph = plain(EngineParagraphStyle( fontFamily: 'MyFont 2000', @@ -280,7 +281,7 @@ Future testMain() async { expect(paragraph.toDomElement().children.single.style.fontFamily, '"MyFont 2000", $fallback, sans-serif'); - debugEmulateFlutterTesterEnvironment = true; + ui_web.debugEmulateFlutterTesterEnvironment = true; }); group('TextRange', () { @@ -360,9 +361,9 @@ Future testMain() async { }); group('test fonts in flutterTester environment', () { - final bool resetValue = debugEmulateFlutterTesterEnvironment; - debugEmulateFlutterTesterEnvironment = true; - tearDownAll(() => debugEmulateFlutterTesterEnvironment = resetValue); + final bool resetValue = ui_web.debugEmulateFlutterTesterEnvironment; + ui_web.debugEmulateFlutterTesterEnvironment = true; + tearDownAll(() => ui_web.debugEmulateFlutterTesterEnvironment = resetValue); const List testFonts = ['FlutterTest', 'Ahem']; test('The default test font is used when a non-test fontFamily is specified, or fontFamily is not specified', () { diff --git a/shell/common/dl_op_spy_unittests.cc b/shell/common/dl_op_spy_unittests.cc index 7aaac1cbe52a8..dba02134238c8 100644 --- a/shell/common/dl_op_spy_unittests.cc +++ b/shell/common/dl_op_spy_unittests.cc @@ -7,40 +7,15 @@ #include "flutter/shell/common/dl_op_spy.h" #include "flutter/testing/testing.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkRSXform.h" namespace flutter { namespace testing { -// The following macros demonstrate that the DlOpSpy class is equivalent -// to DisplayList::affects_transparent_surface() now that DisplayListBuilder -// implements operation culling. -// See https://github.com/flutter/flutter/issues/125403 -#define ASSERT_DID_DRAW(spy, dl) \ - do { \ - ASSERT_TRUE(spy.did_draw()); \ - ASSERT_TRUE(dl->modifies_transparent_black()); \ - } while (0) - -#define ASSERT_NO_DRAW(spy, dl) \ - do { \ - ASSERT_FALSE(spy.did_draw()); \ - ASSERT_FALSE(dl->modifies_transparent_black()); \ - } while (0) - TEST(DlOpSpy, DidDrawIsFalseByDefault) { DlOpSpy dl_op_spy; ASSERT_FALSE(dl_op_spy.did_draw()); } -TEST(DlOpSpy, EmptyDisplayList) { - DisplayListBuilder builder; - sk_sp dl = builder.Build(); - DlOpSpy dl_op_spy; - dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); -} - TEST(DlOpSpy, SetColor) { { // No Color set. DisplayListBuilder builder; @@ -49,7 +24,7 @@ TEST(DlOpSpy, SetColor) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // Set transparent color. DisplayListBuilder builder; @@ -58,7 +33,7 @@ TEST(DlOpSpy, SetColor) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } { // Set black color. DisplayListBuilder builder; @@ -67,7 +42,7 @@ TEST(DlOpSpy, SetColor) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } } @@ -80,7 +55,7 @@ TEST(DlOpSpy, SetColorSource) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // Set transparent color. DisplayListBuilder builder; @@ -92,7 +67,7 @@ TEST(DlOpSpy, SetColorSource) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } { // Set black color. DisplayListBuilder builder; @@ -104,7 +79,7 @@ TEST(DlOpSpy, SetColorSource) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } } @@ -116,25 +91,16 @@ TEST(DlOpSpy, DrawColor) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } - { // Transparent color with kSrc. + { // Transparent color source. DisplayListBuilder builder; auto color = DlColor::kTransparent(); builder.DrawColor(color, DlBlendMode::kSrc); sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); - } - { // Transparent color with kSrcOver. - DisplayListBuilder builder; - auto color = DlColor::kTransparent(); - builder.DrawColor(color, DlBlendMode::kSrcOver); - sk_sp dl = builder.Build(); - DlOpSpy dl_op_spy; - dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } @@ -146,7 +112,7 @@ TEST(DlOpSpy, DrawPaint) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } { // black color in paint. DisplayListBuilder builder; @@ -155,7 +121,7 @@ TEST(DlOpSpy, DrawPaint) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } } @@ -167,7 +133,7 @@ TEST(DlOpSpy, DrawLine) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; @@ -176,7 +142,7 @@ TEST(DlOpSpy, DrawLine) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } @@ -188,7 +154,7 @@ TEST(DlOpSpy, DrawRect) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; @@ -197,11 +163,11 @@ TEST(DlOpSpy, DrawRect) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawOval) { +TEST(DlOpSpy, drawOval) { { // black DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); @@ -209,7 +175,7 @@ TEST(DlOpSpy, DrawOval) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; @@ -218,11 +184,11 @@ TEST(DlOpSpy, DrawOval) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawCircle) { +TEST(DlOpSpy, drawCircle) { { // black DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); @@ -230,7 +196,7 @@ TEST(DlOpSpy, DrawCircle) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; @@ -239,11 +205,11 @@ TEST(DlOpSpy, DrawCircle) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawRRect) { +TEST(DlOpSpy, drawRRect) { { // black DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); @@ -251,7 +217,7 @@ TEST(DlOpSpy, DrawRRect) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; @@ -260,49 +226,34 @@ TEST(DlOpSpy, DrawRRect) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawPath) { - { // black line +TEST(DlOpSpy, drawPath) { + { // black DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); - paint.setDrawStyle(DlDrawStyle::kStroke); builder.DrawPath(SkPath::Line(SkPoint::Make(0, 1), SkPoint::Make(1, 1)), paint); sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } - { // triangle - DisplayListBuilder builder; - DlPaint paint(DlColor::kBlack()); - SkPath path; - path.moveTo({0, 0}); - path.lineTo({1, 0}); - path.lineTo({0, 1}); - builder.DrawPath(path, paint); - sk_sp dl = builder.Build(); - DlOpSpy dl_op_spy; - dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); - } - { // transparent line + { // transparent DisplayListBuilder builder; DlPaint paint(DlColor::kTransparent()); - paint.setDrawStyle(DlDrawStyle::kStroke); builder.DrawPath(SkPath::Line(SkPoint::Make(0, 1), SkPoint::Make(1, 1)), paint); sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawArc) { +TEST(DlOpSpy, drawArc) { { // black DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); @@ -310,7 +261,7 @@ TEST(DlOpSpy, DrawArc) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; @@ -319,11 +270,11 @@ TEST(DlOpSpy, DrawArc) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawPoints) { +TEST(DlOpSpy, drawPoints) { { // black DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); @@ -332,7 +283,7 @@ TEST(DlOpSpy, DrawPoints) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; @@ -342,62 +293,38 @@ TEST(DlOpSpy, DrawPoints) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawVertices) { +TEST(DlOpSpy, drawVertices) { { // black DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); - const SkPoint vertices[] = { - SkPoint::Make(5, 5), - SkPoint::Make(5, 15), - SkPoint::Make(15, 5), - }; - const SkPoint texture_coordinates[] = { - SkPoint::Make(5, 5), - SkPoint::Make(15, 5), - SkPoint::Make(5, 15), - }; - const DlColor colors[] = { - DlColor::kBlack(), - DlColor::kRed(), - DlColor::kGreen(), - }; - auto dl_vertices = DlVertices::Make(DlVertexMode::kTriangles, 3, vertices, + const SkPoint vertices[] = {SkPoint::Make(5, 5)}; + const SkPoint texture_coordinates[] = {SkPoint::Make(5, 5)}; + const DlColor colors[] = {DlColor::kBlack()}; + auto dl_vertices = DlVertices::Make(DlVertexMode::kTriangles, 1, vertices, texture_coordinates, colors, 0); builder.DrawVertices(dl_vertices.get(), DlBlendMode::kSrc, paint); sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; DlPaint paint(DlColor::kTransparent()); - const SkPoint vertices[] = { - SkPoint::Make(5, 5), - SkPoint::Make(5, 15), - SkPoint::Make(15, 5), - }; - const SkPoint texture_coordinates[] = { - SkPoint::Make(5, 5), - SkPoint::Make(15, 5), - SkPoint::Make(5, 15), - }; - const DlColor colors[] = { - DlColor::kBlack(), - DlColor::kRed(), - DlColor::kGreen(), - }; - auto dl_vertices = DlVertices::Make(DlVertexMode::kTriangles, 3, vertices, + const SkPoint vertices[] = {SkPoint::Make(5, 5)}; + const SkPoint texture_coordinates[] = {SkPoint::Make(5, 5)}; + const DlColor colors[] = {DlColor::kBlack()}; + auto dl_vertices = DlVertices::Make(DlVertexMode::kTriangles, 1, vertices, texture_coordinates, colors, 0); builder.DrawVertices(dl_vertices.get(), DlBlendMode::kSrc, paint); sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } @@ -416,7 +343,7 @@ TEST(DlOpSpy, Images) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // DrawImageRect DisplayListBuilder builder; @@ -432,7 +359,7 @@ TEST(DlOpSpy, Images) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // DrawImageNine DisplayListBuilder builder; @@ -448,7 +375,7 @@ TEST(DlOpSpy, Images) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // DrawAtlas DisplayListBuilder builder; @@ -459,19 +386,20 @@ TEST(DlOpSpy, Images) { SkBitmap bitmap; bitmap.allocPixels(info, 0); auto sk_image = SkImages::RasterFromBitmap(bitmap); - const SkRSXform xform[] = {SkRSXform::Make(1, 0, 0, 0)}; - const SkRect tex[] = {SkRect::MakeXYWH(10, 10, 10, 10)}; + const SkRSXform xform[] = {}; + const SkRect tex[] = {}; + const DlColor colors[] = {}; SkRect cull_rect = SkRect::MakeWH(5, 5); - builder.DrawAtlas(DlImage::Make(sk_image), xform, tex, nullptr, 1, + builder.DrawAtlas(DlImage::Make(sk_image), xform, tex, colors, 0, DlBlendMode::kSrc, DlImageSampling::kLinear, &cull_rect); sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawDisplayList) { +TEST(DlOpSpy, drawDisplayList) { { // Recursive Transparent DisplayList DisplayListBuilder builder; DlPaint paint(DlColor::kTransparent()); @@ -486,7 +414,7 @@ TEST(DlOpSpy, DrawDisplayList) { DlOpSpy dl_op_spy; dl2->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl2); + ASSERT_FALSE(dl_op_spy.did_draw()); } { // Sub non-transparent DisplayList, DisplayListBuilder builder; @@ -502,7 +430,7 @@ TEST(DlOpSpy, DrawDisplayList) { DlOpSpy dl_op_spy; dl2->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl2); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // Sub non-transparent DisplayList, 0 opacity @@ -519,7 +447,7 @@ TEST(DlOpSpy, DrawDisplayList) { DlOpSpy dl_op_spy; dl2->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl2); + ASSERT_FALSE(dl_op_spy.did_draw()); } { // Parent non-transparent DisplayList @@ -536,11 +464,11 @@ TEST(DlOpSpy, DrawDisplayList) { DlOpSpy dl_op_spy; dl2->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl2); + ASSERT_TRUE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawTextBlob) { +TEST(DlOpSpy, drawTextBlob) { { // Non-transparent color. DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); @@ -551,7 +479,7 @@ TEST(DlOpSpy, DrawTextBlob) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent color. DisplayListBuilder builder; @@ -563,11 +491,11 @@ TEST(DlOpSpy, DrawTextBlob) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawShadow) { +TEST(DlOpSpy, drawShadow) { { // valid shadow DisplayListBuilder builder; DlPaint paint; @@ -577,7 +505,7 @@ TEST(DlOpSpy, DrawShadow) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent color DisplayListBuilder builder; @@ -588,7 +516,7 @@ TEST(DlOpSpy, DrawShadow) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } diff --git a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/system.h b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/system.h index ba5adba05e637..c2dd01c799c4c 100644 --- a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/system.h +++ b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/system.h @@ -14,15 +14,6 @@ #include "third_party/tonic/dart_wrappable.h" #include "third_party/tonic/typed_data/dart_byte_data.h" -// TODO (kaushikiska): Once fuchsia adds fs to their sdk, -// use the rights macros from "fs/vfs.h" - -// Rights -// The file may be read. -#define ZX_FS_RIGHT_READABLE 0x00000001 -// The file may be written. -#define ZX_FS_RIGHT_WRITABLE 0x00000002 - namespace zircon { namespace dart { diff --git a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc index 366b72bc0b429..3823e672b2361 100644 --- a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc +++ b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc @@ -235,8 +235,26 @@ void FlatlandExternalViewEmbedder::SubmitFrame( const ViewMutators view_mutators = ParseMutatorStack(view_params.mutatorsStack()); const SkSize view_size = view_params.sizePoints(); - FML_CHECK(view_mutators.total_transform == - view_params.transformMatrix()); + + // Verify that we're unpacking the mutators' transform matrix correctly. + // Use built-in get method for SkMatrix to get values, see: + // https://source.corp.google.com/piper///depot/google3/third_party/skia/HEAD/include/core/SkMatrix.h;l=391 + for (int index = 0; index < 9; index++) { + const SkScalar mutators_transform_value = + view_mutators.total_transform.get(index); + const SkScalar params_transform_value = + view_params.transformMatrix().get(index); + if (!SkScalarNearlyEqual(mutators_transform_value, + params_transform_value, 0.0005f)) { + FML_LOG(ERROR) + << "Assertion failed: view_mutators.total_transform[" << index + << "] (" << mutators_transform_value + << ") != view_params.transformMatrix()[" << index << "] (" + << params_transform_value + << "). This likely means there is a bug with the " + << "logic for parsing embedded views' transform matrices."; + } + } if (viewport.pending_create_viewport_callback) { if (view_size.fWidth && view_size.fHeight) { diff --git a/shell/platform/windows/accessibility_bridge_windows.cc b/shell/platform/windows/accessibility_bridge_windows.cc index 5d90d03c33a96..3c8ee215b09e9 100644 --- a/shell/platform/windows/accessibility_bridge_windows.cc +++ b/shell/platform/windows/accessibility_bridge_windows.cc @@ -45,10 +45,8 @@ void AccessibilityBridgeWindows::OnAccessibilityEvent( // only for the focused node whose selection has changed. If a valid // caret and selection exist in the app tree, they must both be within // the focus node. - ui::AXNode::AXID focus_id = GetAXTreeData().sel_focus_object_id; - auto focus_delegate = - GetFlutterPlatformNodeDelegateFromID(focus_id).lock(); - if (!focus_delegate) { + auto focus_delegate = GetFocusedNode().lock(); + if (focus_delegate) { win_delegate = std::static_pointer_cast( focus_delegate); @@ -204,4 +202,10 @@ bool AccessibilityBridgeWindows::IsAXFragmentRootAControlElement() { return true; } +std::weak_ptr +AccessibilityBridgeWindows::GetFocusedNode() { + ui::AXNode::AXID focus_id = GetAXTreeData().sel_focus_object_id; + return GetFlutterPlatformNodeDelegateFromID(focus_id); +} + } // namespace flutter diff --git a/shell/platform/windows/accessibility_bridge_windows.h b/shell/platform/windows/accessibility_bridge_windows.h index 18660bcf605e7..efb2f8a47aac6 100644 --- a/shell/platform/windows/accessibility_bridge_windows.h +++ b/shell/platform/windows/accessibility_bridge_windows.h @@ -68,6 +68,9 @@ class AccessibilityBridgeWindows : public AccessibilityBridge, std::shared_ptr CreateFlutterPlatformNodeDelegate() override; + // Retrieve the focused node for accessibility events. + virtual std::weak_ptr GetFocusedNode(); + private: FlutterWindowsView* view_; diff --git a/shell/platform/windows/accessibility_bridge_windows_unittests.cc b/shell/platform/windows/accessibility_bridge_windows_unittests.cc index 92cfcc7ff8975..a07f52d5c4f25 100644 --- a/shell/platform/windows/accessibility_bridge_windows_unittests.cc +++ b/shell/platform/windows/accessibility_bridge_windows_unittests.cc @@ -50,7 +50,7 @@ class AccessibilityBridgeWindowsSpy : public AccessibilityBridgeWindows { void SetFocus(std::shared_ptr node_delegate) override { - focused_nodes_.push_back(node_delegate->GetAXNode()->id()); + focused_nodes_.push_back(std::move(node_delegate)); } void ResetRecords() { @@ -62,11 +62,24 @@ class AccessibilityBridgeWindowsSpy : public AccessibilityBridgeWindows { return dispatched_events_; } - const std::vector focused_nodes() const { return focused_nodes_; } + const std::vector focused_nodes() const { + std::vector ids; + std::transform(focused_nodes_.begin(), focused_nodes_.end(), + std::back_inserter(ids), + [](std::shared_ptr node) { + return node->GetAXNode()->id(); + }); + return ids; + } + + protected: + std::weak_ptr GetFocusedNode() override { + return focused_nodes_.back(); + } private: std::vector dispatched_events_; - std::vector focused_nodes_; + std::vector> focused_nodes_; FML_DISALLOW_COPY_AND_ASSIGN(AccessibilityBridgeWindowsSpy); }; @@ -189,6 +202,32 @@ void ExpectWinEventFromAXEvent(int32_t node_id, EXPECT_EQ(bridge->dispatched_events()[0].event_type, expected_event); } +void ExpectWinEventFromAXEventOnFocusNode(int32_t node_id, + ui::AXEventGenerator::Event ax_event, + ax::mojom::Event expected_event, + int32_t focus_id) { + auto window_binding_handler = + std::make_unique<::testing::NiceMock>(); + FlutterWindowsViewSpy view(std::move(window_binding_handler)); + view.SetEngine(GetTestEngine()); + view.OnUpdateSemanticsEnabled(true); + + auto bridge = GetAccessibilityBridgeSpy(view.GetEngine()); + PopulateAXTree(bridge); + + bridge->ResetRecords(); + auto focus_delegate = + bridge->GetFlutterPlatformNodeDelegateFromID(focus_id).lock(); + bridge->SetFocus(std::static_pointer_cast( + focus_delegate)); + bridge->OnAccessibilityEvent({AXNodeFromID(bridge, node_id), + {ax_event, ax::mojom::EventFrom::kNone, {}}}); + ASSERT_EQ(bridge->dispatched_events().size(), 1); + EXPECT_EQ(bridge->dispatched_events()[0].event_type, expected_event); + EXPECT_EQ(bridge->dispatched_events()[0].node_delegate->GetAXNode()->id(), + focus_id); +} + } // namespace TEST(AccessibilityBridgeWindows, GetParent) { @@ -342,9 +381,9 @@ TEST(AccessibilityBridgeWindows, OnAccessibilityStateChanged) { } TEST(AccessibilityBridgeWindows, OnDocumentSelectionChanged) { - ExpectWinEventFromAXEvent( + ExpectWinEventFromAXEventOnFocusNode( 1, ui::AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED, - ax::mojom::Event::kDocumentSelectionChanged); + ax::mojom::Event::kDocumentSelectionChanged, 2); } } // namespace testing diff --git a/testing/dart/channel_buffers_test.dart b/testing/dart/channel_buffers_test.dart index 4058719d5f996..a35f84207e49f 100644 --- a/testing/dart/channel_buffers_test.dart +++ b/testing/dart/channel_buffers_test.dart @@ -12,7 +12,7 @@ import 'dart:ui' as ui; import 'package:litetest/litetest.dart'; ByteData _makeByteData(String str) { - final Uint8List list = utf8.encode(str) as Uint8List; + final Uint8List list = const Utf8Encoder().convert(str); final ByteBuffer buffer = list.buffer; return ByteData.view(buffer); } From a87fd1bfa364dd53672c7c6ca54ac16a161ea32b Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 5 Jul 2023 15:46:56 -0700 Subject: [PATCH 08/16] ++ --- .../renderer/backend/vulkan/allocator_vk.cc | 63 ++----------------- 1 file changed, 6 insertions(+), 57 deletions(-) diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index bb5b2f7b93cf5..36a53d2ce04e1 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -93,53 +93,6 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, VALIDATION_LOG << "Could not create memory allocator"; return; } - if (!CreateBufferPool(allocator, UsageHint::kRasterWorkload, - &raster_buffer_pool_)) { - return; - } - if (!CreateBufferPool(allocator, UsageHint::kImageUpload, - &image_upload_buffer_pool_)) { - return; - } - - { - vk::ImageCreateInfo image_info; - image_info.flags = {}; - image_info.imageType = vk::ImageType::e2D; - image_info.format = vk::Format::eR8G8B8A8Unorm; - image_info.extent = VkExtent3D{1u, 1u, 1u}; - image_info.samples = vk::SampleCountFlagBits::e1; - image_info.mipLevels = 1u; - image_info.arrayLayers = 1u; - image_info.tiling = vk::ImageTiling::eOptimal; - image_info.initialLayout = vk::ImageLayout::eUndefined; - image_info.usage = - vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst; - image_info.sharingMode = vk::SharingMode::eExclusive; - - auto create_info_native = - static_cast(image_info); - - VmaAllocationCreateInfo sampleAllocCreateInfo = {}; - sampleAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; - sampleAllocCreateInfo.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - - uint32_t memTypeIndex; - VkResult res = vmaFindMemoryTypeIndexForImageInfo( - allocator, &create_info_native, &sampleAllocCreateInfo, &memTypeIndex); - - VmaPoolCreateInfo poolCreateInfo = {}; - poolCreateInfo.memoryTypeIndex = memTypeIndex; - poolCreateInfo.blockSize = 128ull * 1024 * 1024; - - result = vk::Result{ - vmaCreatePool(allocator, &poolCreateInfo, &image_upload_texture_pool_)}; - if (result != vk::Result::eSuccess) { - VALIDATION_LOG << "Could not create memory allocator"; - return; - } - } - allocator_ = allocator; supports_memoryless_textures_ = capabilities.SupportsMemorylessTextures(); is_valid_ = true; @@ -148,15 +101,6 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, AllocatorVK::~AllocatorVK() { TRACE_EVENT0("impeller", "DestroyAllocatorVK"); if (allocator_) { - if (raster_buffer_pool_) { - ::vmaDestroyPool(allocator_, raster_buffer_pool_); - } - if (image_upload_buffer_pool_) { - ::vmaDestroyPool(allocator_, image_upload_buffer_pool_); - } - if (image_upload_texture_pool_) { - ::vmaDestroyPool(allocator_, image_upload_texture_pool_); - } ::vmaDestroyAllocator(allocator_); } } @@ -449,7 +393,12 @@ std::shared_ptr AllocatorVK::OnCreateBuffer( const DeviceBufferDescriptor& desc) { TRACE_EVENT0("impeller", "AllocatorVK::OnCreateBuffer"); vk::BufferCreateInfo buffer_info; - buffer_info.usage = VmaBufferUsageFlags(desc.usage_hint); + buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer | + vk::BufferUsageFlagBits::eIndexBuffer | + vk::BufferUsageFlagBits::eUniformBuffer | + vk::BufferUsageFlagBits::eStorageBuffer | + vk::BufferUsageFlagBits::eTransferSrc | + vk::BufferUsageFlagBits::eTransferDst; buffer_info.size = desc.size; buffer_info.sharingMode = vk::SharingMode::eExclusive; auto buffer_info_native = From eb5f50fb358952f8f312310a25a60e03ca1022fd Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 5 Jul 2023 16:50:28 -0700 Subject: [PATCH 09/16] backout to just buffer pool. --- impeller/core/device_buffer_descriptor.h | 1 - impeller/core/formats.h | 7 -- impeller/core/texture_descriptor.h | 1 - impeller/entity/geometry/geometry.h | 6 -- .../renderer/backend/vulkan/allocator_vk.cc | 91 +++++++++++++++---- .../renderer/backend/vulkan/allocator_vk.h | 7 +- lib/ui/painting/image_decoder_impeller.cc | 2 - 7 files changed, 78 insertions(+), 37 deletions(-) diff --git a/impeller/core/device_buffer_descriptor.h b/impeller/core/device_buffer_descriptor.h index 7352712b89404..976b8f7b0acac 100644 --- a/impeller/core/device_buffer_descriptor.h +++ b/impeller/core/device_buffer_descriptor.h @@ -13,7 +13,6 @@ namespace impeller { struct DeviceBufferDescriptor { StorageMode storage_mode = StorageMode::kDeviceTransient; size_t size = 0u; - UsageHint usage_hint = UsageHint::kRasterWorkload; }; } // namespace impeller diff --git a/impeller/core/formats.h b/impeller/core/formats.h index 4f0a642de1bc3..ff031d96008b1 100644 --- a/impeller/core/formats.h +++ b/impeller/core/formats.h @@ -293,13 +293,6 @@ constexpr const char* TextureUsageToString(TextureUsage usage) { std::string TextureUsageMaskToString(TextureUsageMask mask); -enum class UsageHint { - /// @brief Texture or buffer is being used during the raster workload. - kRasterWorkload, - /// @brief Texture or buffer is being used as part of an async image upload. - kImageUpload, -}; - enum class TextureIntent { kUploadFromHost, kRenderToTexture, diff --git a/impeller/core/texture_descriptor.h b/impeller/core/texture_descriptor.h index 32ccd0098f175..7d99d20408da5 100644 --- a/impeller/core/texture_descriptor.h +++ b/impeller/core/texture_descriptor.h @@ -46,7 +46,6 @@ struct TextureDescriptor { static_cast(TextureUsage::kShaderRead); SampleCount sample_count = SampleCount::kCount1; CompressionType compression_type = CompressionType::kLossless; - UsageHint usage_hint = UsageHint::kRasterWorkload; constexpr size_t GetByteSizeOfBaseMipLevel() const { if (!IsValid()) { diff --git a/impeller/entity/geometry/geometry.h b/impeller/entity/geometry/geometry.h index 48e6801d89ec4..0f80e5456b0c1 100644 --- a/impeller/entity/geometry/geometry.h +++ b/impeller/entity/geometry/geometry.h @@ -90,13 +90,7 @@ class Geometry { /// @return `true` if this geometry will completely cover all fragments in /// `rect` when the `transform` is applied to it. -<<<<<<< HEAD - virtual bool CoversArea(const Matrix& transform, const Rect& rect) const { - return false; - } -======= virtual bool CoversArea(const Matrix& transform, const Rect& rect) const; ->>>>>>> 1d9c8f35a5dc7e90f41996ab58c99da9be054016 }; } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index 36a53d2ce04e1..c0100b754f327 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -93,6 +93,10 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, VALIDATION_LOG << "Could not create memory allocator"; return; } + + if (!CreateBufferPool(allocator, &staging_buffer_pool_)) { + return; + } allocator_ = allocator; supports_memoryless_textures_ = capabilities.SupportsMemorylessTextures(); is_valid_ = true; @@ -101,6 +105,9 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, AllocatorVK::~AllocatorVK() { TRACE_EVENT0("impeller", "DestroyAllocatorVK"); if (allocator_) { + if (staging_buffer_pool_) { + ::vmaDestroyPool(allocator_, staging_buffer_pool_); + } ::vmaDestroyAllocator(allocator_); } } @@ -211,25 +218,16 @@ static constexpr VkMemoryPropertyFlags ToVKBufferMemoryPropertyFlags( } static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode, - bool is_texture, - size_t size) { + bool dedicated) { VmaAllocationCreateFlags flags = 0; switch (mode) { case StorageMode::kHostVisible: - if (is_texture) { - if (size >= kImageSizeThresholdForDedicatedMemoryAllocation) { - flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; - } else { - flags |= {}; - } - } else { - flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; - flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT; + if (dedicated) { + flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; } return flags; case StorageMode::kDevicePrivate: - if (is_texture && - size >= kImageSizeThresholdForDedicatedMemoryAllocation) { + if (dedicated) { flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; } return flags; @@ -239,6 +237,22 @@ static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode, FML_UNREACHABLE(); } +static VmaAllocationCreateFlags ToVmaAllocationBufferCreateFlags( + StorageMode mode) { + VmaAllocationCreateFlags flags = 0; + switch (mode) { + case StorageMode::kHostVisible: + flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; + flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT; + return flags; + case StorageMode::kDevicePrivate: + return flags; + case StorageMode::kDeviceTransient: + return flags; + } + FML_UNREACHABLE(); +} + class AllocatedTextureSourceVK final : public TextureSourceVK { public: AllocatedTextureSourceVK(const TextureDescriptor& desc, @@ -268,12 +282,14 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { VmaAllocationCreateInfo alloc_nfo = {}; + auto use_dedicated = desc.GetByteSizeOfBaseMipLevel() > + kImageSizeThresholdForDedicatedMemoryAllocation; + alloc_nfo.usage = ToVMAMemoryUsage(); alloc_nfo.preferredFlags = ToVKTextureMemoryPropertyFlags( desc.storage_mode, supports_memoryless_textures); alloc_nfo.flags = - ToVmaAllocationCreateFlags(desc.storage_mode, /*is_texture=*/true, - desc.GetByteSizeOfBaseMipLevel()); + ToVmaAllocationCreateFlags(desc.storage_mode, use_dedicated); auto create_info_native = static_cast(image_info); @@ -408,8 +424,10 @@ std::shared_ptr AllocatorVK::OnCreateBuffer( allocation_info.usage = ToVMAMemoryUsage(); allocation_info.preferredFlags = ToVKBufferMemoryPropertyFlags(desc.storage_mode); - allocation_info.flags = ToVmaAllocationCreateFlags( - desc.storage_mode, /*is_texture=*/false, desc.size); + allocation_info.flags = ToVmaAllocationBufferCreateFlags(desc.storage_mode); + if (desc.storage_mode == StorageMode::kHostVisible) { + allocation_info.pool = staging_buffer_pool_; + } VkBuffer buffer = {}; VmaAllocation buffer_allocation = {}; @@ -437,4 +455,43 @@ std::shared_ptr AllocatorVK::OnCreateBuffer( ); } +// static +bool AllocatorVK::CreateBufferPool(VmaAllocator allocator, VmaPool* pool) { + vk::BufferCreateInfo buffer_info; + buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer | + vk::BufferUsageFlagBits::eIndexBuffer | + vk::BufferUsageFlagBits::eUniformBuffer | + vk::BufferUsageFlagBits::eStorageBuffer | + vk::BufferUsageFlagBits::eTransferSrc | + vk::BufferUsageFlagBits::eTransferDst; + buffer_info.size = 1u; // doesn't matter + buffer_info.sharingMode = vk::SharingMode::eExclusive; + auto buffer_info_native = + static_cast(buffer_info); + + VmaAllocationCreateInfo allocation_info = {}; + allocation_info.usage = VMA_MEMORY_USAGE_AUTO; + allocation_info.preferredFlags = + ToVKBufferMemoryPropertyFlags(StorageMode::kHostVisible); + allocation_info.flags = + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; + + uint32_t memTypeIndex; + VkResult res = vmaFindMemoryTypeIndexForBufferInfo( + allocator, &buffer_info_native, &allocation_info, &memTypeIndex); + + VmaPoolCreateInfo pool_create_info = {}; + pool_create_info.memoryTypeIndex = memTypeIndex; + pool_create_info.flags = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT; + + auto result = vk::Result{vmaCreatePool(allocator, &pool_create_info, pool)}; + if (result != vk::Result::eSuccess) { + VALIDATION_LOG << "Could not create buffer pool."; + return false; + } + return true; +} + + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/allocator_vk.h b/impeller/renderer/backend/vulkan/allocator_vk.h index c453a3b8a33a4..b17a2fdd09372 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.h +++ b/impeller/renderer/backend/vulkan/allocator_vk.h @@ -27,9 +27,7 @@ class AllocatorVK final : public Allocator { fml::RefPtr vk_; VmaAllocator allocator_ = {}; - VmaPool raster_buffer_pool_ = {}; - VmaPool image_upload_buffer_pool_ = {}; - VmaPool image_upload_texture_pool_ = {}; + VmaPool staging_buffer_pool_ = {}; std::weak_ptr context_; std::weak_ptr device_holder_; @@ -60,6 +58,9 @@ class AllocatorVK final : public Allocator { // |Allocator| ISize GetMaxTextureSizeSupported() const override; + static bool CreateBufferPool(VmaAllocator allocator, + VmaPool* pool); + FML_DISALLOW_COPY_AND_ASSIGN(AllocatorVK); }; diff --git a/lib/ui/painting/image_decoder_impeller.cc b/lib/ui/painting/image_decoder_impeller.cc index b553f12ed2190..af111c6ff0341 100644 --- a/lib/ui/painting/image_decoder_impeller.cc +++ b/lib/ui/painting/image_decoder_impeller.cc @@ -268,7 +268,6 @@ static std::pair, std::string> UnsafeUploadTextureToPrivate( texture_descriptor.size = {image_info.width(), image_info.height()}; texture_descriptor.mip_count = texture_descriptor.size.MipCount(); texture_descriptor.compression_type = impeller::CompressionType::kLossy; - texture_descriptor.usage_hint = impeller::UsageHint::kImageUpload; auto dest_texture = context->GetResourceAllocator()->CreateTexture(texture_descriptor); @@ -525,7 +524,6 @@ bool ImpellerAllocator::allocPixelRef(SkBitmap* bitmap) { descriptor.storage_mode = impeller::StorageMode::kHostVisible; descriptor.size = ((bitmap->height() - 1) * bitmap->rowBytes()) + (bitmap->width() * bitmap->bytesPerPixel()); - descriptor.usage_hint = impeller::UsageHint::kImageUpload; auto device_buffer = allocator_->CreateBuffer(descriptor); From d29da31059bbefc453c27b70df7ee25a9803f877 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 5 Jul 2023 16:50:54 -0700 Subject: [PATCH 10/16] ++ --- impeller/renderer/backend/vulkan/allocator_vk.cc | 1 - impeller/renderer/backend/vulkan/allocator_vk.h | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index c0100b754f327..086298a613250 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -493,5 +493,4 @@ bool AllocatorVK::CreateBufferPool(VmaAllocator allocator, VmaPool* pool) { return true; } - } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/allocator_vk.h b/impeller/renderer/backend/vulkan/allocator_vk.h index b17a2fdd09372..b32a9e7c9302b 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.h +++ b/impeller/renderer/backend/vulkan/allocator_vk.h @@ -58,8 +58,7 @@ class AllocatorVK final : public Allocator { // |Allocator| ISize GetMaxTextureSizeSupported() const override; - static bool CreateBufferPool(VmaAllocator allocator, - VmaPool* pool); + static bool CreateBufferPool(VmaAllocator allocator, VmaPool* pool); FML_DISALLOW_COPY_AND_ASSIGN(AllocatorVK); }; From b27390a39a10b46ae9cac17c70680e04fd6520a8 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 5 Jul 2023 16:52:36 -0700 Subject: [PATCH 11/16] ++ --- DEPS | 4 ---- ci/licenses_golden/licenses_flutter | 1 - ci/licenses_golden/licenses_skia | 4 ---- 3 files changed, 9 deletions(-) diff --git a/DEPS b/DEPS index 98faedd12c071..7ccacf40b095a 100644 --- a/DEPS +++ b/DEPS @@ -18,11 +18,7 @@ vars = { 'llvm_git': 'https://llvm.googlesource.com', # OCMock is for testing only so there is no google clone 'ocmock_git': 'https://github.com/erikdoe/ocmock.git', -<<<<<<< HEAD - 'skia_revision': '2d05e3ec6b6702eff0105940fd76b6b499acd031', -======= 'skia_revision': '8ed969b60e98ce250a256a26fcab9a11ec73b34a', ->>>>>>> 1d9c8f35a5dc7e90f41996ab58c99da9be054016 # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 7eef1ecb2efcb..7555581201dd0 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1523,7 +1523,6 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.cc + . ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/limits_vk.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pass_bindings_cache.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pass_bindings_cache.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_cache_vk.cc + ../../../flutter/LICENSE diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 856fced7cf763..ff78bf73c12cb 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -388,10 +388,6 @@ FILE: ../../../third_party/skia/relnotes/canvas_flush.md FILE: ../../../third_party/skia/relnotes/const_context.md FILE: ../../../third_party/skia/relnotes/runtimeeffect_const.md FILE: ../../../third_party/skia/relnotes/runtimeeffect_image.md -<<<<<<< HEAD -FILE: ../../../third_party/skia/relnotes/tiledimages.md -======= ->>>>>>> 1d9c8f35a5dc7e90f41996ab58c99da9be054016 FILE: ../../../third_party/skia/src/core/SkOrderedReadBuffer.h FILE: ../../../third_party/skia/src/gpu/gpu_workaround_list.txt FILE: ../../../third_party/skia/src/sksl/generated/sksl_compute.minified.sksl From 7d62f0ae020fea1970dd2f7381ee3754e8b393c7 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 6 Jul 2023 09:59:02 -0700 Subject: [PATCH 12/16] Update allocator_vk.cc --- impeller/renderer/backend/vulkan/allocator_vk.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index 086298a613250..1d6a02248c020 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -478,14 +478,18 @@ bool AllocatorVK::CreateBufferPool(VmaAllocator allocator, VmaPool* pool) { VMA_ALLOCATION_CREATE_MAPPED_BIT; uint32_t memTypeIndex; - VkResult res = vmaFindMemoryTypeIndexForBufferInfo( - allocator, &buffer_info_native, &allocation_info, &memTypeIndex); + auto result = vk::Result{vmaFindMemoryTypeIndexForBufferInfo( + allocator, &buffer_info_native, &allocation_info, &memTypeIndex)}; + if (result != vk::Result::eSuccess) { + VALIDATION_LOG << "Could not find memory type for buffer pool."; + return false; + } VmaPoolCreateInfo pool_create_info = {}; pool_create_info.memoryTypeIndex = memTypeIndex; pool_create_info.flags = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT; - auto result = vk::Result{vmaCreatePool(allocator, &pool_create_info, pool)}; + result = vk::Result{vmaCreatePool(allocator, &pool_create_info, pool)}; if (result != vk::Result::eSuccess) { VALIDATION_LOG << "Could not create buffer pool."; return false; From d45fd78652725d936fd9c848274b5c44e1e65553 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 6 Jul 2023 11:42:18 -0700 Subject: [PATCH 13/16] ++ --- impeller/renderer/backend/vulkan/allocator_vk.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index 1d6a02248c020..01a2a4291d72d 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -474,8 +474,7 @@ bool AllocatorVK::CreateBufferPool(VmaAllocator allocator, VmaPool* pool) { allocation_info.preferredFlags = ToVKBufferMemoryPropertyFlags(StorageMode::kHostVisible); allocation_info.flags = - VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | - VMA_ALLOCATION_CREATE_MAPPED_BIT; + ToVmaAllocationBufferCreateFlags(StorageMode::kHostVisible); uint32_t memTypeIndex; auto result = vk::Result{vmaFindMemoryTypeIndexForBufferInfo( From 10be3d50ad5c95f71889eed412b3e712b02aa0c0 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 6 Jul 2023 19:34:40 -0700 Subject: [PATCH 14/16] remove device local bit when falling back. --- impeller/renderer/backend/vulkan/allocator_vk.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index 01a2a4291d72d..e12982c1012c4 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -480,8 +480,16 @@ bool AllocatorVK::CreateBufferPool(VmaAllocator allocator, VmaPool* pool) { auto result = vk::Result{vmaFindMemoryTypeIndexForBufferInfo( allocator, &buffer_info_native, &allocation_info, &memTypeIndex)}; if (result != vk::Result::eSuccess) { - VALIDATION_LOG << "Could not find memory type for buffer pool."; - return false; + // We're probably not running on a device with host visible + device local. + // fallback by removing device local bit. + allocation_info.preferredFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + result = vk::Result{vmaFindMemoryTypeIndexForBufferInfo( + allocator, &buffer_info_native, &allocation_info, &memTypeIndex)}; + + if (result != vk::Result::eSuccess) { + VALIDATION_LOG << "Could not find memory type for buffer pool."; + return false; + } } VmaPoolCreateInfo pool_create_info = {}; From 680906ddad403d92db5e1fdb5cfd3a4af1ea5219 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 7 Jul 2023 11:49:26 -0700 Subject: [PATCH 15/16] Drafty stuff --- impeller/aiks/picture.cc | 12 ++- impeller/core/allocator.h | 2 + impeller/core/texture_descriptor.h | 1 + impeller/entity/contents/scene_contents.cc | 1 + impeller/entity/entity_pass.cc | 2 + .../renderer/backend/vulkan/allocator_vk.cc | 100 ++++++++++++++---- .../renderer/backend/vulkan/allocator_vk.h | 14 ++- impeller/renderer/backend/vulkan/context_vk.h | 5 + .../renderer/backend/vulkan/surface_vk.cc | 1 + .../backend/vulkan/swapchain_impl_vk.cc | 1 + impeller/renderer/render_target.cc | 4 + impeller/renderer/render_target.h | 2 + lib/ui/painting/image_decoder_impeller.cc | 2 + 13 files changed, 121 insertions(+), 26 deletions(-) diff --git a/impeller/aiks/picture.cc b/impeller/aiks/picture.cc index 7ad91fb63ef0c..3ca4dc2cdde7d 100644 --- a/impeller/aiks/picture.cc +++ b/impeller/aiks/picture.cc @@ -61,7 +61,8 @@ std::shared_ptr Picture::RenderToTexture( size, // size "Picture Snapshot MSAA", // label RenderTarget:: - kDefaultColorAttachmentConfigMSAA // color_attachment_config + kDefaultColorAttachmentConfigMSAA, // color_attachment_config + true // persistent #ifndef FML_OS_ANDROID // Reduce PSO variants for Vulkan. , std::nullopt // stencil_attachment_config @@ -69,10 +70,11 @@ std::shared_ptr Picture::RenderToTexture( ); } else { target = RenderTarget::CreateOffscreen( - *impeller_context, // context - size, // size - "Picture Snapshot", // label - RenderTarget::kDefaultColorAttachmentConfig // color_attachment_config + *impeller_context, // context + size, // size + "Picture Snapshot", // label + RenderTarget::kDefaultColorAttachmentConfig, // color_attachment_config + true // persistent #ifndef FML_OS_ANDROID // Reduce PSO variants for Vulkan. , std::nullopt // stencil_attachment_config diff --git a/impeller/core/allocator.h b/impeller/core/allocator.h index 25b3dae07a22c..031dcad34d50e 100644 --- a/impeller/core/allocator.h +++ b/impeller/core/allocator.h @@ -45,6 +45,8 @@ class Allocator { virtual ISize GetMaxTextureSizeSupported() const = 0; + virtual void IncrementFrameIndex() {} + protected: Allocator(); diff --git a/impeller/core/texture_descriptor.h b/impeller/core/texture_descriptor.h index 7d99d20408da5..548bc2b53cf0a 100644 --- a/impeller/core/texture_descriptor.h +++ b/impeller/core/texture_descriptor.h @@ -46,6 +46,7 @@ struct TextureDescriptor { static_cast(TextureUsage::kShaderRead); SampleCount sample_count = SampleCount::kCount1; CompressionType compression_type = CompressionType::kLossless; + bool persistent = false; constexpr size_t GetByteSizeOfBaseMipLevel() const { if (!IsValid()) { diff --git a/impeller/entity/contents/scene_contents.cc b/impeller/entity/contents/scene_contents.cc index bb00ff923e26e..1834f5d32d490 100644 --- a/impeller/entity/contents/scene_contents.cc +++ b/impeller/entity/contents/scene_contents.cc @@ -54,6 +54,7 @@ bool SceneContents::Render(const ContentContext& renderer, .load_action = LoadAction::kClear, .store_action = StoreAction::kMultisampleResolve, }, // color_attachment_config + false, RenderTarget::AttachmentConfig{ .storage_mode = StorageMode::kDeviceTransient, .load_action = LoadAction::kDontCare, diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 19b1a2efd1a33..2006ea9640826 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -215,6 +215,7 @@ static EntityPassTarget CreateRenderTarget(ContentContext& renderer, .load_action = LoadAction::kDontCare, .store_action = StoreAction::kMultisampleResolve, .clear_color = clear_color}, // color_attachment_config + false, GetDefaultStencilConfig(readable) // stencil_attachment_config ); } else { @@ -228,6 +229,7 @@ static EntityPassTarget CreateRenderTarget(ContentContext& renderer, .store_action = StoreAction::kDontCare, .clear_color = clear_color, }, // color_attachment_config + false, GetDefaultStencilConfig(readable) // stencil_attachment_config ); } diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index e12982c1012c4..9566e3c5959b6 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -94,9 +94,15 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, return; } - if (!CreateBufferPool(allocator, &staging_buffer_pool_)) { - return; + for (auto i = 0u; i < 3u; i++) { + if (!CreateBufferPool(allocator, &staging_buffer_pools_[i])) { + return; + } + if (!CreateRenderTargetPool(allocator, &render_target_buffer_pools_[i])) { + return; + } } + allocator_ = allocator; supports_memoryless_textures_ = capabilities.SupportsMemorylessTextures(); is_valid_ = true; @@ -105,9 +111,15 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, AllocatorVK::~AllocatorVK() { TRACE_EVENT0("impeller", "DestroyAllocatorVK"); if (allocator_) { - if (staging_buffer_pool_) { - ::vmaDestroyPool(allocator_, staging_buffer_pool_); + for (auto i = 0u; i < 3u; i++) { + if (staging_buffer_pools_[i]) { + ::vmaDestroyPool(allocator_, staging_buffer_pools_[i]); + } + if (render_target_buffer_pools_[i]) { + ::vmaDestroyPool(allocator_, render_target_buffer_pools_[i]); + } } + ::vmaDestroyAllocator(allocator_); } } @@ -258,6 +270,7 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { AllocatedTextureSourceVK(const TextureDescriptor& desc, VmaAllocator allocator, vk::Device device, + VmaPool pool, bool supports_memoryless_textures) : TextureSourceVK(desc) { TRACE_EVENT0("impeller", "CreateDeviceTexture"); @@ -288,6 +301,15 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { alloc_nfo.usage = ToVMAMemoryUsage(); alloc_nfo.preferredFlags = ToVKTextureMemoryPropertyFlags( desc.storage_mode, supports_memoryless_textures); + if (desc.usage & + static_cast(TextureUsage::kRenderTarget) && !desc.persistent) { + if (desc.storage_mode == StorageMode::kDevicePrivate || + (desc.storage_mode == StorageMode::kDeviceTransient && + !supports_memoryless_textures)) { + alloc_nfo.pool = pool; + use_dedicated = false; + } + } alloc_nfo.flags = ToVmaAllocationCreateFlags(desc.storage_mode, use_dedicated); @@ -393,10 +415,11 @@ std::shared_ptr AllocatorVK::OnCreateTexture( return nullptr; } auto source = std::make_shared( - desc, // - allocator_, // - device_holder->GetDevice(), // - supports_memoryless_textures_ // + desc, // + allocator_, // + device_holder->GetDevice(), // + render_target_buffer_pools_[frame_index_ % 3u], // + supports_memoryless_textures_ // ); if (!source->IsValid()) { return nullptr; @@ -426,7 +449,7 @@ std::shared_ptr AllocatorVK::OnCreateBuffer( ToVKBufferMemoryPropertyFlags(desc.storage_mode); allocation_info.flags = ToVmaAllocationBufferCreateFlags(desc.storage_mode); if (desc.storage_mode == StorageMode::kHostVisible) { - allocation_info.pool = staging_buffer_pool_; + allocation_info.pool = staging_buffer_pools_[frame_index_ % 3u]; } VkBuffer buffer = {}; @@ -480,21 +503,14 @@ bool AllocatorVK::CreateBufferPool(VmaAllocator allocator, VmaPool* pool) { auto result = vk::Result{vmaFindMemoryTypeIndexForBufferInfo( allocator, &buffer_info_native, &allocation_info, &memTypeIndex)}; if (result != vk::Result::eSuccess) { - // We're probably not running on a device with host visible + device local. - // fallback by removing device local bit. - allocation_info.preferredFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - result = vk::Result{vmaFindMemoryTypeIndexForBufferInfo( - allocator, &buffer_info_native, &allocation_info, &memTypeIndex)}; - - if (result != vk::Result::eSuccess) { - VALIDATION_LOG << "Could not find memory type for buffer pool."; - return false; - } + VALIDATION_LOG << "Could not find memory type for buffer pool."; + return false; } VmaPoolCreateInfo pool_create_info = {}; pool_create_info.memoryTypeIndex = memTypeIndex; - pool_create_info.flags = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT; + pool_create_info.flags = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT | + VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT; result = vk::Result{vmaCreatePool(allocator, &pool_create_info, pool)}; if (result != vk::Result::eSuccess) { @@ -504,4 +520,48 @@ bool AllocatorVK::CreateBufferPool(VmaAllocator allocator, VmaPool* pool) { return true; } +bool AllocatorVK::CreateRenderTargetPool(VmaAllocator allocator, + VmaPool* pool) { + vk::ImageCreateInfo image_info; + image_info.flags = {}; + image_info.imageType = vk::ImageType::e2D; + image_info.format = vk::Format::eR8G8B8A8Unorm; + image_info.extent = VkExtent3D{1u, 1u, 1u}; + image_info.samples = vk::SampleCountFlagBits::e1; + image_info.mipLevels = 1u; + image_info.arrayLayers = 1u; + image_info.tiling = vk::ImageTiling::eOptimal; + image_info.initialLayout = vk::ImageLayout::eUndefined; + image_info.usage = + vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst; + image_info.sharingMode = vk::SharingMode::eExclusive; + + auto create_info_native = + static_cast(image_info); + + VmaAllocationCreateInfo allocation_info = {}; + allocation_info.usage = VMA_MEMORY_USAGE_AUTO; + allocation_info.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + uint32_t memTypeIndex; + auto result = vk::Result{vmaFindMemoryTypeIndexForImageInfo( + allocator, &create_info_native, &allocation_info, &memTypeIndex)}; + if (result != vk::Result::eSuccess) { + VALIDATION_LOG << "Could not find memory type for buffer pool."; + return false; + } + + VmaPoolCreateInfo pool_create_info = {}; + pool_create_info.memoryTypeIndex = memTypeIndex; + pool_create_info.flags = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT | + VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT; + + result = vk::Result{vmaCreatePool(allocator, &pool_create_info, pool)}; + if (result != vk::Result::eSuccess) { + VALIDATION_LOG << "Could not create render target pool."; + return false; + } + return true; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/allocator_vk.h b/impeller/renderer/backend/vulkan/allocator_vk.h index b32a9e7c9302b..ccbe0ca4f7633 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.h +++ b/impeller/renderer/backend/vulkan/allocator_vk.h @@ -27,13 +27,18 @@ class AllocatorVK final : public Allocator { fml::RefPtr vk_; VmaAllocator allocator_ = {}; - VmaPool staging_buffer_pool_ = {}; + + // Staging buffer pools. + VmaPool staging_buffer_pools_[3] = {}; + // Render target buffer pools. + VmaPool render_target_buffer_pools_[3] = {}; std::weak_ptr context_; std::weak_ptr device_holder_; ISize max_texture_size_; bool is_valid_ = false; bool supports_memoryless_textures_ = false; + uint32_t frame_index_ = 0u; AllocatorVK(std::weak_ptr context, uint32_t vulkan_api_version, @@ -58,8 +63,15 @@ class AllocatorVK final : public Allocator { // |Allocator| ISize GetMaxTextureSizeSupported() const override; + // |Allocator| + void IncrementFrameIndex() override { + frame_index_ += 1; + } + static bool CreateBufferPool(VmaAllocator allocator, VmaPool* pool); + static bool CreateRenderTargetPool(VmaAllocator allocator, VmaPool* pool); + FML_DISALLOW_COPY_AND_ASSIGN(AllocatorVK); }; diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 25f1ff6890d17..0843a8ada1e81 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -50,6 +50,10 @@ class ContextVK final : public Context, uint64_t GetHash() const { return hash_; } + uint32_t GetFrameIndex() const { + return frame_index_; + } + // |Context| ~ContextVK() override; @@ -163,6 +167,7 @@ class ContextVK final : public Context, std::string device_name_; std::shared_ptr raster_message_loop_; const uint64_t hash_; + uint32_t frame_index_ = 0u; bool is_valid_ = false; diff --git a/impeller/renderer/backend/vulkan/surface_vk.cc b/impeller/renderer/backend/vulkan/surface_vk.cc index ab1100664d470..40222d32e30fe 100644 --- a/impeller/renderer/backend/vulkan/surface_vk.cc +++ b/impeller/renderer/backend/vulkan/surface_vk.cc @@ -31,6 +31,7 @@ std::unique_ptr SurfaceVK::WrapSwapchainImage( msaa_tex_desc.format = swapchain_image->GetPixelFormat(); msaa_tex_desc.size = swapchain_image->GetSize(); msaa_tex_desc.usage = static_cast(TextureUsage::kRenderTarget); + msaa_tex_desc.persistent = !supports_memoryless; std::shared_ptr msaa_tex; if (supports_memoryless || !swapchain_image->HasMSAATexture()) { diff --git a/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc b/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc index 85b39a756699e..31bea4c7f2c04 100644 --- a/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc @@ -389,6 +389,7 @@ bool SwapchainImplVK::Present(const std::shared_ptr& image, } const auto& context = ContextVK::Cast(*context_strong); + context.GetResourceAllocator()->IncrementFrameIndex(); const auto& sync = synchronizers_[current_frame_]; diff --git a/impeller/renderer/render_target.cc b/impeller/renderer/render_target.cc index 46ca72b0a815b..3a392777224f8 100644 --- a/impeller/renderer/render_target.cc +++ b/impeller/renderer/render_target.cc @@ -212,6 +212,7 @@ RenderTarget RenderTarget::CreateOffscreen( ISize size, const std::string& label, AttachmentConfig color_attachment_config, + bool persistent, std::optional stencil_attachment_config) { if (size.IsEmpty()) { return {}; @@ -230,6 +231,7 @@ RenderTarget RenderTarget::CreateOffscreen( color_tex0.size = size; color_tex0.usage = static_cast(TextureUsage::kRenderTarget) | static_cast(TextureUsage::kShaderRead); + color_tex0.persistent = persistent; ColorAttachment color0; color0.clear_color = color_attachment_config.clear_color; @@ -258,6 +260,7 @@ RenderTarget RenderTarget::CreateOffscreenMSAA( ISize size, const std::string& label, AttachmentConfigMSAA color_attachment_config, + bool persistent, std::optional stencil_attachment_config) { if (size.IsEmpty()) { return {}; @@ -280,6 +283,7 @@ RenderTarget RenderTarget::CreateOffscreenMSAA( color0_tex_desc.format = pixel_format; color0_tex_desc.size = size; color0_tex_desc.usage = static_cast(TextureUsage::kRenderTarget); + color0_tex_desc.persistent = persistent; auto color0_msaa_tex = context.GetResourceAllocator()->CreateTexture(color0_tex_desc); diff --git a/impeller/renderer/render_target.h b/impeller/renderer/render_target.h index bc54976a030a8..001e2f59aba9c 100644 --- a/impeller/renderer/render_target.h +++ b/impeller/renderer/render_target.h @@ -58,6 +58,7 @@ class RenderTarget final { ISize size, const std::string& label = "Offscreen", AttachmentConfig color_attachment_config = kDefaultColorAttachmentConfig, + bool persistent = false, std::optional stencil_attachment_config = kDefaultStencilAttachmentConfig); @@ -67,6 +68,7 @@ class RenderTarget final { const std::string& label = "Offscreen MSAA", AttachmentConfigMSAA color_attachment_config = kDefaultColorAttachmentConfigMSAA, + bool persistent = false, std::optional stencil_attachment_config = kDefaultStencilAttachmentConfig); diff --git a/lib/ui/painting/image_decoder_impeller.cc b/lib/ui/painting/image_decoder_impeller.cc index af111c6ff0341..2c3fa11ccd901 100644 --- a/lib/ui/painting/image_decoder_impeller.cc +++ b/lib/ui/painting/image_decoder_impeller.cc @@ -268,6 +268,7 @@ static std::pair, std::string> UnsafeUploadTextureToPrivate( texture_descriptor.size = {image_info.width(), image_info.height()}; texture_descriptor.mip_count = texture_descriptor.size.MipCount(); texture_descriptor.compression_type = impeller::CompressionType::kLossy; + texture_descriptor.persistent = true; auto dest_texture = context->GetResourceAllocator()->CreateTexture(texture_descriptor); @@ -371,6 +372,7 @@ ImageDecoderImpeller::UploadTextureToShared( texture_descriptor.size = {image_info.width(), image_info.height()}; texture_descriptor.mip_count = create_mips ? texture_descriptor.size.MipCount() : 1; + texture_descriptor.persistent = true; auto texture = context->GetResourceAllocator()->CreateTexture(texture_descriptor); From 5f79c521cddca58d25e1a35bdee0e6794e77d9f6 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 7 Jul 2023 11:49:51 -0700 Subject: [PATCH 16/16] ++ --- impeller/entity/entity_pass.cc | 4 ++-- impeller/renderer/backend/vulkan/allocator_vk.cc | 3 ++- impeller/renderer/backend/vulkan/allocator_vk.h | 4 +--- impeller/renderer/backend/vulkan/context_vk.h | 4 +--- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 2006ea9640826..8b901baf97904 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -214,7 +214,7 @@ static EntityPassTarget CreateRenderTarget(ContentContext& renderer, .resolve_storage_mode = StorageMode::kDevicePrivate, .load_action = LoadAction::kDontCare, .store_action = StoreAction::kMultisampleResolve, - .clear_color = clear_color}, // color_attachment_config + .clear_color = clear_color}, // color_attachment_config false, GetDefaultStencilConfig(readable) // stencil_attachment_config ); @@ -228,7 +228,7 @@ static EntityPassTarget CreateRenderTarget(ContentContext& renderer, .load_action = LoadAction::kDontCare, .store_action = StoreAction::kDontCare, .clear_color = clear_color, - }, // color_attachment_config + }, // color_attachment_config false, GetDefaultStencilConfig(readable) // stencil_attachment_config ); diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index 9566e3c5959b6..997fc9f40dab8 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -302,7 +302,8 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { alloc_nfo.preferredFlags = ToVKTextureMemoryPropertyFlags( desc.storage_mode, supports_memoryless_textures); if (desc.usage & - static_cast(TextureUsage::kRenderTarget) && !desc.persistent) { + static_cast(TextureUsage::kRenderTarget) && + !desc.persistent) { if (desc.storage_mode == StorageMode::kDevicePrivate || (desc.storage_mode == StorageMode::kDeviceTransient && !supports_memoryless_textures)) { diff --git a/impeller/renderer/backend/vulkan/allocator_vk.h b/impeller/renderer/backend/vulkan/allocator_vk.h index ccbe0ca4f7633..673ae3dbb0f48 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.h +++ b/impeller/renderer/backend/vulkan/allocator_vk.h @@ -64,9 +64,7 @@ class AllocatorVK final : public Allocator { ISize GetMaxTextureSizeSupported() const override; // |Allocator| - void IncrementFrameIndex() override { - frame_index_ += 1; - } + void IncrementFrameIndex() override { frame_index_ += 1; } static bool CreateBufferPool(VmaAllocator allocator, VmaPool* pool); diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 0843a8ada1e81..5a9aa9d4a2dc5 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -50,9 +50,7 @@ class ContextVK final : public Context, uint64_t GetHash() const { return hash_; } - uint32_t GetFrameIndex() const { - return frame_index_; - } + uint32_t GetFrameIndex() const { return frame_index_; } // |Context| ~ContextVK() override;