Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
44
46 const TextureDescriptor& desc) {
47 const auto usage = static_cast<TextureUsageMask>(desc.usage);
48 const auto render_target = TextureUsage::kRenderTarget;
49 const auto is_msaa = desc.sample_count == SampleCount::kCount4;
50 if (usage == render_target && IsDepthStencilFormat(desc.format)) {
53 }
56}
57
69
71 : TextureGLES(std::move(reactor), desc, false, std::nullopt) {}
72
75 enum IsWrapped wrapped)
76 : TextureGLES(std::move(reactor), desc, true, std::nullopt) {}
77
78std::shared_ptr<TextureGLES> TextureGLES::WrapFBO(ReactorGLES::Ref reactor,
80 GLuint fbo) {
81 return std::shared_ptr<TextureGLES>(
82 new TextureGLES(std::move(reactor), desc, true, fbo));
83}
84
85TextureGLES::TextureGLES(std::shared_ptr<ReactorGLES> reactor,
87 bool is_wrapped,
88 std::optional<GLuint> fbo)
89 : Texture(desc),
90 reactor_(std::move(reactor)),
91 type_(GetTextureTypeFromDescriptor(GetTextureDescriptor())),
92 handle_(reactor_->CreateHandle(ToHandleType(type_))),
93 is_wrapped_(is_wrapped),
94 wrapped_fbo_(fbo) {
95 // Ensure the texture descriptor itself is valid.
97 VALIDATION_LOG << "Invalid texture descriptor.";
98 return;
99 }
100 // Ensure the texture doesn't exceed device capabilities.
101 const auto tex_size = GetTextureDescriptor().size;
102 const auto max_size =
103 reactor_->GetProcTable().GetCapabilities()->max_texture_size;
104 if (tex_size.Max(max_size) != max_size) {
105 VALIDATION_LOG << "Texture of size " << tex_size
106 << " would exceed max supported size of " << max_size << ".";
107 return;
108 }
109
110 is_valid_ = true;
111}
112
113// |Texture|
115 reactor_->CollectHandle(handle_);
116}
117
118// |Texture|
120 return is_valid_;
121}
122
123// |Texture|
124void TextureGLES::SetLabel(std::string_view label) {
125 reactor_->SetDebugLabel(handle_, std::string{label.data(), label.size()});
126}
127
130 GLenum external_format = GL_NONE;
131 GLenum type = GL_NONE;
132 std::shared_ptr<const fml::Mapping> data;
133
134 explicit TexImage2DData(PixelFormat pixel_format) {
135 switch (pixel_format) {
137 internal_format = GL_ALPHA;
138 external_format = GL_ALPHA;
139 type = GL_UNSIGNED_BYTE;
140 break;
142 internal_format = GL_RED;
143 external_format = GL_RED;
144 type = GL_UNSIGNED_BYTE;
145 break;
150 internal_format = GL_RGBA;
151 external_format = GL_RGBA;
152 type = GL_UNSIGNED_BYTE;
153 break;
155 internal_format = GL_RGBA;
156 external_format = GL_RGBA;
157 type = GL_FLOAT;
158 break;
160 internal_format = GL_RGBA;
161 external_format = GL_RGBA;
162 type = GL_HALF_FLOAT;
163 break;
165 // Pure stencil textures are only available in OpenGL 4.4+, which is
166 // ~0% of mobile devices. Instead, we use a depth-stencil texture and
167 // only use the stencil component.
168 //
169 // https://registry.khronos.org/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml
171 internal_format = GL_DEPTH_STENCIL;
172 external_format = GL_DEPTH_STENCIL;
173 type = GL_UNSIGNED_INT_24_8;
174 break;
181 return;
182 }
183 is_valid_ = true;
184 }
185
187 std::shared_ptr<const fml::Mapping> mapping)
188 : TexImage2DData(pixel_format) {
189 data = std::move(mapping);
190 }
191
192 bool IsValid() const { return is_valid_; }
193
194 private:
195 bool is_valid_ = false;
196};
197
198// |Texture|
199bool TextureGLES::OnSetContents(const uint8_t* contents,
200 size_t length,
201 size_t slice) {
202 return OnSetContents(CreateMappingWithCopy(contents, length), slice);
203}
204
205// |Texture|
206bool TextureGLES::OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
207 size_t slice) {
208 if (!mapping) {
209 return false;
210 }
211
212 if (mapping->GetSize() == 0u) {
213 return true;
214 }
215
216 if (mapping->GetMapping() == nullptr) {
217 return false;
218 }
219
220 if (GetType() != Type::kTexture) {
221 VALIDATION_LOG << "Incorrect texture usage flags for setting contents on "
222 "this texture object.";
223 return false;
224 }
225
226 if (is_wrapped_) {
227 VALIDATION_LOG << "Cannot set the contents of a wrapped texture.";
228 return false;
229 }
230
231 const auto& tex_descriptor = GetTextureDescriptor();
232
233 if (tex_descriptor.size.IsEmpty()) {
234 return true;
235 }
236
237 if (!tex_descriptor.IsValid()) {
238 return false;
239 }
240
241 if (mapping->GetSize() < tex_descriptor.GetByteSizeOfBaseMipLevel()) {
242 return false;
243 }
244
245 GLenum texture_type;
246 GLenum texture_target;
247 switch (tex_descriptor.type) {
249 texture_type = GL_TEXTURE_2D;
250 texture_target = GL_TEXTURE_2D;
251 break;
253 VALIDATION_LOG << "Multisample texture uploading is not supported for "
254 "the OpenGLES backend.";
255 return false;
257 texture_type = GL_TEXTURE_CUBE_MAP;
258 texture_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
259 break;
261 texture_type = GL_TEXTURE_EXTERNAL_OES;
262 texture_target = GL_TEXTURE_EXTERNAL_OES;
263 break;
264 }
265
266 auto data = std::make_shared<TexImage2DData>(tex_descriptor.format,
267 std::move(mapping));
268 if (!data || !data->IsValid()) {
269 VALIDATION_LOG << "Invalid texture format.";
270 return false;
271 }
272
273 ReactorGLES::Operation texture_upload = [handle = handle_, //
274 data, //
275 size = tex_descriptor.size, //
276 texture_type, //
277 texture_target //
278 ](const auto& reactor) {
279 auto gl_handle = reactor.GetGLHandle(handle);
280 if (!gl_handle.has_value()) {
282 << "Texture was collected before it could be uploaded to the GPU.";
283 return;
284 }
285 const auto& gl = reactor.GetProcTable();
286 gl.BindTexture(texture_type, gl_handle.value());
287 const GLvoid* tex_data = nullptr;
288 if (data->data) {
289 tex_data = data->data->GetMapping();
290 }
291
292 {
293 TRACE_EVENT1("impeller", "TexImage2DUpload", "Bytes",
294 std::to_string(data->data->GetSize()).c_str());
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 contents_initialized_ = reactor_->AddOperation(texture_upload);
309 return contents_initialized_;
310}
311
312// |Texture|
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()) {
348 return;
349 }
350 if (contents_initialized_) {
351 return;
352 }
353 contents_initialized_ = true;
354
355 if (is_wrapped_) {
356 return;
357 }
358
359 auto size = GetSize();
360
361 if (size.IsEmpty()) {
362 return;
363 }
364
365 const auto& gl = reactor_->GetProcTable();
366 auto handle = reactor_->GetGLHandle(handle_);
367 if (!handle.has_value()) {
368 VALIDATION_LOG << "Could not initialize the contents of texture.";
369 return;
370 }
371
372 switch (type_) {
373 case Type::kTexture:
375 TexImage2DData tex_data(GetTextureDescriptor().format);
376 if (!tex_data.IsValid()) {
377 VALIDATION_LOG << "Invalid format for texture image.";
378 return;
379 }
380 gl.BindTexture(GL_TEXTURE_2D, handle.value());
381 {
382 TRACE_EVENT0("impeller", "TexImage2DInitialization");
383 gl.TexImage2D(GL_TEXTURE_2D, // target
384 0u, // LOD level (base mip level size checked)
385 tex_data.internal_format, // internal format
386 size.width, // width
387 size.height, // height
388 0u, // border
389 tex_data.external_format, // format
390 tex_data.type, // type
391 nullptr // data
392 );
393 }
394 } break;
397 auto render_buffer_format =
399 if (!render_buffer_format.has_value()) {
400 VALIDATION_LOG << "Invalid format for render-buffer image.";
401 return;
402 }
403 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
404 {
405 TRACE_EVENT0("impeller", "RenderBufferStorageInitialization");
406 if (type_ == Type::kRenderBufferMultisampled) {
407 gl.RenderbufferStorageMultisampleEXT(
408 GL_RENDERBUFFER, // target
409 4, // samples
410 render_buffer_format.value(), // internal format
411 size.width, // width
412 size.height // height
413 );
414 } else {
415 gl.RenderbufferStorage(
416 GL_RENDERBUFFER, // target
417 render_buffer_format.value(), // internal format
418 size.width, // width
419 size.height // height
420 );
421 }
422 }
423 } break;
424 }
425}
426
427std::optional<GLuint> TextureGLES::GetGLHandle() const {
428 if (!IsValid()) {
429 return std::nullopt;
430 }
431 return reactor_->GetGLHandle(handle_);
432}
433
434bool TextureGLES::Bind() const {
435 auto handle = GetGLHandle();
436 if (!handle.has_value()) {
437 return false;
438 }
439 const auto& gl = reactor_->GetProcTable();
440 switch (type_) {
441 case Type::kTexture:
444 if (!target.has_value()) {
445 VALIDATION_LOG << "Could not bind texture of this type.";
446 return false;
447 }
448 gl.BindTexture(target.value(), handle.value());
449 } break;
452 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
453 break;
454 }
455 InitializeContentsIfNecessary();
456 return true;
457}
458
460 if (!IsValid()) {
461 return false;
462 }
463
465 switch (type) {
467 break;
469 VALIDATION_LOG << "Generating mipmaps for multisample textures is not "
470 "supported in the GLES backend.";
471 return false;
473 break;
475 break;
476 }
477
478 if (!Bind()) {
479 return false;
480 }
481
482 auto handle = GetGLHandle();
483 if (!handle.has_value()) {
484 return false;
485 }
486
487 const auto& gl = reactor_->GetProcTable();
488 gl.GenerateMipmap(ToTextureType(type));
489 mipmap_generated_ = true;
490 return true;
491}
492
494 return type_;
495}
496
498 switch (point) {
500 return GL_COLOR_ATTACHMENT0;
502 return GL_DEPTH_ATTACHMENT;
504 return GL_STENCIL_ATTACHMENT;
505 }
506}
507
509 GLenum target,
510 AttachmentType attachment_type) const {
511 if (!IsValid()) {
512 return false;
513 }
514 InitializeContentsIfNecessary();
515 auto handle = GetGLHandle();
516 if (!handle.has_value()) {
517 return false;
518 }
519 const auto& gl = reactor_->GetProcTable();
520
521 switch (type_) {
522 case Type::kTexture:
523 gl.FramebufferTexture2D(target, // target
524 ToAttachmentType(attachment_type), // attachment
525 GL_TEXTURE_2D, // textarget
526 handle.value(), // texture
527 0 // level
528 );
529 break;
531 gl.FramebufferTexture2DMultisampleEXT(
532 target, // target
533 ToAttachmentType(attachment_type), // attachment
534 GL_TEXTURE_2D, // textarget
535 handle.value(), // texture
536 0, // level
537 4 // samples
538 );
539 break;
542 gl.FramebufferRenderbuffer(
543 target, // target
544 ToAttachmentType(attachment_type), // attachment
545 GL_RENDERBUFFER, // render-buffer target
546 handle.value() // render-buffer
547 );
548 break;
549 }
550
551 return true;
552}
553
554// |Texture|
556 switch (GetCoordinateSystem()) {
558 return 1.0;
560 return -1.0;
561 }
563}
564
565} // namespace impeller
static sk_sp< GrTextureProxy > wrapped(skiatest::Reporter *reporter, GrRecordingContext *rContext, GrProxyProvider *proxyProvider, SkBackingFit fit)
std::function< void(const ReactorGLES &reactor)> Operation
std::shared_ptr< ReactorGLES > Ref
TextureGLES(ReactorGLES::Ref reactor, TextureDescriptor desc)
bool IsValid() const override
void SetLabel(std::string_view label) override
bool SetAsFramebufferAttachment(GLenum target, AttachmentType attachment_type) const
static std::shared_ptr< TextureGLES > WrapFBO(ReactorGLES::Ref reactor, TextureDescriptor desc, GLuint fbo)
std::optional< GLuint > GetGLHandle() const
bool OnSetContents(const uint8_t *contents, size_t length, size_t slice) override
ISize GetSize() const override
Scalar GetYCoordScale() const override
const TextureDescriptor & GetTextureDescriptor() const
Definition texture.cc:57
TextureCoordinateSystem GetCoordinateSystem() const
Definition texture.cc:77
bool mipmap_generated_
Definition texture.h:64
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)
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:100
constexpr GLenum ToTextureType(TextureType type)
static TextureGLES::Type GetTextureTypeFromDescriptor(const TextureDescriptor &desc)
static std::optional< GLenum > ToRenderBufferFormat(PixelFormat format)
static bool IsDepthStencilFormat(PixelFormat format)
static GLenum ToAttachmentType(TextureGLES::AttachmentType point)
HandleType ToHandleType(TextureGLES::Type type)
Definition ref_ptr.h:256
fuchsia::ui::composition::ParentViewportWatcherHandle handle_
static void usage(char *argv0)
TexImage2DData(PixelFormat pixel_format, std::shared_ptr< const fml::Mapping > mapping)
std::shared_ptr< const fml::Mapping > data
TexImage2DData(PixelFormat pixel_format)
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
#define TRACE_EVENT0(category_group, name)
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)
#define VALIDATION_LOG
Definition validation.h:73