mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
205 lines
6.7 KiB
C++
205 lines
6.7 KiB
C++
// Copyright 2017 The Chromium 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 "flutter/content_handler/vulkan_surface_producer.h"
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
#include "flutter/glue/trace_event.h"
|
|
#include "third_party/skia/include/gpu/GrBackendSemaphore.h"
|
|
#include "third_party/skia/include/gpu/GrContext.h"
|
|
#include "third_party/skia/include/gpu/vk/GrVkTypes.h"
|
|
#include "third_party/skia/src/gpu/vk/GrVkUtil.h"
|
|
|
|
namespace flutter_runner {
|
|
|
|
VulkanSurfaceProducer::VulkanSurfaceProducer(
|
|
scenic_lib::Session* mozart_session) {
|
|
valid_ = Initialize(mozart_session);
|
|
|
|
if (valid_) {
|
|
FXL_LOG(INFO)
|
|
<< "Flutter engine: Vulkan surface producer initialization: Successful";
|
|
} else {
|
|
FXL_LOG(ERROR)
|
|
<< "Flutter engine: Vulkan surface producer initialization: Failed";
|
|
}
|
|
}
|
|
|
|
VulkanSurfaceProducer::~VulkanSurfaceProducer() {
|
|
// Make sure queue is idle before we start destroying surfaces
|
|
VkResult wait_result =
|
|
VK_CALL_LOG_ERROR(vk_->QueueWaitIdle(backend_context_->fQueue));
|
|
FXL_DCHECK(wait_result == VK_SUCCESS);
|
|
};
|
|
|
|
bool VulkanSurfaceProducer::Initialize(scenic_lib::Session* mozart_session) {
|
|
vk_ = fxl::MakeRefCounted<vulkan::VulkanProcTable>();
|
|
|
|
std::vector<std::string> extensions = {
|
|
VK_KHR_SURFACE_EXTENSION_NAME,
|
|
VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME,
|
|
};
|
|
application_ = std::make_unique<vulkan::VulkanApplication>(
|
|
*vk_, "FlutterContentHandler", std::move(extensions));
|
|
|
|
if (!application_->IsValid() || !vk_->AreInstanceProcsSetup()) {
|
|
// Make certain the application instance was created and it setup the
|
|
// instance proc table entries.
|
|
FXL_LOG(ERROR) << "Instance proc addresses have not been setup.";
|
|
return false;
|
|
}
|
|
|
|
// Create the device.
|
|
|
|
logical_device_ = application_->AcquireFirstCompatibleLogicalDevice();
|
|
|
|
if (logical_device_ == nullptr || !logical_device_->IsValid() ||
|
|
!vk_->AreDeviceProcsSetup()) {
|
|
// Make certain the device was created and it setup the device proc table
|
|
// entries.
|
|
FXL_LOG(ERROR) << "Device proc addresses have not been setup.";
|
|
return false;
|
|
}
|
|
|
|
if (!vk_->HasAcquiredMandatoryProcAddresses()) {
|
|
FXL_LOG(ERROR) << "Failed to acquire mandatory proc addresses.";
|
|
return false;
|
|
}
|
|
|
|
if (!vk_->IsValid()) {
|
|
FXL_LOG(ERROR) << "VulkanProcTable invalid";
|
|
return false;
|
|
}
|
|
|
|
auto interface = vk_->CreateSkiaInterface();
|
|
|
|
if (interface == nullptr || !interface->validate(0)) {
|
|
FXL_LOG(ERROR) << "Skia interface invalid.";
|
|
return false;
|
|
}
|
|
|
|
uint32_t skia_features = 0;
|
|
if (!logical_device_->GetPhysicalDeviceFeaturesSkia(&skia_features)) {
|
|
FXL_LOG(ERROR) << "Failed to get physical device features.";
|
|
|
|
return false;
|
|
}
|
|
|
|
backend_context_ = sk_make_sp<GrVkBackendContext>();
|
|
backend_context_->fInstance = application_->GetInstance();
|
|
backend_context_->fPhysicalDevice =
|
|
logical_device_->GetPhysicalDeviceHandle();
|
|
backend_context_->fDevice = logical_device_->GetHandle();
|
|
backend_context_->fQueue = logical_device_->GetQueueHandle();
|
|
backend_context_->fGraphicsQueueIndex =
|
|
logical_device_->GetGraphicsQueueIndex();
|
|
backend_context_->fMinAPIVersion = application_->GetAPIVersion();
|
|
backend_context_->fFeatures = skia_features;
|
|
backend_context_->fInterface.reset(interface.release());
|
|
|
|
logical_device_->ReleaseDeviceOwnership();
|
|
application_->ReleaseInstanceOwnership();
|
|
|
|
context_ = GrContext::MakeVulkan(backend_context_);
|
|
|
|
context_->setResourceCacheLimits(vulkan::kGrCacheMaxCount,
|
|
vulkan::kGrCacheMaxByteSize);
|
|
|
|
surface_pool_ = std::make_unique<VulkanSurfacePool>(
|
|
*this, context_, backend_context_, mozart_session);
|
|
|
|
return true;
|
|
}
|
|
|
|
void VulkanSurfaceProducer::OnSurfacesPresented(
|
|
std::vector<
|
|
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>>
|
|
surfaces) {
|
|
TRACE_EVENT0("flutter", "VulkanSurfaceProducer::OnSurfacesPresented");
|
|
|
|
// Do a single flush for all canvases derived from the context.
|
|
{
|
|
TRACE_EVENT0("flutter", "GrContext::flushAndSignalSemaphores");
|
|
context_->flush();
|
|
}
|
|
|
|
if (!TransitionSurfacesToExternal(surfaces))
|
|
FXL_LOG(ERROR) << "TransitionSurfacesToExternal failed";
|
|
|
|
// Submit surface
|
|
for (auto& surface : surfaces) {
|
|
SubmitSurface(std::move(surface));
|
|
}
|
|
|
|
// Buffer management.
|
|
surface_pool_->AgeAndCollectOldBuffers();
|
|
}
|
|
|
|
bool VulkanSurfaceProducer::TransitionSurfacesToExternal(
|
|
const std::vector<
|
|
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>>&
|
|
surfaces) {
|
|
for (auto& surface : surfaces) {
|
|
auto vk_surface = static_cast<VulkanSurface*>(surface.get());
|
|
|
|
vulkan::VulkanCommandBuffer* command_buffer =
|
|
vk_surface->GetCommandBuffer(logical_device_->GetCommandPool());
|
|
if (!command_buffer->Begin())
|
|
return false;
|
|
|
|
GrVkImageInfo* imageInfo;
|
|
vk_surface->GetSkiaSurface()->getRenderTargetHandle(
|
|
reinterpret_cast<GrBackendObject*>(&imageInfo),
|
|
SkSurface::kFlushRead_BackendHandleAccess);
|
|
|
|
VkImageMemoryBarrier image_barrier = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
.pNext = nullptr,
|
|
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
.dstAccessMask = 0,
|
|
.oldLayout = imageInfo->fImageLayout,
|
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
.srcQueueFamilyIndex = 0,
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL_KHR,
|
|
.image = vk_surface->GetVkImage(),
|
|
.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};
|
|
|
|
if (!command_buffer->InsertPipelineBarrier(
|
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
|
0, // dependencyFlags
|
|
0, nullptr, // memory barriers
|
|
0, nullptr, // buffer barriers
|
|
1, &image_barrier))
|
|
return false;
|
|
|
|
imageInfo->updateImageLayout(image_barrier.newLayout);
|
|
|
|
if (!command_buffer->End())
|
|
return false;
|
|
|
|
if (!logical_device_->QueueSubmit(
|
|
{}, {}, {vk_surface->GetAcquireVkSemaphore()},
|
|
{command_buffer->Handle()}, vk_surface->GetCommandBufferFence()))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>
|
|
VulkanSurfaceProducer::ProduceSurface(const SkISize& size) {
|
|
FXL_DCHECK(valid_);
|
|
return surface_pool_->AcquireSurface(size);
|
|
}
|
|
|
|
void VulkanSurfaceProducer::SubmitSurface(
|
|
std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface> surface) {
|
|
FXL_DCHECK(valid_ && surface != nullptr);
|
|
surface_pool_->SubmitSurface(std::move(surface));
|
|
}
|
|
|
|
} // namespace flutter_runner
|