Skip to content

Commit 912825c

Browse files
authored
[Tizen] Support render texture for vulkan + impeller (#17)
Add new struct FlutterVulkanTexture for embedder : ``` typedef struct { /// Handle to the VkImage that is owned by the embedder. The engine will /// bind this image for writing the frame. FlutterVulkanImageHandle image; /// The VkDeviceMemory that backs the iamge. FlutterVulkanDeviceMemoryHandle image_memory; /// The VkFormat of the image (for example: VK_FORMAT_R8G8B8A8_UNORM). uint32_t format; /// User data to be returned on the invocation of the destruction callback. void* user_data; /// Callback invoked (on an engine managed thread) that asks the embedder to /// collect the texture. VoidCallback destruction_callback; /// Optional parameters for texture height/width, default is 0, non-zero means /// the texture has the specified width/height. /// Width of the texture. size_t width; /// Height of the texture. size_t height; } FlutterVulkanTexture; ``` The implement of [texture source](https://github.com/flutter-tizen/flutter/pull/17/files#diff-7955a8522a753162869f2e8ca0017a83f4854b60800c844202e70c3aa00ff0c9R5-R204) refer to the solution of android platform(https://github.com/flutter-tizen/flutter/blob/flutter-3.35.3/engine/src/flutter/impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.cc) and I have submitted the code [Support render texture for embedder](xiaowei-guan/embedder@6a94746), I will create a new PR after[ support vulkan backend](flutter-tizen/embedder#110) PR released.
1 parent 8242a0c commit 912825c

9 files changed

+627
-1
lines changed

engine/src/flutter/shell/platform/embedder/BUILD.gn

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ template("embedder_source_set") {
167167

168168
if (embedder_enable_vulkan) {
169169
sources += [
170+
"embedder_external_texture_vulkan.cc",
171+
"embedder_external_texture_vulkan.h",
170172
"embedder_surface_vulkan.cc",
171173
"embedder_surface_vulkan.h",
172174
]
@@ -175,6 +177,8 @@ template("embedder_source_set") {
175177
sources += [
176178
"embedder_surface_vulkan_impeller.cc",
177179
"embedder_surface_vulkan_impeller.h",
180+
"embedder_external_texture_source_vulkan.cc",
181+
"embedder_external_texture_source_vulkan.h",
178182
]
179183
}
180184

engine/src/flutter/shell/platform/embedder/embedder.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2342,6 +2342,27 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
23422342
external_texture_metal_callback);
23432343
}
23442344
}
2345+
#endif
2346+
#ifdef SHELL_ENABLE_VULKAN
2347+
if (config->type == kVulkan) {
2348+
const FlutterVulkanRendererConfig* vulkan_config = &config->vulkan;
2349+
if (auto callback = SAFE_ACCESS(vulkan_config,
2350+
external_texture_frame_callback, nullptr)) {
2351+
auto external_texture_vulkan_callback =
2352+
[ptr = callback, user_data](
2353+
int64_t texture_identifier, size_t width,
2354+
size_t height) -> std::unique_ptr<FlutterVulkanTexture> {
2355+
std::unique_ptr<FlutterVulkanTexture> texture =
2356+
std::make_unique<FlutterVulkanTexture>();
2357+
if (!ptr(user_data, texture_identifier, width, height, texture.get())) {
2358+
return nullptr;
2359+
}
2360+
return texture;
2361+
};
2362+
external_texture_resolver = std::make_unique<ExternalTextureResolver>(
2363+
external_texture_vulkan_callback);
2364+
}
2365+
}
23452366
#endif
23462367
auto custom_task_runners = SAFE_ACCESS(args, custom_task_runners, nullptr);
23472368
auto thread_config_callback = [&custom_task_runners](

engine/src/flutter/shell/platform/embedder/embedder.h

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,9 @@ typedef void* FlutterVulkanQueueHandle;
924924
/// Alias for VkImage.
925925
typedef uint64_t FlutterVulkanImageHandle;
926926

927+
/// Alias for VkDeviceMemory.
928+
typedef uint64_t FlutterVulkanDeviceMemoryHandle;
929+
927930
typedef struct {
928931
/// The size of this struct. Must be sizeof(FlutterVulkanImage).
929932
size_t struct_size;
@@ -952,6 +955,36 @@ typedef bool (*FlutterVulkanPresentCallback)(
952955
void* /* user data */,
953956
const FlutterVulkanImage* /* image */);
954957

958+
typedef struct {
959+
/// Handle to the VkImage that is owned by the embedder. The engine will
960+
/// bind this image for writing the frame.
961+
FlutterVulkanImageHandle image;
962+
/// The VkDeviceMemory that backs the iamge.
963+
FlutterVulkanDeviceMemoryHandle image_memory;
964+
/// The VkFormat of the image (for example: VK_FORMAT_R8G8B8A8_UNORM).
965+
uint32_t format;
966+
/// User data to be returned on the invocation of the destruction callback.
967+
void* user_data;
968+
/// Callback invoked (on an engine managed thread) that asks the embedder to
969+
/// collect the texture.
970+
VoidCallback destruction_callback;
971+
/// Optional parameters for texture height/width, default is 0, non-zero means
972+
/// the texture has the specified width/height.
973+
/// Width of the texture.
974+
size_t width;
975+
/// Height of the texture.
976+
size_t height;
977+
} FlutterVulkanTexture;
978+
979+
/// Callback to provide an external texture for a given texture_id.
980+
/// See: external_texture_frame_callback.
981+
typedef bool (*FlutterVulkanTextureFrameCallback)(
982+
void* /* user data */,
983+
int64_t /* texture identifier */,
984+
size_t /* width */,
985+
size_t /* height */,
986+
FlutterVulkanTexture* /* texture out */);
987+
955988
typedef struct {
956989
/// The size of this struct. Must be sizeof(FlutterVulkanRendererConfig).
957990
size_t struct_size;
@@ -1015,7 +1048,11 @@ typedef struct {
10151048
/// without any additional synchronization.
10161049
/// Not used if a FlutterCompositor is supplied in FlutterProjectArgs.
10171050
FlutterVulkanPresentCallback present_image_callback;
1018-
1051+
/// When the embedder specifies that a texture has a frame available, the
1052+
/// engine will call this method (on an internal engine managed thread) so
1053+
/// that external texture details can be supplied to the engine for subsequent
1054+
/// composition.
1055+
FlutterVulkanTextureFrameCallback external_texture_frame_callback;
10191056
} FlutterVulkanRendererConfig;
10201057

10211058
typedef struct {

engine/src/flutter/shell/platform/embedder/embedder_external_texture_resolver.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ EmbedderExternalTextureResolver::EmbedderExternalTextureResolver(
2121
: metal_callback_(std::move(metal_callback)) {}
2222
#endif
2323

24+
#ifdef SHELL_ENABLE_VULKAN
25+
EmbedderExternalTextureResolver::EmbedderExternalTextureResolver(
26+
EmbedderExternalTextureVulkan::ExternalTextureCallback vulkan_callback)
27+
: vulkan_callback_(std::move(vulkan_callback)) {}
28+
#endif
29+
2430
std::unique_ptr<Texture>
2531
EmbedderExternalTextureResolver::ResolveExternalTexture(int64_t texture_id) {
2632
#ifdef SHELL_ENABLE_GL
@@ -37,6 +43,13 @@ EmbedderExternalTextureResolver::ResolveExternalTexture(int64_t texture_id) {
3743
}
3844
#endif
3945

46+
#ifdef SHELL_ENABLE_VULKAN
47+
if (vulkan_callback_) {
48+
return std::make_unique<EmbedderExternalTextureVulkan>(texture_id,
49+
vulkan_callback_);
50+
}
51+
#endif
52+
4053
return nullptr;
4154
}
4255

@@ -53,6 +66,12 @@ bool EmbedderExternalTextureResolver::SupportsExternalTextures() {
5366
}
5467
#endif
5568

69+
#ifdef SHELL_ENABLE_VULKAN
70+
if (vulkan_callback_) {
71+
return true;
72+
}
73+
#endif
74+
5675
return false;
5776
}
5877

engine/src/flutter/shell/platform/embedder/embedder_external_texture_resolver.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
#include "flutter/shell/platform/embedder/embedder_external_texture_metal.h"
1818
#endif
1919

20+
#ifdef SHELL_ENABLE_VULKAN
21+
#include "flutter/shell/platform/embedder/embedder_external_texture_vulkan.h"
22+
#endif
23+
2024
namespace flutter {
2125
class EmbedderExternalTextureResolver {
2226
public:
@@ -34,6 +38,11 @@ class EmbedderExternalTextureResolver {
3438
EmbedderExternalTextureMetal::ExternalTextureCallback metal_callback);
3539
#endif
3640

41+
#ifdef SHELL_ENABLE_VULKAN
42+
explicit EmbedderExternalTextureResolver(
43+
EmbedderExternalTextureVulkan::ExternalTextureCallback vulkan_callback);
44+
#endif
45+
3746
std::unique_ptr<Texture> ResolveExternalTexture(int64_t texture_id);
3847

3948
bool SupportsExternalTextures();
@@ -47,6 +56,9 @@ class EmbedderExternalTextureResolver {
4756
EmbedderExternalTextureMetal::ExternalTextureCallback metal_callback_;
4857
#endif
4958

59+
#ifdef SHELL_ENABLE_VULKAN
60+
EmbedderExternalTextureVulkan::ExternalTextureCallback vulkan_callback_;
61+
#endif
5062
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderExternalTextureResolver);
5163
};
5264
} // namespace flutter
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/shell/platform/embedder/embedder_external_texture_source_vulkan.h"
6+
7+
#include "impeller/renderer/backend/vulkan/allocator_vk.h"
8+
#include "impeller/renderer/backend/vulkan/context_vk.h"
9+
#include "impeller/renderer/backend/vulkan/texture_source_vk.h"
10+
#include "impeller/renderer/backend/vulkan/yuv_conversion_library_vk.h"
11+
#include "vulkan/vulkan.hpp"
12+
13+
namespace flutter {
14+
15+
bool RequiresYCBCRConversion(impeller::vk::Format format) {
16+
switch (format) {
17+
case impeller::vk::Format::eG8B8R83Plane420Unorm:
18+
case impeller::vk::Format::eG8B8R82Plane420Unorm:
19+
case impeller::vk::Format::eG8B8R83Plane422Unorm:
20+
case impeller::vk::Format::eG8B8R82Plane422Unorm:
21+
case impeller::vk::Format::eG8B8R83Plane444Unorm:
22+
return true;
23+
default:
24+
// NOTE: NOT EXHAUSTIVE.
25+
break;
26+
}
27+
return false;
28+
}
29+
30+
EmbedderExternalTextureSourceVulkan::EmbedderExternalTextureSourceVulkan(
31+
const std::shared_ptr<impeller::Context>& p_context,
32+
FlutterVulkanTexture* embedder_desc)
33+
: TextureSourceVK(ToTextureDescriptor(embedder_desc)) {
34+
const auto& context = impeller::ContextVK::Cast(*p_context);
35+
const auto& device = context.GetDevice();
36+
texture_image_ =
37+
impeller::vk::Image(reinterpret_cast<VkImage>(embedder_desc->image));
38+
texture_device_memory_ = impeller::vk::DeviceMemory(
39+
reinterpret_cast<VkDeviceMemory>(embedder_desc->image_memory));
40+
41+
needs_yuv_conversion_ = RequiresYCBCRConversion(
42+
static_cast<impeller::vk::Format>(embedder_desc->format));
43+
std::shared_ptr<impeller::YUVConversionVK> yuv_conversion;
44+
if (needs_yuv_conversion_) {
45+
// Figure out how to perform YUV conversions.
46+
yuv_conversion = CreateYUVConversion(context, embedder_desc);
47+
if (!yuv_conversion || !yuv_conversion->IsValid()) {
48+
VALIDATION_LOG << "Fail to create yuv conversion";
49+
return;
50+
}
51+
}
52+
53+
// Create image view for the newly created image.
54+
if (!CreateTextureImageView(device, embedder_desc, yuv_conversion)) {
55+
VALIDATION_LOG << "Fail to create texture image view";
56+
return;
57+
}
58+
59+
yuv_conversion_ = std::move(yuv_conversion);
60+
is_valid_ = true;
61+
}
62+
63+
impeller::PixelFormat ToPixelFormat(int32_t vk_format) {
64+
switch (vk_format) {
65+
case VK_FORMAT_UNDEFINED:
66+
return impeller::PixelFormat::kUnknown;
67+
case VK_FORMAT_R8G8B8A8_UNORM:
68+
return impeller::PixelFormat::kR8G8B8A8UNormInt;
69+
case VK_FORMAT_R8G8B8A8_SRGB:
70+
return impeller::PixelFormat::kR8G8B8A8UNormIntSRGB;
71+
case VK_FORMAT_B8G8R8A8_UNORM:
72+
return impeller::PixelFormat::kB8G8R8A8UNormInt;
73+
case VK_FORMAT_B8G8R8A8_SRGB:
74+
return impeller::PixelFormat::kB8G8R8A8UNormIntSRGB;
75+
case VK_FORMAT_R32G32B32A32_SFLOAT:
76+
return impeller::PixelFormat::kR32G32B32A32Float;
77+
case VK_FORMAT_R16G16B16A16_SFLOAT:
78+
return impeller::PixelFormat::kR16G16B16A16Float;
79+
case VK_FORMAT_S8_UINT:
80+
return impeller::PixelFormat::kS8UInt;
81+
case VK_FORMAT_D24_UNORM_S8_UINT:
82+
return impeller::PixelFormat::kD24UnormS8Uint;
83+
case VK_FORMAT_D32_SFLOAT_S8_UINT:
84+
return impeller::PixelFormat::kD32FloatS8UInt;
85+
case VK_FORMAT_R8_UNORM:
86+
return impeller::PixelFormat::kR8UNormInt;
87+
case VK_FORMAT_R8G8_UNORM:
88+
return impeller::PixelFormat::kR8G8UNormInt;
89+
default:
90+
return impeller::PixelFormat::kUnknown;
91+
}
92+
}
93+
94+
impeller::TextureDescriptor
95+
EmbedderExternalTextureSourceVulkan::ToTextureDescriptor(
96+
FlutterVulkanTexture* embedder_desc) {
97+
const auto size =
98+
impeller::ISize{static_cast<int64_t>(embedder_desc->width),
99+
static_cast<int64_t>(embedder_desc->height)};
100+
impeller::TextureDescriptor desc;
101+
desc.storage_mode = impeller::StorageMode::kDevicePrivate;
102+
desc.format = ToPixelFormat(embedder_desc->format);
103+
desc.size = size;
104+
desc.type = impeller::TextureType::kTexture2D;
105+
desc.sample_count = impeller::SampleCount::kCount1;
106+
desc.compression_type = impeller::CompressionType::kLossless;
107+
desc.mip_count = 1u;
108+
desc.usage = impeller::TextureUsage::kRenderTarget;
109+
return desc;
110+
}
111+
112+
std::shared_ptr<impeller::YUVConversionVK>
113+
EmbedderExternalTextureSourceVulkan::CreateYUVConversion(
114+
const impeller::ContextVK& context,
115+
FlutterVulkanTexture* embedder_desc) {
116+
impeller::YUVConversionDescriptorVK conversion_chain;
117+
auto& conversion_info = conversion_chain.get();
118+
119+
conversion_info.format =
120+
static_cast<impeller::vk::Format>(embedder_desc->format);
121+
conversion_info.ycbcrModel =
122+
impeller::vk::SamplerYcbcrModelConversion::eYcbcr709;
123+
conversion_info.ycbcrRange = impeller::vk::SamplerYcbcrRange::eItuFull;
124+
conversion_info.components = {impeller::vk::ComponentSwizzle::eIdentity,
125+
impeller::vk::ComponentSwizzle::eIdentity,
126+
impeller::vk::ComponentSwizzle::eIdentity,
127+
impeller::vk::ComponentSwizzle::eIdentity};
128+
conversion_info.xChromaOffset = impeller::vk::ChromaLocation::eCositedEven;
129+
conversion_info.yChromaOffset = impeller::vk::ChromaLocation::eCositedEven;
130+
conversion_info.chromaFilter = impeller::vk::Filter::eNearest;
131+
conversion_info.forceExplicitReconstruction = false;
132+
return context.GetYUVConversionLibrary()->GetConversion(conversion_chain);
133+
}
134+
135+
bool EmbedderExternalTextureSourceVulkan::CreateTextureImageView(
136+
const impeller::vk::Device& device,
137+
FlutterVulkanTexture* embedder_desc,
138+
const std::shared_ptr<impeller::YUVConversionVK>& yuv_conversion_wrapper) {
139+
impeller::vk::StructureChain<impeller::vk::ImageViewCreateInfo,
140+
impeller::vk::SamplerYcbcrConversionInfo>
141+
view_chain;
142+
auto& view_info = view_chain.get();
143+
view_info.image = texture_image_;
144+
view_info.viewType = impeller::vk::ImageViewType::e2D;
145+
view_info.format = static_cast<impeller::vk::Format>(embedder_desc->format);
146+
view_info.subresourceRange.aspectMask =
147+
impeller::vk::ImageAspectFlagBits::eColor;
148+
view_info.subresourceRange.baseMipLevel = 0u;
149+
view_info.subresourceRange.baseArrayLayer = 0u;
150+
view_info.subresourceRange.levelCount = 1;
151+
view_info.subresourceRange.layerCount = 1;
152+
153+
if (RequiresYCBCRConversion(
154+
static_cast<impeller::vk::Format>(embedder_desc->format))) {
155+
view_chain.get<impeller::vk::SamplerYcbcrConversionInfo>().conversion =
156+
yuv_conversion_wrapper->GetConversion();
157+
} else {
158+
view_chain.unlink<impeller::vk::SamplerYcbcrConversionInfo>();
159+
}
160+
auto image_view = device.createImageViewUnique(view_info);
161+
if (image_view.result != impeller::vk::Result::eSuccess) {
162+
return false;
163+
}
164+
texture_image_view_ = std::move(image_view.value);
165+
return true;
166+
}
167+
168+
// |TextureSourceVK|
169+
EmbedderExternalTextureSourceVulkan::~EmbedderExternalTextureSourceVulkan() =
170+
default;
171+
172+
bool EmbedderExternalTextureSourceVulkan::IsValid() const {
173+
return is_valid_;
174+
}
175+
176+
// |TextureSourceVK|
177+
impeller::vk::Image EmbedderExternalTextureSourceVulkan::GetImage() const {
178+
return texture_image_;
179+
}
180+
181+
// |TextureSourceVK|
182+
impeller::vk::ImageView EmbedderExternalTextureSourceVulkan::GetImageView()
183+
const {
184+
return texture_image_view_.get();
185+
}
186+
187+
// |TextureSourceVK|
188+
impeller::vk::ImageView
189+
EmbedderExternalTextureSourceVulkan::GetRenderTargetView() const {
190+
return texture_image_view_.get();
191+
}
192+
193+
// |TextureSourceVK|
194+
bool EmbedderExternalTextureSourceVulkan::IsSwapchainImage() const {
195+
return is_swapchain_image_;
196+
}
197+
198+
// |TextureSourceVK|
199+
std::shared_ptr<impeller::YUVConversionVK>
200+
EmbedderExternalTextureSourceVulkan::GetYUVConversion() const {
201+
return needs_yuv_conversion_ ? yuv_conversion_ : nullptr;
202+
}
203+
204+
} // namespace flutter

0 commit comments

Comments
 (0)