mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Switched engine to use buffer collection. (flutter/engine#23488)
The old way of allocating images meant that one would have to make sure that Scenic and Flutter were using exactly the same pixel formats. This patch removes the old image allocation and replaces it with a sysmem API that uses buffer collections instead. This permits a smooth negotiation of formats between the two systems.
This commit is contained in:
parent
a18173a94b
commit
ef98b148e5
@ -93,7 +93,7 @@ class ScopedFrame final : public flutter::CompositorContext::ScopedFrame {
|
||||
"of size: "
|
||||
<< physical_size.width() << "x" << physical_size.height();
|
||||
} else {
|
||||
task.material.SetTexture(*(surface->GetImage()));
|
||||
task.material.SetTexture(surface->GetImageId());
|
||||
}
|
||||
|
||||
frame_surfaces.emplace_back(std::move(surface));
|
||||
|
||||
@ -299,8 +299,8 @@ void FuchsiaExternalViewEmbedder::SubmitFrame(
|
||||
if (layer->second.canvas_spy->DidDrawIntoCanvas()) {
|
||||
const auto& surface_index = frame_surface_indices.find(layer_id);
|
||||
FML_DCHECK(surface_index != frame_surface_indices.end());
|
||||
scenic::Image* surface_image =
|
||||
frame_surfaces[surface_index->second]->GetImage();
|
||||
uint32_t surface_image_id =
|
||||
frame_surfaces[surface_index->second]->GetImageId();
|
||||
|
||||
// Create a new layer if needed for the surface.
|
||||
FML_DCHECK(scenic_layer_index <= scenic_layers_.size());
|
||||
@ -363,7 +363,7 @@ void FuchsiaExternalViewEmbedder::SubmitFrame(
|
||||
layer->second.surface_size.height() * 0.5f, -layer_elevation);
|
||||
scenic_layer.material.SetColor(SK_AlphaOPAQUE, SK_AlphaOPAQUE,
|
||||
SK_AlphaOPAQUE, SK_AlphaOPAQUE - 1);
|
||||
scenic_layer.material.SetTexture(*surface_image);
|
||||
scenic_layer.material.SetTexture(surface_image_id);
|
||||
|
||||
// Only the first (i.e. the bottom-most) layer should receive input.
|
||||
// TODO: Workaround for invisible overlays stealing input. Remove when
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "vulkan_surface.h"
|
||||
|
||||
#include <lib/async/default.h>
|
||||
#include <lib/ui/scenic/cpp/commands.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -15,52 +16,51 @@
|
||||
#include "third_party/skia/include/gpu/GrBackendSurface.h"
|
||||
#include "third_party/skia/include/gpu/GrDirectContext.h"
|
||||
|
||||
#define LOG_AND_RETURN(cond, msg) \
|
||||
if (cond) { \
|
||||
FML_DLOG(ERROR) << msg; \
|
||||
return false; \
|
||||
}
|
||||
|
||||
namespace flutter_runner {
|
||||
|
||||
namespace {
|
||||
|
||||
// Immutable format is technically limited to R8G8B8A8_SRGB but
|
||||
// R8G8B8A8_UNORM works with existing ARM drivers so we allow that
|
||||
// until we have a more reliable API for creating external Vulkan
|
||||
// images using sysmem. TODO(fxb/52835)
|
||||
#if defined(__aarch64__)
|
||||
constexpr SkColorType kSkiaColorType = kRGBA_8888_SkColorType;
|
||||
constexpr fuchsia::images::PixelFormat kPixelFormat =
|
||||
fuchsia::images::PixelFormat::R8G8B8A8;
|
||||
constexpr fuchsia::sysmem::PixelFormatType kSysmemPixelFormat =
|
||||
fuchsia::sysmem::PixelFormatType::R8G8B8A8;
|
||||
constexpr VkFormat kVulkanFormat = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
constexpr VkImageCreateFlags kVulkanImageCreateFlags = 0;
|
||||
#else
|
||||
constexpr SkColorType kSkiaColorType = kBGRA_8888_SkColorType;
|
||||
constexpr fuchsia::images::PixelFormat kPixelFormat =
|
||||
fuchsia::images::PixelFormat::BGRA_8;
|
||||
constexpr VkFormat kVulkanFormat = VK_FORMAT_B8G8R8A8_UNORM;
|
||||
constexpr VkImageCreateFlags kVulkanImageCreateFlags =
|
||||
VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
|
||||
#endif
|
||||
// TODO: We should only keep usages that are actually required by Skia.
|
||||
constexpr VkImageUsageFlags kVkImageUsage =
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
constexpr uint32_t kSysmemImageUsage =
|
||||
fuchsia::sysmem::VULKAN_IMAGE_USAGE_COLOR_ATTACHMENT |
|
||||
fuchsia::sysmem::VULKAN_IMAGE_USAGE_TRANSFER_DST |
|
||||
fuchsia::sysmem::VULKAN_IMAGE_USAGE_TRANSFER_SRC |
|
||||
fuchsia::sysmem::VULKAN_IMAGE_USAGE_SAMPLED;
|
||||
|
||||
} // namespace
|
||||
|
||||
bool CreateVulkanImage(vulkan::VulkanProvider& vulkan_provider,
|
||||
const SkISize& size,
|
||||
VulkanImage* out_vulkan_image) {
|
||||
bool VulkanSurface::CreateVulkanImage(vulkan::VulkanProvider& vulkan_provider,
|
||||
const SkISize& size,
|
||||
VulkanImage* out_vulkan_image) {
|
||||
TRACE_EVENT0("flutter", "CreateVulkanImage");
|
||||
|
||||
FML_DCHECK(!size.isEmpty());
|
||||
FML_DCHECK(out_vulkan_image != nullptr);
|
||||
|
||||
// The image creation parameters need to be the same as those in scenic
|
||||
// (src/ui/scenic/lib/gfx/resources/gpu_image.cc and
|
||||
// src/ui/lib/escher/util/image_utils.cc) or else the different vulkan
|
||||
// devices may interpret the bytes differently.
|
||||
// TODO(SCN-1369): Use API to coordinate this with scenic.
|
||||
out_vulkan_image->vk_external_image_create_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
|
||||
out_vulkan_image->vk_collection_image_create_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA,
|
||||
.pNext = nullptr,
|
||||
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA,
|
||||
.collection = collection_,
|
||||
.index = 0,
|
||||
};
|
||||
|
||||
out_vulkan_image->vk_image_create_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.pNext = &out_vulkan_image->vk_external_image_create_info,
|
||||
.pNext = &out_vulkan_image->vk_collection_image_create_info,
|
||||
.flags = kVulkanImageCreateFlags,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.format = kVulkanFormat,
|
||||
@ -70,18 +70,22 @@ bool CreateVulkanImage(vulkan::VulkanProvider& vulkan_provider,
|
||||
.arrayLayers = 1,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||
.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
.usage = kVkImageUsage,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = nullptr,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
};
|
||||
|
||||
if (VK_CALL_LOG_ERROR(
|
||||
vulkan_provider.vk().SetBufferCollectionConstraintsFUCHSIA(
|
||||
vulkan_provider.vk_device(), collection_,
|
||||
&out_vulkan_image->vk_image_create_info)) != VK_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
VkImage vk_image = VK_NULL_HANDLE;
|
||||
|
||||
if (VK_CALL_LOG_ERROR(vulkan_provider.vk().CreateImage(
|
||||
vulkan_provider.vk_device(),
|
||||
&out_vulkan_image->vk_image_create_info, nullptr, &vk_image)) !=
|
||||
@ -103,35 +107,30 @@ bool CreateVulkanImage(vulkan::VulkanProvider& vulkan_provider,
|
||||
return true;
|
||||
}
|
||||
|
||||
VulkanSurface::VulkanSurface(vulkan::VulkanProvider& vulkan_provider,
|
||||
sk_sp<GrDirectContext> context,
|
||||
scenic::Session* session,
|
||||
const SkISize& size)
|
||||
: vulkan_provider_(vulkan_provider), session_(session), wait_(this) {
|
||||
VulkanSurface::VulkanSurface(
|
||||
vulkan::VulkanProvider& vulkan_provider,
|
||||
fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator,
|
||||
sk_sp<GrDirectContext> context,
|
||||
scenic::Session* session,
|
||||
const SkISize& size,
|
||||
uint32_t buffer_id)
|
||||
: vulkan_provider_(vulkan_provider),
|
||||
session_(session),
|
||||
buffer_id_(buffer_id),
|
||||
wait_(this) {
|
||||
FML_DCHECK(session_);
|
||||
|
||||
zx::vmo exported_vmo;
|
||||
if (!AllocateDeviceMemory(std::move(context), size, exported_vmo)) {
|
||||
if (!AllocateDeviceMemory(sysmem_allocator, std::move(context), size)) {
|
||||
FML_DLOG(INFO) << "Could not allocate device memory.";
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t vmo_size;
|
||||
zx_status_t status = exported_vmo.get_size(&vmo_size);
|
||||
FML_DCHECK(status == ZX_OK);
|
||||
|
||||
if (!CreateFences()) {
|
||||
FML_DLOG(INFO) << "Could not create signal fences.";
|
||||
return;
|
||||
}
|
||||
|
||||
scenic_memory_ = std::make_unique<scenic::Memory>(
|
||||
session, std::move(exported_vmo), vmo_size,
|
||||
fuchsia::images::MemoryType::VK_DEVICE_MEMORY);
|
||||
if (!PushSessionImageSetupOps(session)) {
|
||||
FML_DLOG(INFO) << "Could not push session image setup ops.";
|
||||
return;
|
||||
}
|
||||
PushSessionImageSetupOps(session);
|
||||
|
||||
std::fill(size_history_.begin(), size_history_.end(), SkISize::MakeEmpty());
|
||||
|
||||
@ -226,57 +225,100 @@ bool VulkanSurface::CreateFences() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanSurface::AllocateDeviceMemory(sk_sp<GrDirectContext> context,
|
||||
const SkISize& size,
|
||||
zx::vmo& exported_vmo) {
|
||||
bool VulkanSurface::AllocateDeviceMemory(
|
||||
fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator,
|
||||
sk_sp<GrDirectContext> context,
|
||||
const SkISize& size) {
|
||||
if (size.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VulkanImage vulkan_image;
|
||||
if (!CreateVulkanImage(vulkan_provider_, size, &vulkan_image)) {
|
||||
FML_DLOG(ERROR) << "Failed to create VkImage";
|
||||
fuchsia::sysmem::BufferCollectionTokenSyncPtr local_token;
|
||||
zx_status_t status =
|
||||
sysmem_allocator->AllocateSharedCollection(local_token.NewRequest());
|
||||
LOG_AND_RETURN(status != ZX_OK, "Failed to allocate collection");
|
||||
fuchsia::sysmem::BufferCollectionTokenSyncPtr scenic_token;
|
||||
status = local_token->Duplicate(std::numeric_limits<uint32_t>::max(),
|
||||
scenic_token.NewRequest());
|
||||
LOG_AND_RETURN(status != ZX_OK, "Failed to duplicate token");
|
||||
status = local_token->Sync();
|
||||
LOG_AND_RETURN(status != ZX_OK, "Failed to sync token");
|
||||
fuchsia::sysmem::BufferCollectionTokenSyncPtr vulkan_token;
|
||||
status = local_token->Duplicate(std::numeric_limits<uint32_t>::max(),
|
||||
vulkan_token.NewRequest());
|
||||
LOG_AND_RETURN(status != ZX_OK, "Failed to duplicate token");
|
||||
status = local_token->Sync();
|
||||
LOG_AND_RETURN(status != ZX_OK, "Failed to sync token");
|
||||
|
||||
session_->RegisterBufferCollection(buffer_id_, std::move(scenic_token));
|
||||
|
||||
fuchsia::sysmem::BufferCollectionSyncPtr buffer_collection;
|
||||
status = sysmem_allocator->BindSharedCollection(
|
||||
std::move(local_token), buffer_collection.NewRequest());
|
||||
LOG_AND_RETURN(status != ZX_OK, "Failed to bind collection");
|
||||
|
||||
fuchsia::sysmem::BufferCollectionConstraints constraints;
|
||||
constraints.min_buffer_count = 1;
|
||||
constraints.usage.vulkan = kSysmemImageUsage;
|
||||
|
||||
constraints.image_format_constraints_count = 1;
|
||||
fuchsia::sysmem::ImageFormatConstraints& image_constraints =
|
||||
constraints.image_format_constraints[0];
|
||||
image_constraints = fuchsia::sysmem::ImageFormatConstraints();
|
||||
image_constraints.min_coded_width = size.width();
|
||||
image_constraints.min_coded_height = size.height();
|
||||
image_constraints.max_coded_width = size.width();
|
||||
image_constraints.max_coded_height = size.height();
|
||||
image_constraints.min_bytes_per_row = 0;
|
||||
image_constraints.pixel_format.type = kSysmemPixelFormat;
|
||||
image_constraints.color_spaces_count = 1;
|
||||
image_constraints.color_space[0].type = fuchsia::sysmem::ColorSpaceType::SRGB;
|
||||
|
||||
status = buffer_collection->SetConstraints(true, constraints);
|
||||
LOG_AND_RETURN(status != ZX_OK, "Failed to set constraints");
|
||||
|
||||
VkBufferCollectionCreateInfoFUCHSIA import_info;
|
||||
import_info.collectionToken = vulkan_token.Unbind().TakeChannel().release();
|
||||
if (VK_CALL_LOG_ERROR(vulkan_provider_.vk().CreateBufferCollectionFUCHSIA(
|
||||
vulkan_provider_.vk_device(), &import_info, nullptr, &collection_)) !=
|
||||
VK_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VulkanImage vulkan_image;
|
||||
LOG_AND_RETURN(!CreateVulkanImage(vulkan_provider_, size, &vulkan_image),
|
||||
"Failed to create VkImage");
|
||||
|
||||
status = buffer_collection->Close();
|
||||
LOG_AND_RETURN(status != ZX_OK, "Failed to close collection");
|
||||
|
||||
vulkan_image_ = std::move(vulkan_image);
|
||||
const VkMemoryRequirements& memory_reqs =
|
||||
const VkMemoryRequirements& memory_requirements =
|
||||
vulkan_image_.vk_memory_requirements;
|
||||
const VkImageCreateInfo& image_create_info =
|
||||
vulkan_image_.vk_image_create_info;
|
||||
VkImageCreateInfo& image_create_info = vulkan_image_.vk_image_create_info;
|
||||
|
||||
uint32_t memory_type = 0;
|
||||
for (; memory_type < 32; memory_type++) {
|
||||
if ((memory_reqs.memoryTypeBits & (1 << memory_type))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VkMemoryDedicatedAllocateInfo dedicated_allocate_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
|
||||
VkImportMemoryBufferCollectionFUCHSIA import_memory_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA,
|
||||
.pNext = nullptr,
|
||||
.image = vulkan_image_.vk_image,
|
||||
.buffer = VK_NULL_HANDLE};
|
||||
VkExportMemoryAllocateInfoKHR export_allocate_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
|
||||
.pNext = &dedicated_allocate_info,
|
||||
.handleTypes =
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA};
|
||||
|
||||
const VkMemoryAllocateInfo alloc_info = {
|
||||
.collection = collection_,
|
||||
.index = 0,
|
||||
};
|
||||
auto bits = memory_requirements.memoryTypeBits;
|
||||
FML_DCHECK(bits != 0);
|
||||
VkMemoryAllocateInfo allocation_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = &export_allocate_info,
|
||||
.allocationSize = memory_reqs.size,
|
||||
.memoryTypeIndex = memory_type,
|
||||
.pNext = &import_memory_info,
|
||||
.allocationSize = memory_requirements.size,
|
||||
.memoryTypeIndex = static_cast<uint32_t>(__builtin_ctz(bits)),
|
||||
};
|
||||
|
||||
{
|
||||
TRACE_EVENT1("flutter", "vkAllocateMemory", "allocationSize",
|
||||
alloc_info.allocationSize);
|
||||
allocation_info.allocationSize);
|
||||
VkDeviceMemory vk_memory = VK_NULL_HANDLE;
|
||||
if (VK_CALL_LOG_ERROR(vulkan_provider_.vk().AllocateMemory(
|
||||
vulkan_provider_.vk_device(), &alloc_info, NULL, &vk_memory)) !=
|
||||
VK_SUCCESS) {
|
||||
vulkan_provider_.vk_device(), &allocation_info, NULL,
|
||||
&vk_memory)) != VK_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -286,7 +328,7 @@ bool VulkanSurface::AllocateDeviceMemory(sk_sp<GrDirectContext> context,
|
||||
memory, NULL);
|
||||
}};
|
||||
|
||||
vk_memory_info_ = alloc_info;
|
||||
vk_memory_info_ = allocation_info;
|
||||
}
|
||||
|
||||
// Bind image memory.
|
||||
@ -296,31 +338,8 @@ bool VulkanSurface::AllocateDeviceMemory(sk_sp<GrDirectContext> context,
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
// Acquire the VMO for the device memory.
|
||||
uint32_t vmo_handle = 0;
|
||||
|
||||
VkMemoryGetZirconHandleInfoFUCHSIA get_handle_info = {
|
||||
VK_STRUCTURE_TYPE_TEMP_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA, nullptr,
|
||||
vk_memory_, VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA};
|
||||
if (VK_CALL_LOG_ERROR(vulkan_provider_.vk().GetMemoryZirconHandleFUCHSIA(
|
||||
vulkan_provider_.vk_device(), &get_handle_info, &vmo_handle)) !=
|
||||
VK_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
exported_vmo.reset(static_cast<zx_handle_t>(vmo_handle));
|
||||
}
|
||||
|
||||
// Assert that the VMO size was sufficient.
|
||||
size_t vmo_size = 0;
|
||||
if (exported_vmo.get_size(&vmo_size) != ZX_OK ||
|
||||
vmo_size < memory_reqs.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return SetupSkiaSurface(std::move(context), size, kSkiaColorType,
|
||||
image_create_info, memory_reqs);
|
||||
image_create_info, memory_requirements);
|
||||
}
|
||||
|
||||
bool VulkanSurface::SetupSkiaSurface(sk_sp<GrDirectContext> context,
|
||||
@ -370,89 +389,21 @@ bool VulkanSurface::SetupSkiaSurface(sk_sp<GrDirectContext> context,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanSurface::PushSessionImageSetupOps(scenic::Session* session) {
|
||||
FML_DCHECK(scenic_memory_ != nullptr);
|
||||
|
||||
if (sk_surface_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fuchsia::images::ImageInfo image_info;
|
||||
image_info.width = sk_surface_->width();
|
||||
image_info.height = sk_surface_->height();
|
||||
image_info.stride = 4 * sk_surface_->width();
|
||||
image_info.pixel_format = kPixelFormat;
|
||||
image_info.color_space = fuchsia::images::ColorSpace::SRGB;
|
||||
switch (vulkan_image_.vk_image_create_info.tiling) {
|
||||
case VK_IMAGE_TILING_OPTIMAL:
|
||||
image_info.tiling = fuchsia::images::Tiling::GPU_OPTIMAL;
|
||||
break;
|
||||
case VK_IMAGE_TILING_LINEAR:
|
||||
image_info.tiling = fuchsia::images::Tiling::LINEAR;
|
||||
break;
|
||||
default:
|
||||
FML_DLOG(ERROR) << "Bad image tiling: "
|
||||
<< vulkan_image_.vk_image_create_info.tiling;
|
||||
return false;
|
||||
}
|
||||
|
||||
session_image_ = std::make_unique<scenic::Image>(
|
||||
*scenic_memory_, 0 /* memory offset */, std::move(image_info));
|
||||
|
||||
return session_image_ != nullptr;
|
||||
void VulkanSurface::PushSessionImageSetupOps(scenic::Session* session) {
|
||||
if (image_id_ == 0)
|
||||
image_id_ = session->AllocResourceId();
|
||||
session->Enqueue(scenic::NewCreateImage2Cmd(
|
||||
image_id_, sk_surface_->width(), sk_surface_->height(), buffer_id_, 0));
|
||||
}
|
||||
|
||||
scenic::Image* VulkanSurface::GetImage() {
|
||||
if (!valid_) {
|
||||
return 0;
|
||||
}
|
||||
return session_image_.get();
|
||||
uint32_t VulkanSurface::GetImageId() {
|
||||
return image_id_;
|
||||
}
|
||||
|
||||
sk_sp<SkSurface> VulkanSurface::GetSkiaSurface() const {
|
||||
return valid_ ? sk_surface_ : nullptr;
|
||||
}
|
||||
|
||||
bool VulkanSurface::BindToImage(sk_sp<GrDirectContext> context,
|
||||
VulkanImage vulkan_image) {
|
||||
FML_DCHECK(vulkan_image.vk_memory_requirements.size <=
|
||||
vk_memory_info_.allocationSize);
|
||||
|
||||
vulkan_image_ = std::move(vulkan_image);
|
||||
|
||||
// Bind image memory.
|
||||
if (VK_CALL_LOG_ERROR(vulkan_provider_.vk().BindImageMemory(
|
||||
vulkan_provider_.vk_device(), vulkan_image_.vk_image, vk_memory_,
|
||||
0)) != VK_SUCCESS) {
|
||||
valid_ = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& extent = vulkan_image.vk_image_create_info.extent;
|
||||
auto size = SkISize::Make(extent.width, extent.height);
|
||||
|
||||
if (!SetupSkiaSurface(std::move(context), size, kSkiaColorType,
|
||||
vulkan_image.vk_image_create_info,
|
||||
vulkan_image.vk_memory_requirements)) {
|
||||
FML_DLOG(ERROR) << "Failed to setup skia surface";
|
||||
valid_ = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sk_surface_ == nullptr) {
|
||||
valid_ = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!PushSessionImageSetupOps(session_)) {
|
||||
FML_DLOG(ERROR) << "Could not push session image setup ops.";
|
||||
valid_ = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t VulkanSurface::AdvanceAndGetAge() {
|
||||
size_history_[size_history_index_] = GetSize();
|
||||
size_history_index_ = (size_history_index_ + 1) % kSizeHistorySize;
|
||||
|
||||
@ -37,7 +37,7 @@ class SurfaceProducerSurface {
|
||||
virtual void SignalWritesFinished(
|
||||
const std::function<void(void)>& on_writes_committed) = 0;
|
||||
|
||||
virtual scenic::Image* GetImage() = 0;
|
||||
virtual uint32_t GetImageId() = 0;
|
||||
|
||||
virtual sk_sp<SkSurface> GetSkiaSurface() const = 0;
|
||||
};
|
||||
@ -59,7 +59,7 @@ struct VulkanImage {
|
||||
VulkanImage(VulkanImage&&) = default;
|
||||
VulkanImage& operator=(VulkanImage&&) = default;
|
||||
|
||||
VkExternalMemoryImageCreateInfo vk_external_image_create_info;
|
||||
VkBufferCollectionImageCreateInfoFUCHSIA vk_collection_image_create_info;
|
||||
VkImageCreateInfo vk_image_create_info;
|
||||
VkMemoryRequirements vk_memory_requirements;
|
||||
vulkan::VulkanHandle<VkImage> vk_image;
|
||||
@ -67,19 +67,14 @@ struct VulkanImage {
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(VulkanImage);
|
||||
};
|
||||
|
||||
// Create a new |VulkanImage| of size |size|, stored in
|
||||
// |out_vulkan_image|. Returns whether creation of the |VkImage| was
|
||||
// successful.
|
||||
bool CreateVulkanImage(vulkan::VulkanProvider& vulkan_provider,
|
||||
const SkISize& size,
|
||||
VulkanImage* out_vulkan_image);
|
||||
|
||||
class VulkanSurface final : public SurfaceProducerSurface {
|
||||
public:
|
||||
VulkanSurface(vulkan::VulkanProvider& vulkan_provider,
|
||||
fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator,
|
||||
sk_sp<GrDirectContext> context,
|
||||
scenic::Session* session,
|
||||
const SkISize& size);
|
||||
const SkISize& size,
|
||||
uint32_t buffer_id);
|
||||
|
||||
~VulkanSurface() override;
|
||||
|
||||
@ -101,7 +96,7 @@ class VulkanSurface final : public SurfaceProducerSurface {
|
||||
const std::function<void(void)>& on_writes_committed) override;
|
||||
|
||||
// |SurfaceProducerSurface|
|
||||
scenic::Image* GetImage() override;
|
||||
uint32_t GetImageId() override;
|
||||
|
||||
// |SurfaceProducerSurface|
|
||||
sk_sp<SkSurface> GetSkiaSurface() const override;
|
||||
@ -141,13 +136,6 @@ class VulkanSurface final : public SurfaceProducerSurface {
|
||||
size_history_.begin());
|
||||
}
|
||||
|
||||
// Bind |vulkan_image| to |vk_memory_| and create a new skia surface,
|
||||
// replacing the previous |vk_image_|. |vulkan_image| MUST require less
|
||||
// than or equal the amount of memory contained in |vk_memory_|. Returns
|
||||
// whether the swap was successful. The |VulkanSurface| will become invalid
|
||||
// if the swap was not successful.
|
||||
bool BindToImage(sk_sp<GrDirectContext> context, VulkanImage vulkan_image);
|
||||
|
||||
private:
|
||||
static constexpr int kSizeHistorySize = 4;
|
||||
|
||||
@ -156,9 +144,13 @@ class VulkanSurface final : public SurfaceProducerSurface {
|
||||
zx_status_t status,
|
||||
const zx_packet_signal_t* signal);
|
||||
|
||||
bool AllocateDeviceMemory(sk_sp<GrDirectContext> context,
|
||||
const SkISize& size,
|
||||
zx::vmo& exported_vmo);
|
||||
bool AllocateDeviceMemory(fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator,
|
||||
sk_sp<GrDirectContext> context,
|
||||
const SkISize& size);
|
||||
|
||||
bool CreateVulkanImage(vulkan::VulkanProvider& vulkan_provider,
|
||||
const SkISize& size,
|
||||
VulkanImage* out_vulkan_image);
|
||||
|
||||
bool SetupSkiaSurface(sk_sp<GrDirectContext> context,
|
||||
const SkISize& size,
|
||||
@ -168,7 +160,7 @@ class VulkanSurface final : public SurfaceProducerSurface {
|
||||
|
||||
bool CreateFences();
|
||||
|
||||
bool PushSessionImageSetupOps(scenic::Session* session);
|
||||
void PushSessionImageSetupOps(scenic::Session* session);
|
||||
|
||||
void Reset();
|
||||
|
||||
@ -182,9 +174,9 @@ class VulkanSurface final : public SurfaceProducerSurface {
|
||||
VkMemoryAllocateInfo vk_memory_info_;
|
||||
vulkan::VulkanHandle<VkFence> command_buffer_fence_;
|
||||
sk_sp<SkSurface> sk_surface_;
|
||||
// TODO: Don't heap allocate this once SCN-268 is resolved.
|
||||
std::unique_ptr<scenic::Memory> scenic_memory_;
|
||||
std::unique_ptr<scenic::Image> session_image_;
|
||||
const uint32_t buffer_id_;
|
||||
uint32_t image_id_ = 0;
|
||||
VkBufferCollectionFUCHSIA collection_;
|
||||
zx::event acquire_event_;
|
||||
vulkan::VulkanHandle<VkSemaphore> acquire_semaphore_;
|
||||
std::unique_ptr<vulkan::VulkanCommandBuffer> command_buffer_;
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
|
||||
#include "vulkan_surface_pool.h"
|
||||
|
||||
#include <lib/fdio/directory.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
@ -12,21 +14,17 @@
|
||||
|
||||
namespace flutter_runner {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string ToString(const SkISize& size) {
|
||||
return "{width: " + std::to_string(size.width()) +
|
||||
", height: " + std::to_string(size.height()) + "}";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
VulkanSurfacePool::VulkanSurfacePool(vulkan::VulkanProvider& vulkan_provider,
|
||||
sk_sp<GrDirectContext> context,
|
||||
scenic::Session* scenic_session)
|
||||
: vulkan_provider_(vulkan_provider),
|
||||
context_(std::move(context)),
|
||||
scenic_session_(scenic_session) {}
|
||||
scenic_session_(scenic_session) {
|
||||
zx_status_t status = fdio_service_connect(
|
||||
"/svc/fuchsia.sysmem.Allocator",
|
||||
sysmem_allocator_.NewRequest().TakeChannel().release());
|
||||
FML_DCHECK(status != ZX_OK);
|
||||
}
|
||||
|
||||
VulkanSurfacePool::~VulkanSurfacePool() {}
|
||||
|
||||
@ -66,49 +64,7 @@ std::unique_ptr<VulkanSurface> VulkanSurfacePool::GetCachedOrCreateSurface(
|
||||
}
|
||||
}
|
||||
|
||||
// Then, look for a surface that has enough |VkDeviceMemory| to hold a
|
||||
// |VkImage| of size |size|, but is currently holding a |VkImage| of a
|
||||
// different size.
|
||||
VulkanImage vulkan_image;
|
||||
if (!CreateVulkanImage(vulkan_provider_, size, &vulkan_image)) {
|
||||
FML_DLOG(ERROR) << "Failed to create a VkImage of size: " << ToString(size);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto best_it = available_surfaces_.end();
|
||||
for (auto it = available_surfaces_.begin(); it != available_surfaces_.end();
|
||||
++it) {
|
||||
const auto& surface = *it;
|
||||
if (!surface->IsValid() || surface->GetAllocationSize() <
|
||||
vulkan_image.vk_memory_requirements.size) {
|
||||
continue;
|
||||
}
|
||||
if (best_it == available_surfaces_.end() ||
|
||||
surface->GetAllocationSize() < (*best_it)->GetAllocationSize()) {
|
||||
best_it = it;
|
||||
}
|
||||
}
|
||||
|
||||
// If no such surface exists, then create a new one.
|
||||
if (best_it == available_surfaces_.end()) {
|
||||
TRACE_EVENT_INSTANT0("flutter", "No available surfaces");
|
||||
return CreateSurface(size);
|
||||
}
|
||||
|
||||
auto acquired_surface = std::move(*best_it);
|
||||
available_surfaces_.erase(best_it);
|
||||
bool swap_succeeded =
|
||||
acquired_surface->BindToImage(context_, std::move(vulkan_image));
|
||||
if (!swap_succeeded) {
|
||||
FML_DLOG(ERROR) << "Failed to swap VulkanSurface to new VkImage of size: "
|
||||
<< ToString(size);
|
||||
TRACE_EVENT_INSTANT0("flutter", "failed to swap, making new");
|
||||
return CreateSurface(size);
|
||||
}
|
||||
TRACE_EVENT_INSTANT0("flutter", "Using differently sized image");
|
||||
FML_DCHECK(acquired_surface->IsValid());
|
||||
trace_surfaces_reused_++;
|
||||
return acquired_surface;
|
||||
return CreateSurface(size);
|
||||
}
|
||||
|
||||
void VulkanSurfacePool::SubmitSurface(
|
||||
@ -140,8 +96,9 @@ std::unique_ptr<VulkanSurface> VulkanSurfacePool::CreateSurface(
|
||||
const SkISize& size) {
|
||||
TRACE_EVENT2("flutter", "VulkanSurfacePool::CreateSurface", "width",
|
||||
size.width(), "height", size.height());
|
||||
auto surface = std::make_unique<VulkanSurface>(vulkan_provider_, context_,
|
||||
scenic_session_, size);
|
||||
auto surface = std::make_unique<VulkanSurface>(
|
||||
vulkan_provider_, sysmem_allocator_, context_, scenic_session_, size,
|
||||
buffer_id_++);
|
||||
if (!surface->IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -41,9 +41,11 @@ class VulkanSurfacePool final {
|
||||
vulkan::VulkanProvider& vulkan_provider_;
|
||||
sk_sp<GrDirectContext> context_;
|
||||
scenic::Session* scenic_session_;
|
||||
fuchsia::sysmem::AllocatorSyncPtr sysmem_allocator_;
|
||||
std::vector<std::unique_ptr<VulkanSurface>> available_surfaces_;
|
||||
std::unordered_map<uintptr_t, std::unique_ptr<VulkanSurface>>
|
||||
pending_surfaces_;
|
||||
uint32_t buffer_id_ = 1;
|
||||
|
||||
size_t trace_surfaces_created_ = 0;
|
||||
size_t trace_surfaces_reused_ = 0;
|
||||
|
||||
@ -69,6 +69,7 @@ VulkanDevice::VulkanDevice(VulkanProcTable& p_vk,
|
||||
VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
|
||||
VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
|
||||
VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
|
||||
VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -137,8 +137,10 @@ bool VulkanProcTable::SetupDeviceProcAddresses(
|
||||
ACQUIRE_PROC(QueuePresentKHR, handle);
|
||||
#endif // OS_ANDROID
|
||||
#if OS_FUCHSIA
|
||||
ACQUIRE_PROC(CreateBufferCollectionFUCHSIA, handle);
|
||||
ACQUIRE_PROC(GetMemoryZirconHandleFUCHSIA, handle);
|
||||
ACQUIRE_PROC(ImportSemaphoreZirconHandleFUCHSIA, handle);
|
||||
ACQUIRE_PROC(SetBufferCollectionConstraintsFUCHSIA, handle);
|
||||
#endif // OS_FUCHSIA
|
||||
device_ = {handle, nullptr};
|
||||
return true;
|
||||
|
||||
@ -115,8 +115,10 @@ class VulkanProcTable : public fml::RefCountedThreadSafe<VulkanProcTable> {
|
||||
DEFINE_PROC(CreateAndroidSurfaceKHR);
|
||||
#endif // OS_ANDROID
|
||||
#if OS_FUCHSIA
|
||||
DEFINE_PROC(CreateBufferCollectionFUCHSIA);
|
||||
DEFINE_PROC(GetMemoryZirconHandleFUCHSIA);
|
||||
DEFINE_PROC(ImportSemaphoreZirconHandleFUCHSIA);
|
||||
DEFINE_PROC(SetBufferCollectionConstraintsFUCHSIA);
|
||||
#endif // OS_FUCHSIA
|
||||
|
||||
#undef DEFINE_PROC
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user