mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
DX-939 #progress MA-394 #progress This informs the vulkan driver that we're creating an image that will be backed by external memory. The driver driver can decide to use different memory requirements based on the if memory for the image can be exported or not. No change in behavior. Existing tests (modular_tests, scenic_tests, etc.) are sufficient and regressions will be prevented by running these tests on aemu. Test: fx shell run fuchsia-pkg://fuchsia.com/basemgr#meta/basemgr.cmx --base_shell=fuchsia-pkg://fuchsia.com/spinning_cube# Change-Id: I489318c2e31f752f76c80a81245e203861d44d94 Ported from Topaz tree.
213 lines
7.6 KiB
C++
213 lines
7.6 KiB
C++
// 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 <lib/async/cpp/wait.h>
|
|
#include <lib/zx/event.h>
|
|
#include <lib/zx/vmo.h>
|
|
|
|
#include <array>
|
|
#include <memory>
|
|
|
|
#include "flutter/flow/raster_cache_key.h"
|
|
#include "flutter/flow/scene_update_context.h"
|
|
#include "flutter/fml/macros.h"
|
|
#include "flutter/vulkan/vulkan_command_buffer.h"
|
|
#include "flutter/vulkan/vulkan_handle.h"
|
|
#include "flutter/vulkan/vulkan_proc_table.h"
|
|
#include "flutter/vulkan/vulkan_provider.h"
|
|
#include "lib/ui/scenic/cpp/resources.h"
|
|
#include "third_party/skia/include/core/SkSurface.h"
|
|
|
|
namespace flutter_runner {
|
|
|
|
// A |VkImage| and its relevant metadata.
|
|
struct VulkanImage {
|
|
VulkanImage() = default;
|
|
VulkanImage(VulkanImage&&) = default;
|
|
VulkanImage& operator=(VulkanImage&&) = default;
|
|
|
|
VkExternalMemoryImageCreateInfo vk_external_image_create_info;
|
|
VkImageCreateInfo vk_image_create_info;
|
|
VkMemoryRequirements vk_memory_requirements;
|
|
vulkan::VulkanHandle<VkImage> vk_image;
|
|
|
|
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 flutter::SceneUpdateContext::SurfaceProducerSurface {
|
|
public:
|
|
VulkanSurface(vulkan::VulkanProvider& vulkan_provider,
|
|
sk_sp<GrContext> context,
|
|
scenic::Session* session,
|
|
const SkISize& size);
|
|
|
|
~VulkanSurface() override;
|
|
|
|
// |flutter::SceneUpdateContext::SurfaceProducerSurface|
|
|
size_t AdvanceAndGetAge() override;
|
|
|
|
// |flutter::SceneUpdateContext::SurfaceProducerSurface|
|
|
bool FlushSessionAcquireAndReleaseEvents() override;
|
|
|
|
// |flutter::SceneUpdateContext::SurfaceProducerSurface|
|
|
bool IsValid() const override;
|
|
|
|
// |flutter::SceneUpdateContext::SurfaceProducerSurface|
|
|
SkISize GetSize() const override;
|
|
|
|
// Note: It is safe for the caller to collect the surface in the
|
|
// |on_writes_committed| callback.
|
|
void SignalWritesFinished(
|
|
std::function<void(void)> on_writes_committed) override;
|
|
|
|
// |flutter::SceneUpdateContext::SurfaceProducerSurface|
|
|
scenic::Image* GetImage() override;
|
|
|
|
// |flutter::SceneUpdateContext::SurfaceProducerSurface|
|
|
sk_sp<SkSurface> GetSkiaSurface() const override;
|
|
|
|
const vulkan::VulkanHandle<VkImage>& GetVkImage() {
|
|
return vulkan_image_.vk_image;
|
|
}
|
|
|
|
const vulkan::VulkanHandle<VkSemaphore>& GetAcquireVkSemaphore() {
|
|
return acquire_semaphore_;
|
|
}
|
|
|
|
vulkan::VulkanCommandBuffer* GetCommandBuffer(
|
|
const vulkan::VulkanHandle<VkCommandPool>& pool) {
|
|
if (!command_buffer_)
|
|
command_buffer_ = std::make_unique<vulkan::VulkanCommandBuffer>(
|
|
vulkan_provider_.vk(), vulkan_provider_.vk_device(), pool);
|
|
return command_buffer_.get();
|
|
}
|
|
|
|
const vulkan::VulkanHandle<VkFence>& GetCommandBufferFence() {
|
|
return command_buffer_fence_;
|
|
}
|
|
|
|
size_t GetAllocationSize() const { return vk_memory_info_.allocationSize; }
|
|
|
|
size_t GetImageMemoryRequirementsSize() const {
|
|
return vulkan_image_.vk_memory_requirements.size;
|
|
}
|
|
|
|
bool IsOversized() const {
|
|
return GetAllocationSize() > GetImageMemoryRequirementsSize();
|
|
}
|
|
|
|
bool HasStableSizeHistory() const {
|
|
return std::equal(size_history_.begin() + 1, size_history_.end(),
|
|
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<GrContext> context, VulkanImage vulkan_image);
|
|
|
|
// Flutter may retain a |VulkanSurface| for a |flutter::Layer| subtree to
|
|
// improve the performance. The |retained_key_| identifies which layer subtree
|
|
// this |VulkanSurface| is retained for. The key has two parts. One is the
|
|
// pointer to the root of that layer subtree: |retained_key_.id()|. Another is
|
|
// the transformation matrix: |retained_key_.matrix()|. We need the matrix
|
|
// part because a different matrix would invalidate the pixels (raster cache)
|
|
// in this |VulkanSurface|.
|
|
const flutter::LayerRasterCacheKey& GetRetainedKey() const {
|
|
return retained_key_;
|
|
}
|
|
|
|
// For better safety in retained rendering, Flutter uses a retained
|
|
// |EntityNode| associated with the retained surface instead of using the
|
|
// retained surface directly. Hence Flutter can't modify the surface during
|
|
// retained rendering.
|
|
const scenic::EntityNode& GetRetainedNode() {
|
|
used_in_retained_rendering_ = true;
|
|
return *retained_node_;
|
|
}
|
|
|
|
// Check whether the retained surface (and its associated |EntityNode|) is
|
|
// used in the current frame or not. If unused, the |VulkanSurfacePool| will
|
|
// try to recycle the surface. This flag is reset after each frame.
|
|
bool IsUsedInRetainedRendering() const { return used_in_retained_rendering_; }
|
|
void ResetIsUsedInRetainedRendering() { used_in_retained_rendering_ = false; }
|
|
|
|
// Let this surface own the retained EntityNode associated with it (see
|
|
// |GetRetainedNode|), and set the retained key (see |GetRetainedKey|).
|
|
void SetRetainedInfo(const flutter::LayerRasterCacheKey& key,
|
|
std::unique_ptr<scenic::EntityNode> node) {
|
|
retained_key_ = key;
|
|
retained_node_ = std::move(node);
|
|
}
|
|
|
|
private:
|
|
static constexpr int kSizeHistorySize = 4;
|
|
|
|
void OnHandleReady(async_dispatcher_t* dispatcher,
|
|
async::WaitBase* wait,
|
|
zx_status_t status,
|
|
const zx_packet_signal_t* signal);
|
|
|
|
bool AllocateDeviceMemory(sk_sp<GrContext> context,
|
|
const SkISize& size,
|
|
zx::vmo& exported_vmo);
|
|
|
|
bool SetupSkiaSurface(sk_sp<GrContext> context,
|
|
const SkISize& size,
|
|
SkColorType color_type,
|
|
const VkImageCreateInfo& image_create_info,
|
|
const VkMemoryRequirements& memory_reqs);
|
|
|
|
bool CreateFences();
|
|
|
|
bool PushSessionImageSetupOps(scenic::Session* session);
|
|
|
|
void Reset();
|
|
|
|
vulkan::VulkanHandle<VkSemaphore> SemaphoreFromEvent(
|
|
const zx::event& event) const;
|
|
|
|
vulkan::VulkanProvider& vulkan_provider_;
|
|
scenic::Session* session_;
|
|
VulkanImage vulkan_image_;
|
|
vulkan::VulkanHandle<VkDeviceMemory> vk_memory_;
|
|
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_;
|
|
zx::event acquire_event_;
|
|
vulkan::VulkanHandle<VkSemaphore> acquire_semaphore_;
|
|
std::unique_ptr<vulkan::VulkanCommandBuffer> command_buffer_;
|
|
zx::event release_event_;
|
|
async::WaitMethod<VulkanSurface, &VulkanSurface::OnHandleReady> wait_;
|
|
std::function<void()> pending_on_writes_committed_;
|
|
std::array<SkISize, kSizeHistorySize> size_history_;
|
|
int size_history_index_ = 0;
|
|
size_t age_ = 0;
|
|
bool valid_ = false;
|
|
|
|
flutter::LayerRasterCacheKey retained_key_ = {0, SkMatrix::MakeScale(1, 1)};
|
|
std::unique_ptr<scenic::EntityNode> retained_node_ = nullptr;
|
|
|
|
std::atomic<bool> used_in_retained_rendering_ = {false};
|
|
|
|
FML_DISALLOW_COPY_AND_ASSIGN(VulkanSurface);
|
|
};
|
|
|
|
} // namespace flutter_runner
|