Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
texture.cc
Go to the documentation of this file.
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
6
7#include <cstring>
8
12#include "fml/make_copyable.h"
13#include "fml/mapping.h"
24
25#if IMPELLER_SUPPORTS_RENDERING
26#include "flutter/display_list/image/dl_image.h" // nogncheck
28#endif
32
33namespace flutter {
34namespace gpu {
35
37
38Texture::Texture(std::shared_ptr<impeller::Texture> texture)
39 : texture_(std::move(texture)) {}
40
41Texture::~Texture() = default;
42
43std::shared_ptr<impeller::Texture> Texture::GetTexture() {
44 return texture_;
45}
46
47// Returns the size in pixels of the given dimension at `mip_level`, clamped
48// at 1, matching standard mip-chain semantics. The Dart-side helper
49// `Texture.getMipLevelSizeInBytes` uses the same `max(1, dim >> level)`
50// formula in pixel-count form; if either is updated, both must be kept in
51// sync.
52static int32_t MipDimensionAtLevel(int32_t base_dimension, uint32_t mip_level) {
53 const int32_t shifted = base_dimension >> mip_level;
54 return shifted > 0 ? shifted : 1;
55}
56
57// Records a blit-pass that copies `source_bytes` into the given mip level and
58// slice of `texture` on `context`, then submits the command buffer. Returns
59// true if the encode and submit both succeed. The actual GPU upload may
60// complete asynchronously after this call returns.
63 const std::shared_ptr<impeller::Texture>& texture,
64 const std::shared_ptr<impeller::DeviceBuffer>& staging_buffer,
65 size_t source_length,
66 impeller::IRect destination_region,
67 uint32_t mip_level,
68 uint32_t slice) {
69 auto command_buffer = context.CreateCommandBuffer();
70 if (!command_buffer) {
71 FML_LOG(ERROR) << "Failed to create command buffer for texture overwrite.";
72 return false;
73 }
74 auto blit_pass = command_buffer->CreateBlitPass();
75 if (!blit_pass) {
76 FML_LOG(ERROR) << "Failed to create blit pass for texture overwrite.";
77 return false;
78 }
79 impeller::BufferView buffer_view(staging_buffer,
80 impeller::Range(0, source_length));
81 if (!blit_pass->AddCopy(std::move(buffer_view), texture, destination_region,
82 /*label=*/"Texture.overwrite", mip_level, slice)) {
83 return false;
84 }
85 if (!blit_pass->EncodeCommands()) {
86 return false;
87 }
88 return context.GetCommandQueue()->Submit({std::move(command_buffer)}).ok();
89}
90
91bool Texture::Overwrite(Context& gpu_context,
92 const tonic::DartByteData& source_bytes,
93 uint32_t mip_level,
94 uint32_t slice) {
95 const uint8_t* data = static_cast<const uint8_t*>(source_bytes.data());
96 const size_t length = source_bytes.length_in_bytes();
97
98 auto& impeller_context = gpu_context.GetContext();
99 auto staging_buffer =
100 impeller_context.GetResourceAllocator()->CreateBufferWithCopy(data,
101 length);
102 if (!staging_buffer) {
103 FML_LOG(ERROR) << "Failed to allocate staging buffer for texture "
104 "overwrite.";
105 return false;
106 }
107
108 // Compute the destination region for the requested mip level. The
109 // BlitPass::AddCopy validation requires the region to fit within the base
110 // texture size, and the actual GPU copy uses this rectangle as the
111 // destination on the chosen mip level. The same `max(1, dim >> level)`
112 // formula is used by `Texture.getMipLevelSizeInBytes` on the Dart side; if
113 // either is updated, both must be kept in sync.
114 const impeller::ISize base_size = texture_->GetSize();
115 const impeller::IRect destination_region = impeller::IRect::MakeXYWH(
116 0, 0, MipDimensionAtLevel(base_size.width, mip_level),
117 MipDimensionAtLevel(base_size.height, mip_level));
118
119 // For the GLES backend, command queue submission just flushes the reactor,
120 // which needs to happen on the raster thread.
121 if (impeller_context.GetBackendType() ==
123 auto dart_state = flutter::UIDartState::Current();
124 auto& task_runners = dart_state->GetTaskRunners();
125 auto context_shared = gpu_context.GetContextShared();
126 task_runners.GetRasterTaskRunner()->PostTask(fml::MakeCopyable(
127 [context_shared, texture = texture_, staging_buffer, length,
128 destination_region, mip_level, slice]() mutable {
129 if (!EncodeAndSubmitOverwrite(*context_shared, texture,
130 staging_buffer, length,
131 destination_region, mip_level, slice)) {
132 FML_LOG(ERROR) << "Failed to encode texture overwrite blit on the "
133 "raster thread.";
134 }
135 context_shared->DisposeThreadLocalCachedResources();
136 }));
137 return true;
138 }
139
140 if (!EncodeAndSubmitOverwrite(impeller_context, texture_, staging_buffer,
141 length, destination_region, mip_level, slice)) {
142 return false;
143 }
144 impeller_context.DisposeThreadLocalCachedResources();
145 return true;
146}
147
148#if IMPELLER_SUPPORTS_RENDERING
149// Extracts the impeller::Texture that backs the ui.Image `image_wrapper`.
150// Returns nullptr if the image is not backed by a Flutter GPU compatible
151// texture, for example a non-Impeller image or a deferred image (from
152// Picture.toImageSync) that has not finished rasterizing yet.
153static std::shared_ptr<impeller::Texture> GetTextureFromImage(
154 Context* gpu_context,
155 Dart_Handle image_wrapper) {
156 if (gpu_context == nullptr || Dart_IsNull(image_wrapper)) {
157 return nullptr;
158 }
159 // A `ui.Image` wraps the private `_Image` native field holder.
160 Dart_Handle inner = Dart_GetField(image_wrapper, tonic::ToDart("_image"));
161 if (Dart_IsError(inner) || Dart_IsNull(inner)) {
162 return nullptr;
163 }
164 auto* canvas_image =
166 if (!canvas_image) {
167 return nullptr;
168 }
169 sk_sp<flutter::DlImage> dl_image = canvas_image->image();
170 if (!dl_image) {
171 return nullptr;
172 }
173 const impeller::DlImageImpeller* impeller_image = dl_image->asImpellerImage();
174 if (!impeller_image) {
175 return nullptr;
176 }
177 return impeller_image->GetImpellerTexture(gpu_context->GetContextShared());
178}
179#endif
180
181Dart_Handle Texture::AsImage() const {
182 // DlImageImpeller isn't compiled in builds with Impeller disabled. If
183 // Impeller is disabled, it's impossible to get here anyhow, so just ifdef it
184 // out.
185#if IMPELLER_SUPPORTS_RENDERING
187 auto dl_image = impeller::DlImageImpeller::Make(texture_);
188 image->set_image(dl_image);
189 auto wrapped = image->CreateOuterWrapping();
190 return wrapped;
191#else
192 return Dart_Null();
193#endif
194}
195
196} // namespace gpu
197} // namespace flutter
198
199//----------------------------------------------------------------------------
200/// Exports
201///
202
204 flutter::gpu::Context* gpu_context,
205 int storage_mode,
206 int format,
207 int width,
208 int height,
209 int sample_count,
210 int texture_type,
211 bool enable_render_target_usage,
212 bool enable_shader_read_usage,
213 bool enable_shader_write_usage,
214 int mip_level_count) {
215 if (mip_level_count < 1) {
216 return false;
217 }
220 desc.size = {width, height};
222 desc.mip_count = static_cast<size_t>(mip_level_count);
223 desc.usage = {};
224 if (enable_render_target_usage) {
226 }
227 if (enable_shader_read_usage) {
229 }
230 if (enable_shader_write_usage) {
232 }
233 switch (sample_count) {
234 case 1:
236 break;
237 case 4:
239 break;
240 default:
241 return false;
242 }
243 desc.type = static_cast<impeller::TextureType>(texture_type);
246 return false;
247 }
248
249 auto texture =
250 gpu_context->GetContext().GetResourceAllocator()->CreateTexture(desc,
251 true);
252 if (!texture) {
253 FML_LOG(ERROR) << "Failed to create texture.";
254 return false;
255 }
256
257 auto res = fml::MakeRefCounted<flutter::gpu::Texture>(std::move(texture));
258 res->AssociateWithDartWrapper(wrapper);
259
260 return true;
261}
262
264 flutter::gpu::Context* gpu_context,
265 Dart_Handle source_byte_data,
266 int mip_level,
267 int slice) {
268 if (mip_level < 0 || slice < 0) {
269 return false;
270 }
271 return texture->Overwrite(*gpu_context, tonic::DartByteData(source_byte_data),
272 static_cast<uint32_t>(mip_level),
273 static_cast<uint32_t>(slice));
274}
275
277 return wrapper->AsImage();
278}
279
281 flutter::gpu::Context* gpu_context,
282 Dart_Handle image_wrapper) {
283#if IMPELLER_SUPPORTS_RENDERING
284 auto texture = flutter::gpu::GetTextureFromImage(gpu_context, image_wrapper);
285 if (!texture) {
286 return Dart_NewTypedData(Dart_TypedData_kInt32, 0);
287 }
288 const impeller::TextureDescriptor& desc = texture->GetTextureDescriptor();
289 const impeller::TextureUsageMask usage = desc.usage;
290
291 // Layout must match the parsing in the Dart `Texture._fromImage`.
292 int32_t values[10];
293 values[0] = static_cast<int32_t>(
295 values[1] =
296 static_cast<int32_t>(flutter::gpu::FromImpellerPixelFormat(desc.format));
297 values[2] = static_cast<int32_t>(desc.size.width);
298 values[3] = static_cast<int32_t>(desc.size.height);
299 values[4] = static_cast<int32_t>(desc.sample_count);
300 // The Flutter GPU `TextureType` enum mirrors `impeller::TextureType`.
301 values[5] = static_cast<int32_t>(desc.type);
302 values[6] = (usage & impeller::TextureUsage::kRenderTarget) ? 1 : 0;
303 values[7] = (usage & impeller::TextureUsage::kShaderRead) ? 1 : 0;
304 values[8] = (usage & impeller::TextureUsage::kShaderWrite) ? 1 : 0;
305 values[9] = static_cast<int32_t>(desc.mip_count);
306
307 const intptr_t length = sizeof(values) / sizeof(values[0]);
308 Dart_Handle list = Dart_NewTypedData(Dart_TypedData_kInt32, length);
309 if (Dart_IsError(list)) {
310 return list;
311 }
312 Dart_TypedData_Type type;
313 void* data = nullptr;
314 intptr_t data_length = 0;
315 Dart_Handle acquire_result =
316 Dart_TypedDataAcquireData(list, &type, &data, &data_length);
317 if (Dart_IsError(acquire_result)) {
318 return acquire_result;
319 }
320 std::memcpy(data, values, sizeof(values));
321 Dart_TypedDataReleaseData(list);
322 return list;
323#else
324 return Dart_NewTypedData(Dart_TypedData_kInt32, 0);
325#endif
326}
327
329 Dart_Handle wrapper,
330 flutter::gpu::Context* gpu_context,
331 Dart_Handle image_wrapper) {
332#if IMPELLER_SUPPORTS_RENDERING
333 auto texture = flutter::gpu::GetTextureFromImage(gpu_context, image_wrapper);
334 if (!texture) {
335 return false;
336 }
337 auto res = fml::MakeRefCounted<flutter::gpu::Texture>(std::move(texture));
338 res->AssociateWithDartWrapper(wrapper);
339 return true;
340#else
341 return false;
342#endif
343}
static fml::RefPtr< CanvasImage > Create()
Definition image.h:36
static UIDartState * Current()
std::shared_ptr< impeller::Context > & GetContextShared()
Definition context.cc:91
impeller::Context & GetContext()
Definition context.cc:87
Texture(std::shared_ptr< impeller::Texture > texture)
Definition texture.cc:38
bool Overwrite(Context &gpu_context, const tonic::DartByteData &source_bytes, uint32_t mip_level, uint32_t slice)
Definition texture.cc:91
std::shared_ptr< impeller::Texture > GetTexture()
Definition texture.cc:43
Dart_Handle AsImage() const
Definition texture.cc:181
To do anything rendering related with Impeller, you need a context.
Definition context.h:69
virtual std::shared_ptr< Allocator > GetResourceAllocator() const =0
Returns the allocator used to create textures and buffers on the device.
virtual std::shared_ptr< Texture > GetImpellerTexture(const std::shared_ptr< Context > &context) const =0
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
const DlImageImpeller * asImpellerImage() const override
Safe downcast to DlImageImpeller.
const void * data() const
size_t length_in_bytes() const
#define IMPLEMENT_WRAPPERTYPEINFO(LibraryName, ClassName)
FlutterVulkanImage * image
uint32_t uint32_t * format
#define FML_LOG(severity)
Definition logging.h:101
size_t length
bool InternalFlutterGpu_Texture_Overwrite(flutter::gpu::Texture *texture, flutter::gpu::Context *gpu_context, Dart_Handle source_byte_data, int mip_level, int slice)
Definition texture.cc:263
bool InternalFlutterGpu_Texture_InitializeFromImage(Dart_Handle wrapper, flutter::gpu::Context *gpu_context, Dart_Handle image_wrapper)
Definition texture.cc:328
Dart_Handle InternalFlutterGpu_Texture_AsImage(flutter::gpu::Texture *wrapper)
Definition texture.cc:276
Dart_Handle InternalFlutterGpu_Texture_ImageTextureInfo(flutter::gpu::Context *gpu_context, Dart_Handle image_wrapper)
Definition texture.cc:280
bool InternalFlutterGpu_Texture_Initialize(Dart_Handle wrapper, flutter::gpu::Context *gpu_context, int storage_mode, int format, int width, int height, int sample_count, int texture_type, bool enable_render_target_usage, bool enable_shader_read_usage, bool enable_shader_write_usage, int mip_level_count)
Definition texture.cc:203
FlTexture * texture
constexpr impeller::PixelFormat ToImpellerPixelFormat(FlutterGPUPixelFormat value)
Definition formats.h:116
constexpr FlutterGPUStorageMode FromImpellerStorageMode(impeller::StorageMode value)
Definition formats.h:41
constexpr FlutterGPUPixelFormat FromImpellerPixelFormat(impeller::PixelFormat value)
Definition formats.h:188
static int32_t MipDimensionAtLevel(int32_t base_dimension, uint32_t mip_level)
Definition texture.cc:52
static bool EncodeAndSubmitOverwrite(impeller::Context &context, const std::shared_ptr< impeller::Texture > &texture, const std::shared_ptr< impeller::DeviceBuffer > &staging_buffer, size_t source_length, impeller::IRect destination_region, uint32_t mip_level, uint32_t slice)
Definition texture.cc:61
constexpr impeller::StorageMode ToImpellerStorageMode(FlutterGPUStorageMode value)
Definition formats.h:25
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switch_defs.h:36
internal::CopyableLambda< T > MakeCopyable(T lambda)
constexpr bool IsMultisampleCapable(TextureType type)
Definition formats.h:471
Definition ref_ptr.h:261
Dart_Handle ToDart(const T &object)
std::shared_ptr< ContextGLES > context
std::shared_ptr< CommandBuffer > command_buffer
impeller::ShaderType type
int32_t height
int32_t width
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition rect.h:136
Type height
Definition size.h:29
Type width
Definition size.h:28
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...