Flutter Engine
The Flutter Engine
texture_gles.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 <optional>
8#include <utility>
9
10#include "flutter/fml/logging.h"
11#include "flutter/fml/mapping.h"
12#include "flutter/fml/trace_event.h"
18
19namespace impeller {
20
21namespace {
22static bool IsDepthStencilFormat(PixelFormat format) {
23 switch (format) {
27 return true;
41 return false;
42 }
44}
45
46static TextureGLES::Type GetTextureTypeFromDescriptor(
47 const TextureDescriptor& desc) {
48 const auto usage = static_cast<TextureUsageMask>(desc.usage);
49 const auto render_target = TextureUsage::kRenderTarget;
50 const auto is_msaa = desc.sample_count == SampleCount::kCount4;
51 if (usage == render_target && IsDepthStencilFormat(desc.format)) {
54 }
57}
58
59struct TexImage2DData {
60 GLint internal_format = 0;
61 GLenum external_format = GL_NONE;
62 GLenum type = GL_NONE;
63 std::shared_ptr<const fml::Mapping> data;
64
65 explicit TexImage2DData(PixelFormat pixel_format) {
66 switch (pixel_format) {
68 internal_format = GL_ALPHA;
69 external_format = GL_ALPHA;
70 type = GL_UNSIGNED_BYTE;
71 break;
73 internal_format = GL_RED;
74 external_format = GL_RED;
75 type = GL_UNSIGNED_BYTE;
76 break;
81 internal_format = GL_RGBA;
82 external_format = GL_RGBA;
83 type = GL_UNSIGNED_BYTE;
84 break;
86 internal_format = GL_RGBA;
87 external_format = GL_RGBA;
88 type = GL_FLOAT;
89 break;
91 internal_format = GL_RGBA;
92 external_format = GL_RGBA;
93 type = GL_HALF_FLOAT;
94 break;
96 // Pure stencil textures are only available in OpenGL 4.4+, which is
97 // ~0% of mobile devices. Instead, we use a depth-stencil texture and
98 // only use the stencil component.
99 //
100 // https://registry.khronos.org/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml
102 internal_format = GL_DEPTH_STENCIL;
103 external_format = GL_DEPTH_STENCIL;
104 type = GL_UNSIGNED_INT_24_8;
105 break;
112 return;
113 }
114 is_valid_ = true;
115 }
116
117 TexImage2DData(PixelFormat pixel_format,
118 std::shared_ptr<const fml::Mapping> mapping)
119 : TexImage2DData(pixel_format) {
120 data = std::move(mapping);
121 }
122
123 bool IsValid() const { return is_valid_; }
124
125 private:
126 bool is_valid_ = false;
127};
128} // namespace
129
131 switch (type) {
138 }
140}
141
143 : TextureGLES(std::move(reactor), desc, false, std::nullopt) {}
144
147 enum IsWrapped wrapped)
148 : TextureGLES(std::move(reactor), desc, true, std::nullopt) {}
149
150std::shared_ptr<TextureGLES> TextureGLES::WrapFBO(ReactorGLES::Ref reactor,
152 GLuint fbo) {
153 return std::shared_ptr<TextureGLES>(
154 new TextureGLES(std::move(reactor), desc, true, fbo));
155}
156
157TextureGLES::TextureGLES(std::shared_ptr<ReactorGLES> reactor,
159 bool is_wrapped,
160 std::optional<GLuint> fbo)
161 : Texture(desc),
162 reactor_(std::move(reactor)),
163 type_(GetTextureTypeFromDescriptor(GetTextureDescriptor())),
164 handle_(reactor_->CreateHandle(ToHandleType(type_))),
165 is_wrapped_(is_wrapped),
166 wrapped_fbo_(fbo) {
167 // Ensure the texture descriptor itself is valid.
168 if (!GetTextureDescriptor().IsValid()) {
169 VALIDATION_LOG << "Invalid texture descriptor.";
170 return;
171 }
172 // Ensure the texture doesn't exceed device capabilities.
173 const auto tex_size = GetTextureDescriptor().size;
174 const auto max_size =
175 reactor_->GetProcTable().GetCapabilities()->max_texture_size;
176 if (tex_size.Max(max_size) != max_size) {
177 VALIDATION_LOG << "Texture of size " << tex_size
178 << " would exceed max supported size of " << max_size << ".";
179 return;
180 }
181
182 is_valid_ = true;
183}
184
185// |Texture|
187 reactor_->CollectHandle(handle_);
188}
189
190// |Texture|
191bool TextureGLES::IsValid() const {
192 return is_valid_;
193}
194
195// |Texture|
196void TextureGLES::SetLabel(std::string_view label) {
197 reactor_->SetDebugLabel(handle_, std::string{label.data(), label.size()});
198}
199
200// |Texture|
201bool TextureGLES::OnSetContents(const uint8_t* contents,
202 size_t length,
203 size_t slice) {
204 return OnSetContents(CreateMappingWithCopy(contents, length), slice);
205}
206
207// |Texture|
208bool TextureGLES::OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
209 size_t slice) {
210 if (!mapping) {
211 return false;
212 }
213
214 if (mapping->GetSize() == 0u) {
215 return true;
216 }
217
218 if (mapping->GetMapping() == nullptr) {
219 return false;
220 }
221
222 if (GetType() != Type::kTexture) {
223 VALIDATION_LOG << "Incorrect texture usage flags for setting contents on "
224 "this texture object.";
225 return false;
226 }
227
228 if (is_wrapped_) {
229 VALIDATION_LOG << "Cannot set the contents of a wrapped texture.";
230 return false;
231 }
232
233 const auto& tex_descriptor = GetTextureDescriptor();
234
235 if (tex_descriptor.size.IsEmpty()) {
236 return true;
237 }
238
239 if (!tex_descriptor.IsValid() ||
240 mapping->GetSize() < tex_descriptor.GetByteSizeOfBaseMipLevel()) {
241 return false;
242 }
243
244 GLenum texture_type;
245 GLenum texture_target;
246 switch (tex_descriptor.type) {
248 texture_type = GL_TEXTURE_2D;
249 texture_target = GL_TEXTURE_2D;
250 break;
252 VALIDATION_LOG << "Multisample texture uploading is not supported for "
253 "the OpenGLES backend.";
254 return false;
256 texture_type = GL_TEXTURE_CUBE_MAP;
257 texture_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
258 break;
260 texture_type = GL_TEXTURE_EXTERNAL_OES;
261 texture_target = GL_TEXTURE_EXTERNAL_OES;
262 break;
263 }
264
265 auto data = std::make_shared<TexImage2DData>(tex_descriptor.format,
266 std::move(mapping));
267 if (!data || !data->IsValid()) {
268 VALIDATION_LOG << "Invalid texture format.";
269 return false;
270 }
271
272 ReactorGLES::Operation texture_upload = [handle = handle_, //
273 data, //
274 size = tex_descriptor.size, //
275 texture_type, //
276 texture_target //
277 ](const auto& reactor) {
278 auto gl_handle = reactor.GetGLHandle(handle);
279 if (!gl_handle.has_value()) {
281 << "Texture was collected before it could be uploaded to the GPU.";
282 return;
283 }
284 const auto& gl = reactor.GetProcTable();
285 gl.BindTexture(texture_type, gl_handle.value());
286 const GLvoid* tex_data = nullptr;
287 if (data->data) {
288 tex_data = data->data->GetMapping();
289 }
290
291 {
292 TRACE_EVENT1("impeller", "TexImage2DUpload", "Bytes",
293 std::to_string(data->data->GetSize()).c_str());
294 gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
295 gl.TexImage2D(texture_target, // target
296 0u, // LOD level
297 data->internal_format, // internal format
298 size.width, // width
299 size.height, // height
300 0u, // border
301 data->external_format, // external format
302 data->type, // type
303 tex_data // data
304 );
305 }
306 };
307
308 slices_initialized_ = reactor_->AddOperation(texture_upload);
309 return slices_initialized_[0];
310}
311
312// |Texture|
313ISize TextureGLES::GetSize() const {
314 return GetTextureDescriptor().size;
315}
316
317static std::optional<GLenum> ToRenderBufferFormat(PixelFormat format) {
318 switch (format) {
321 return GL_RGBA4;
323 return GL_RGBA32F;
325 return GL_RGBA16F;
327 return GL_STENCIL_INDEX8;
329 return GL_DEPTH24_STENCIL8;
331 return GL_DEPTH32F_STENCIL8;
341 return std::nullopt;
342 }
344}
345
346void TextureGLES::InitializeContentsIfNecessary() const {
347 if (!IsValid() || slices_initialized_[0]) {
348 return;
349 }
350 slices_initialized_[0] = true;
351
352 if (is_wrapped_) {
353 return;
354 }
355
356 auto size = GetSize();
357
358 if (size.IsEmpty()) {
359 return;
360 }
361
362 const auto& gl = reactor_->GetProcTable();
363 auto handle = reactor_->GetGLHandle(handle_);
364 if (!handle.has_value()) {
365 VALIDATION_LOG << "Could not initialize the contents of texture.";
366 return;
367 }
368
369 switch (type_) {
370 case Type::kTexture:
372 TexImage2DData tex_data(GetTextureDescriptor().format);
373 if (!tex_data.IsValid()) {
374 VALIDATION_LOG << "Invalid format for texture image.";
375 return;
376 }
377 gl.BindTexture(GL_TEXTURE_2D, handle.value());
378 {
379 TRACE_EVENT0("impeller", "TexImage2DInitialization");
380 gl.TexImage2D(GL_TEXTURE_2D, // target
381 0u, // LOD level (base mip level size checked)
382 tex_data.internal_format, // internal format
383 size.width, // width
384 size.height, // height
385 0u, // border
386 tex_data.external_format, // format
387 tex_data.type, // type
388 nullptr // data
389 );
390 }
391 } break;
394 auto render_buffer_format =
396 if (!render_buffer_format.has_value()) {
397 VALIDATION_LOG << "Invalid format for render-buffer image.";
398 return;
399 }
400 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
401 {
402 TRACE_EVENT0("impeller", "RenderBufferStorageInitialization");
403 if (type_ == Type::kRenderBufferMultisampled) {
404 gl.RenderbufferStorageMultisampleEXT(
405 GL_RENDERBUFFER, // target
406 4, // samples
407 render_buffer_format.value(), // internal format
408 size.width, // width
409 size.height // height
410 );
411 } else {
412 gl.RenderbufferStorage(
413 GL_RENDERBUFFER, // target
414 render_buffer_format.value(), // internal format
415 size.width, // width
416 size.height // height
417 );
418 }
419 }
420 } break;
421 }
422}
423
424std::optional<GLuint> TextureGLES::GetGLHandle() const {
425 if (!IsValid()) {
426 return std::nullopt;
427 }
428 return reactor_->GetGLHandle(handle_);
429}
430
431bool TextureGLES::Bind() const {
432 auto handle = GetGLHandle();
433 if (!handle.has_value()) {
434 return false;
435 }
436 const auto& gl = reactor_->GetProcTable();
437 switch (type_) {
438 case Type::kTexture:
441 if (!target.has_value()) {
442 VALIDATION_LOG << "Could not bind texture of this type.";
443 return false;
444 }
445 gl.BindTexture(target.value(), handle.value());
446 } break;
449 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
450 break;
451 }
452 InitializeContentsIfNecessary();
453 return true;
454}
455
456void TextureGLES::MarkSliceInitialized(size_t slice) const {
457 slices_initialized_[slice] = true;
458}
459
460bool TextureGLES::IsSliceInitialized(size_t slice) const {
461 return slices_initialized_[slice];
462}
463
465 if (!IsValid()) {
466 return false;
467 }
468
470 switch (type) {
472 break;
474 VALIDATION_LOG << "Generating mipmaps for multisample textures is not "
475 "supported in the GLES backend.";
476 return false;
478 break;
480 break;
481 }
482
483 if (!Bind()) {
484 return false;
485 }
486
487 auto handle = GetGLHandle();
488 if (!handle.has_value()) {
489 return false;
490 }
491
492 const auto& gl = reactor_->GetProcTable();
493 gl.GenerateMipmap(ToTextureType(type));
494 mipmap_generated_ = true;
495 return true;
496}
497
499 return type_;
500}
501
503 switch (point) {
505 return GL_COLOR_ATTACHMENT0;
507 return GL_DEPTH_ATTACHMENT;
509 return GL_STENCIL_ATTACHMENT;
510 }
511}
512
514 GLenum target,
515 AttachmentType attachment_type) const {
516 if (!IsValid()) {
517 return false;
518 }
519 InitializeContentsIfNecessary();
520 auto handle = GetGLHandle();
521 if (!handle.has_value()) {
522 return false;
523 }
524 const auto& gl = reactor_->GetProcTable();
525
526 switch (type_) {
527 case Type::kTexture:
528 gl.FramebufferTexture2D(target, // target
529 ToAttachmentType(attachment_type), // attachment
530 GL_TEXTURE_2D, // textarget
531 handle.value(), // texture
532 0 // level
533 );
534 break;
536 gl.FramebufferTexture2DMultisampleEXT(
537 target, // target
538 ToAttachmentType(attachment_type), // attachment
539 GL_TEXTURE_2D, // textarget
540 handle.value(), // texture
541 0, // level
542 4 // samples
543 );
544 break;
547 gl.FramebufferRenderbuffer(
548 target, // target
549 ToAttachmentType(attachment_type), // attachment
550 GL_RENDERBUFFER, // render-buffer target
551 handle.value() // render-buffer
552 );
553 break;
554 }
555
556 return true;
557}
558
559// |Texture|
560Scalar TextureGLES::GetYCoordScale() const {
561 switch (GetCoordinateSystem()) {
563 return 1.0;
565 return -1.0;
566 }
568}
569
570} // namespace impeller
static sk_sp< GrTextureProxy > wrapped(skiatest::Reporter *reporter, GrRecordingContext *rContext, GrProxyProvider *proxyProvider, SkBackingFit fit)
const char * c_str() const
Definition: SkString.h:133
std::function< void(const ReactorGLES &reactor)> Operation
Definition: reactor_gles.h:194
std::shared_ptr< ReactorGLES > Ref
Definition: reactor_gles.h:86
bool IsSliceInitialized(size_t slice) const
TextureGLES(ReactorGLES::Ref reactor, TextureDescriptor desc)
bool SetAsFramebufferAttachment(GLenum target, AttachmentType attachment_type) const
void MarkSliceInitialized(size_t slice) const
static std::shared_ptr< TextureGLES > WrapFBO(ReactorGLES::Ref reactor, TextureDescriptor desc, GLuint fbo)
std::optional< GLuint > GetGLHandle() const
const TextureDescriptor & GetTextureDescriptor() const
Definition: texture.cc:57
TextureCoordinateSystem GetCoordinateSystem() const
Definition: texture.cc:77
bool mipmap_generated_
Definition: texture.h:70
uint32_t uint32_t * format
uint32_t * target
#define FML_UNREACHABLE()
Definition: logging.h:109
size_t length
it will be possible to load the file into Perfetto s trace viewer 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
Definition: switches.h:259
constexpr std::optional< GLenum > ToTextureTarget(TextureType type)
Definition: formats_gles.h:183
float Scalar
Definition: scalar.h:18
std::shared_ptr< fml::Mapping > CreateMappingWithCopy(const uint8_t *contents, size_t length)
Definition: allocation.cc:83
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:99
constexpr GLenum ToTextureType(TextureType type)
Definition: formats_gles.h:169
static std::optional< GLenum > ToRenderBufferFormat(PixelFormat format)
ISize64 ISize
Definition: size.h:140
static GLenum ToAttachmentType(TextureGLES::AttachmentType point)
Mask< TextureUsage > TextureUsageMask
Definition: formats.h:308
HandleType ToHandleType(TextureGLES::Type type)
gl
Definition: malisc.py:41
Definition: ref_ptr.h:256
static SkString to_string(int n)
Definition: nanobench.cpp:119
fuchsia::ui::composition::ParentViewportWatcherHandle handle_
static void usage(char *argv0)
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
GLenum type
Definition: texture_gles.cc:62
GLenum external_format
Definition: texture_gles.cc:61
GLint internal_format
Definition: texture_gles.cc:60
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)
Definition: trace_event.h:141
#define VALIDATION_LOG
Definition: validation.h:73