15#if IMPELLER_SUPPORTS_RENDERING
26constexpr int64_t kMaxInternalTextureReferences = 3;
30Surface::TextureRecord::TextureRecord(
31 std::shared_ptr<impeller::Texture>
texture,
47std::shared_ptr<Surface::TextureRecord> Surface::CreateTextureRecord()
const {
48#if !IMPELLER_SUPPORTS_RENDERING
49 FML_LOG(ERROR) <<
"Flutter GPU surfaces require Impeller rendering support.";
63 auto texture = context_->GetResourceAllocator()->CreateTexture(desc,
true);
65 FML_LOG(ERROR) <<
"Failed to create Flutter GPU surface texture.";
71 FML_LOG(ERROR) <<
"Failed to create Flutter GPU surface image.";
75 return std::make_shared<TextureRecord>(std::move(
texture), std::move(
image),
80bool Surface::IsReusable(
const std::shared_ptr<TextureRecord>& record,
82 if (current_index_.has_value() && current_index_.value() == index) {
85 return record && record->size.width == size_.
width &&
86 record->size.height == size_.
height && record->format == format_ &&
87 !record->acquired && !record->producer_pending.load() &&
88 record->image && record->image->unique() &&
89 static_cast<int64_t
>(record->texture.use_count()) <=
90 kMaxInternalTextureReferences;
93void Surface::PruneTextureRecords() {
94 for (
size_t i = 0;
i < records_.size();
i++) {
95 auto& record = records_[
i];
100 const bool is_current =
101 current_index_.has_value() && current_index_.value() ==
i;
102 const bool matches_surface = record->size.width == size_.
width &&
103 record->size.height == size_.
height &&
104 record->format == format_;
108 const bool has_external_references =
109 !record->image || !record->image->unique() ||
110 static_cast<int64_t
>(record->texture.use_count()) >
111 kMaxInternalTextureReferences;
113 if (!is_current && !matches_surface && !record->acquired &&
114 !record->producer_pending.load() && !has_external_references) {
119 while (!records_.empty() && !records_.back()) {
125 std::optional<size_t> available_index;
127 for (
const auto& record : records_) {
128 if (!record && !available_index.has_value()) {
129 available_index = index;
131 if (IsReusable(record, index)) {
132 record->acquired =
true;
133 auto texture = fml::MakeRefCounted<Texture>(record->texture);
134 texture->AssociateWithDartWrapper(texture_wrapper);
135 return static_cast<int>(index);
140 auto record = CreateTextureRecord();
144 record->acquired =
true;
146 if (available_index.has_value()) {
147 records_[available_index.value()] = record;
148 index = available_index.value();
150 records_.push_back(record);
151 index = records_.size() - 1u;
154 auto texture = fml::MakeRefCounted<Texture>(record->texture);
155 texture->AssociateWithDartWrapper(texture_wrapper);
156 return static_cast<int>(index);
159Dart_Handle Surface::CreateImage(
const sk_sp<DlImage>&
image)
const {
164 canvas_image->set_image(
image);
165 return canvas_image->CreateOuterWrapping();
170 if (texture_index >= records_.size()) {
171 return tonic::ToDart(
"SurfaceFrame does not belong to this GpuSurface.");
174 auto record = records_[texture_index];
175 if (!record || !record->acquired) {
177 "SurfaceFrame has already been presented or discarded.");
180 record->producer_pending.store(
true);
183 record->producer_pending.store(false);
185 record->producer_pending.store(
false);
187 "SurfaceFrame.present must be called before submitting the command "
191 record->acquired =
false;
192 current_index_ = texture_index;
193 PruneTextureRecords();
200 if (texture_index >= records_.size()) {
203 auto record = records_[texture_index];
205 record->acquired =
false;
210 if (!current_index_.has_value() ||
211 current_index_.value() >= records_.size()) {
214 auto record = records_[current_index_.value()];
218 return CreateImage(record->image);
222 for (
const auto& record : records_) {
223 if (record && record->acquired) {
224 return "GpuSurface.resize cannot be called while a SurfaceFrame is "
229 PruneTextureRecords();
235 for (
const auto& record : records_) {
251 [[maybe_unused]] Dart_Handle wrapper,
255 [[maybe_unused]]
int format) {
257 return tonic::ToDart(
"GpuSurface dimensions must be greater than zero.");
260#if !IMPELLER_SUPPORTS_RENDERING
261 return tonic::ToDart(
"GpuSurface requires Impeller rendering support.");
265 return tonic::ToDart(
"Unsupported GpuSurface pixel format.");
268 auto res = fml::MakeRefCounted<flutter::gpu::Surface>(
271 res->AssociateWithDartWrapper(wrapper);
277 Dart_Handle texture_wrapper) {
285 if (texture_index < 0) {
288 return wrapper->
PresentFrame(
static_cast<size_t>(texture_index),
294 if (texture_index < 0) {
297 wrapper->
DiscardFrame(
static_cast<size_t>(texture_index));
309 return tonic::ToDart(
"GpuSurface dimensions must be greater than zero.");
312 if (
error.has_value()) {
static fml::RefPtr< CanvasImage > Create()
int AcquireNextFrame(Dart_Handle texture_wrapper)
Dart_Handle GetCurrentImage() const
size_t GetBackingTextureCount() const
Dart_Handle PresentFrame(size_t texture_index, CommandBuffer &command_buffer)
std::optional< std::string > Resize(impeller::ISize size)
void DiscardFrame(size_t texture_index)
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
#define IMPLEMENT_WRAPPERTYPEINFO(LibraryName, ClassName)
FlutterVulkanImage * image
const uint8_t uint32_t uint32_t GError ** error
uint32_t uint32_t * format
#define FML_LOG(severity)
int InternalFlutterGpu_Surface_AcquireNextFrame(flutter::gpu::Surface *wrapper, Dart_Handle texture_wrapper)
Dart_Handle InternalFlutterGpu_Surface_Initialize(Dart_Handle wrapper, flutter::gpu::Context *gpu_context, int width, int height, int format)
Dart_Handle InternalFlutterGpu_Surface_PresentFrame(flutter::gpu::Surface *wrapper, int texture_index, flutter::gpu::CommandBuffer *command_buffer)
Dart_Handle InternalFlutterGpu_Surface_Resize(flutter::gpu::Surface *wrapper, int width, int height)
int InternalFlutterGpu_Surface_GetBackingTextureCount(flutter::gpu::Surface *wrapper)
void InternalFlutterGpu_Surface_DiscardFrame(flutter::gpu::Surface *wrapper, int texture_index)
Dart_Handle InternalFlutterGpu_Surface_GetCurrentImage(flutter::gpu::Surface *wrapper)
constexpr impeller::PixelFormat ToImpellerPixelFormat(FlutterGPUPixelFormat value)
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Dart_Handle ToDart(const T &object)
std::shared_ptr< ContextGLES > context
std::shared_ptr< CommandBuffer > command_buffer
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...