Flutter Impeller
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 <format>
8 #include <optional>
9 #include <utility>
10 
11 #include "flutter/fml/logging.h"
12 #include "flutter/fml/mapping.h"
13 #include "flutter/fml/trace_event.h"
16 #include "impeller/core/formats.h"
19 
20 namespace impeller {
21 
22 namespace {
23 static bool IsDepthStencilFormat(PixelFormat format) {
24  switch (format) {
28  return true;
60  return false;
61  }
62  FML_UNREACHABLE();
63 }
64 
65 static TextureGLES::Type GetTextureTypeFromDescriptor(
66  const TextureDescriptor& desc,
67  const std::shared_ptr<const CapabilitiesGLES>& capabilities) {
68  const auto usage = static_cast<TextureUsageMask>(desc.usage);
69  const auto render_target = TextureUsage::kRenderTarget;
70  const auto is_msaa = desc.sample_count == SampleCount::kCount4;
71  if (usage == render_target && IsDepthStencilFormat(desc.format)) {
74  }
75  return is_msaa ? (capabilities->SupportsImplicitResolvingMSAA()
79 }
80 
81 } // namespace
82 
84  switch (type) {
87  return HandleType::kTexture;
91  }
92  FML_UNREACHABLE();
93 }
94 
95 std::shared_ptr<TextureGLES> TextureGLES::WrapFBO(
96  std::shared_ptr<ReactorGLES> reactor,
97  TextureDescriptor desc,
98  GLuint fbo) {
99  auto texture = std::shared_ptr<TextureGLES>(
100  new TextureGLES(std::move(reactor), desc, false, fbo, std::nullopt));
101  if (!texture->IsValid()) {
102  return nullptr;
103  }
104  return texture;
105 }
106 
107 std::shared_ptr<TextureGLES> TextureGLES::WrapTexture(
108  std::shared_ptr<ReactorGLES> reactor,
109  TextureDescriptor desc,
110  HandleGLES external_handle) {
111  if (external_handle.IsDead()) {
112  VALIDATION_LOG << "Cannot wrap a dead handle.";
113  return nullptr;
114  }
115  if (external_handle.GetType() != HandleType::kTexture) {
116  VALIDATION_LOG << "Cannot wrap a non-texture handle.";
117  return nullptr;
118  }
119  auto texture = std::shared_ptr<TextureGLES>(new TextureGLES(
120  std::move(reactor), desc, false, std::nullopt, external_handle));
121  if (!texture->IsValid()) {
122  return nullptr;
123  }
124  return texture;
125 }
126 
127 std::shared_ptr<TextureGLES> TextureGLES::CreatePlaceholder(
128  std::shared_ptr<ReactorGLES> reactor,
129  TextureDescriptor desc) {
130  return TextureGLES::WrapFBO(std::move(reactor), desc, 0u);
131 }
132 
133 TextureGLES::TextureGLES(std::shared_ptr<ReactorGLES> reactor,
134  TextureDescriptor desc,
135  bool threadsafe)
136  : TextureGLES(std::move(reactor), //
137  desc, //
138  threadsafe, //
139  std::nullopt, //
140  std::nullopt //
141  ) {}
142 
143 TextureGLES::TextureGLES(std::shared_ptr<ReactorGLES> reactor,
144  TextureDescriptor desc,
145  bool threadsafe,
146  std::optional<GLuint> fbo,
147  std::optional<HandleGLES> external_handle)
148  : Texture(desc),
149  reactor_(std::move(reactor)),
150  type_(GetTextureTypeFromDescriptor(
151  GetTextureDescriptor(),
152  reactor_->GetProcTable().GetCapabilities())),
153  handle_(
154  external_handle.has_value()
155  ? UniqueHandleGLES(reactor_, external_handle.value())
156  : (threadsafe
157  ? UniqueHandleGLES(reactor_, ToHandleType(type_))
158  : UniqueHandleGLES::MakeUntracked(reactor_,
159  ToHandleType(type_)))),
160  is_wrapped_(fbo.has_value() || external_handle.has_value()),
161  wrapped_fbo_(fbo) {
162  // Ensure the texture descriptor itself is valid.
163  if (!GetTextureDescriptor().IsValid()) {
164  return;
165  }
166  // Ensure the texture doesn't exceed device capabilities.
167  const auto tex_size = GetTextureDescriptor().size;
168  const auto max_size =
169  reactor_->GetProcTable().GetCapabilities()->max_texture_size;
170  if (tex_size.Max(max_size) != max_size) {
171  VALIDATION_LOG << "Texture of size " << tex_size
172  << " would exceed max supported size of " << max_size << ".";
173  return;
174  }
175 
176  is_valid_ = true;
177 }
178 
180  handle_.Release();
181 }
182 
183 // |Texture|
184 bool TextureGLES::IsValid() const {
185  return is_valid_;
186 }
187 
188 // |Texture|
189 void TextureGLES::SetLabel(std::string_view label) {
190 #ifdef IMPELLER_DEBUG
191  reactor_->SetDebugLabel(handle_.Get(), label);
192 #endif // IMPELLER_DEBUG
193 }
194 
195 // |Texture|
196 void TextureGLES::SetLabel(std::string_view label, std::string_view trailing) {
197 #ifdef IMPELLER_DEBUG
198  if (reactor_->CanSetDebugLabels()) {
199  reactor_->SetDebugLabel(handle_.Get(),
200  std::format("{} {}", label, trailing));
201  }
202 #endif // IMPELLER_DEBUG
203 }
204 
205 // |Texture|
206 bool TextureGLES::OnSetContents(const uint8_t* contents,
207  size_t length,
208  size_t slice) {
209  return OnSetContents(CreateMappingWithCopy(contents, Bytes{length}), slice);
210 }
211 
212 // |Texture|
213 bool TextureGLES::OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
214  size_t slice) {
215  if (!mapping) {
216  return false;
217  }
218 
219  if (mapping->GetSize() == 0u) {
220  return true;
221  }
222 
223  if (mapping->GetMapping() == nullptr) {
224  return false;
225  }
226 
227  if (GetType() != Type::kTexture) {
228  VALIDATION_LOG << "Incorrect texture usage flags for setting contents on "
229  "this texture object.";
230  return false;
231  }
232 
233  if (is_wrapped_) {
234  VALIDATION_LOG << "Cannot set the contents of a wrapped texture.";
235  return false;
236  }
237 
238  const auto& tex_descriptor = GetTextureDescriptor();
239 
240  if (tex_descriptor.size.IsEmpty()) {
241  return true;
242  }
243 
244  if (!tex_descriptor.IsValid() ||
245  mapping->GetSize() < tex_descriptor.GetByteSizeOfBaseMipLevel()) {
246  return false;
247  }
248 
249  GLenum texture_type;
250  GLenum texture_target;
251  switch (tex_descriptor.type) {
253  texture_type = GL_TEXTURE_2D;
254  texture_target = GL_TEXTURE_2D;
255  break;
257  VALIDATION_LOG << "Multisample texture uploading is not supported for "
258  "the OpenGLES backend.";
259  return false;
261  texture_type = GL_TEXTURE_CUBE_MAP;
262  texture_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
263  break;
265  texture_type = GL_TEXTURE_EXTERNAL_OES;
266  texture_target = GL_TEXTURE_EXTERNAL_OES;
267  break;
268  }
269 
270  std::optional<PixelFormatGLES> gles_format =
271  ToPixelFormatGLES(tex_descriptor.format,
272  /*supports_bgra=*/
273  reactor_->GetProcTable().GetDescription()->HasExtension(
274  "GL_EXT_texture_format_BGRA8888"));
275  if (!gles_format.has_value()) {
276  VALIDATION_LOG << "Invalid texture format.";
277  return false;
278  }
279 
280  ReactorGLES::Operation texture_upload =
281  [handle = handle_.Get(), //
282  mapping, //
283  format = gles_format.value(), //
284  size = tex_descriptor.size, //
285  image_size = tex_descriptor.GetByteSizeOfBaseMipLevel(), //
286  texture_type, //
287  texture_target //
288  ](const auto& reactor) {
289  auto gl_handle = reactor.GetGLHandle(handle);
290  if (!gl_handle.has_value()) {
291  VALIDATION_LOG << "Texture was collected before it could be uploaded "
292  "to the GPU.";
293  return;
294  }
295  const auto& gl = reactor.GetProcTable();
296  gl.BindTexture(texture_type, gl_handle.value());
297  const GLvoid* tex_data = nullptr;
298  if (mapping) {
299  tex_data = mapping->GetMapping();
300  }
301 
302  {
303  TRACE_EVENT1("impeller", "TexImage2DUpload", "Bytes",
304  std::to_string(mapping->GetSize()).c_str());
305  gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
306  if (format.is_compressed) {
307  gl.CompressedTexImage2D(texture_target, // target
308  0u, // LOD level
309  format.internal_format, // internal format
310  size.width, // width
311  size.height, // height
312  0u, // border
313  image_size, // image size
314  tex_data); // data
315  } else {
316  gl.TexImage2D(texture_target, // target
317  0u, // LOD level
318  format.internal_format, // internal format
319  size.width, // width
320  size.height, // height
321  0u, // border
322  format.external_format, // format
323  format.type, // type
324  tex_data); // data
325  }
326  }
327  };
328 
329  const bool added = reactor_->AddOperation(texture_upload);
330  if (added) {
332  }
333  return added;
334 }
335 
336 // |Texture|
337 ISize TextureGLES::GetSize() const {
338  return GetTextureDescriptor().size;
339 }
340 
341 static std::optional<GLenum> ToRenderBufferFormat(PixelFormat format) {
342  switch (format) {
345  return GL_RGBA8;
347  return GL_RGBA32F;
349  return GL_RGBA16F;
351  return GL_STENCIL_INDEX8;
353  return GL_DEPTH24_STENCIL8;
355  return GL_DEPTH32F_STENCIL8;
383  return std::nullopt;
384  }
385  FML_UNREACHABLE();
386 }
387 
389  // When binding to a GL_READ_FRAMEBUFFER, any multisampled
390  // textures must be bound as single sampled.
391  if (target == GL_READ_FRAMEBUFFER && type_ == Type::kTextureMultisampled) {
392  return Type::kTexture;
393  }
394  return type_;
395 }
396 
397 void TextureGLES::InitializeContentsIfNecessary() {
398  if (!IsValid() || IsSliceMipLevelInitialized(0, 0)) {
399  return;
400  }
401 
402  if (is_wrapped_) {
403  // Storage is owned externally; mark it covered so we don't re-enter.
405  return;
406  }
407 
408  auto size = GetSize();
409 
410  if (size.IsEmpty()) {
412  return;
413  }
414 
415  const auto& gl = reactor_->GetProcTable();
416  std::optional<GLuint> handle = reactor_->GetGLHandle(handle_.Get());
417  if (!handle.has_value()) {
418  VALIDATION_LOG << "Could not initialize the contents of texture.";
419  return;
420  }
421 
422  switch (type_) {
423  case Type::kTexture:
425  const auto& desc = GetTextureDescriptor();
426  std::optional<PixelFormatGLES> gles_format = ToPixelFormatGLES(
427  desc.format,
428  /*supports_bgra=*/
429  reactor_->GetProcTable().GetDescription()->HasExtension(
430  "GL_EXT_texture_format_BGRA8888"));
431  if (!gles_format.has_value()) {
432  VALIDATION_LOG << "Invalid format for texture image.";
433  return;
434  }
435  TRACE_EVENT0("impeller", "TexImage2DInitialization");
436  if (desc.type == TextureType::kTextureCube) {
437  // Cubemap handles must be bound to GL_TEXTURE_CUBE_MAP and each face
438  // target must be defined independently before sampling. Allocate the
439  // base mip level for every face here so the cubemap is sample-ready
440  // even before any face has been uploaded; non-zero mip levels are
441  // still allocated lazily on first per-level write in the blit path.
442  gl.BindTexture(GL_TEXTURE_CUBE_MAP, handle.value());
443  for (size_t face = 0; face < 6; ++face) {
444  gl.TexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, // target
445  0u, // LOD level
446  gles_format->internal_format, // internal
447  size.width, // width
448  size.height, // height
449  0u, // border
450  gles_format->external_format, // format
451  gles_format->type, // type
452  nullptr // data
453  );
455  }
456  } else {
457  // 2D / multisampled. External-OES textures are always wrapped, so
458  // they returned at the is_wrapped_ check above. Only the base mip
459  // is allocated here. `glGenerateMipmap` (used by the snapshot
460  // pipeline) implicitly allocates and fills the rest, and per-level
461  // uploads from the blit path allocate non-zero levels lazily on
462  // first write.
463  gl.BindTexture(GL_TEXTURE_2D, handle.value());
464  gl.TexImage2D(GL_TEXTURE_2D, // target
465  0u, // LOD level
466  gles_format->internal_format, // internal
467  size.width, // width
468  size.height, // height
469  0u, // border
470  gles_format->external_format, // format
471  gles_format->type, // type
472  nullptr // data
473  );
475  }
476  } break;
477  case Type::kRenderBuffer:
479  auto render_buffer_format =
481  if (!render_buffer_format.has_value()) {
482  VALIDATION_LOG << "Invalid format for render-buffer image.";
483  return;
484  }
485  gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
486  {
487  if (type_ == Type::kRenderBufferMultisampled) {
488  // BEWARE: these functions are not at all equivalent! the extensions
489  // are from EXT_multisampled_render_to_texture and cannot be used
490  // with regular GLES 3.0 multisampled renderbuffers/textures.
491  if (gl.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
492  gl.RenderbufferStorageMultisampleEXT(
493  /*target=*/GL_RENDERBUFFER, //
494  /*samples=*/4, //
495  /*internal_format=*/render_buffer_format.value(), //
496  /*width=*/size.width, //
497  /*height=*/size.height //
498  );
499  } else {
500  gl.RenderbufferStorageMultisample(
501  /*target=*/GL_RENDERBUFFER, //
502  /*samples=*/4, //
503  /*internal_format=*/render_buffer_format.value(), //
504  /*width=*/size.width, //
505  /*height=*/size.height //
506  );
507  }
508  } else {
509  gl.RenderbufferStorage(
510  /*target=*/GL_RENDERBUFFER, //
511  /*internal_format=*/render_buffer_format.value(), //
512  /*width=*/size.width, //
513  /*height=*/size.height //
514  );
515  }
516  }
517  // Renderbuffers don't have mip levels, but we still mark slot (0, 0)
518  // so the early-out guard at the top of this function fires on subsequent
519  // calls.
521  } break;
522  }
523 }
524 
525 std::optional<GLuint> TextureGLES::GetGLHandle() const {
526  if (!IsValid()) {
527  return std::nullopt;
528  }
529  return reactor_->GetGLHandle(handle_.Get());
530 }
531 
533  auto handle = GetGLHandle();
534  if (!handle.has_value()) {
535  return false;
536  }
537  const auto& gl = reactor_->GetProcTable();
538 
539  if (fence_.IsValid()) {
540  std::optional<GLsync> fence = reactor_->GetGLFence(fence_.Get());
541  if (fence.has_value()) {
542  gl.WaitSync(fence.value(), 0, GL_TIMEOUT_IGNORED);
543  }
544  fence_.Reset();
545  }
546 
547  switch (type_) {
548  case Type::kTexture:
550  const auto target = ToTextureTarget(GetTextureDescriptor().type);
551  if (!target.has_value()) {
552  VALIDATION_LOG << "Could not bind texture of this type.";
553  return false;
554  }
555  gl.BindTexture(target.value(), handle.value());
556  } break;
557  case Type::kRenderBuffer:
559  gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
560  break;
561  }
562  InitializeContentsIfNecessary();
563  return true;
564 }
565 
567  for (auto& slice_mips : slice_mip_initialized_) {
568  slice_mips.set();
569  }
570 }
571 
574 }
575 
576 bool TextureGLES::IsSliceInitialized(size_t slice) const {
577  return IsSliceMipLevelInitialized(slice, 0);
578 }
579 
580 void TextureGLES::MarkSliceMipLevelInitialized(size_t slice, size_t mip_level) {
581  if (slice >= slice_mip_initialized_.size() ||
582  mip_level >= kMaxTrackedMipLevels) {
583  return;
584  }
585  slice_mip_initialized_[slice].set(mip_level);
586 }
587 
589  size_t mip_level) const {
590  if (slice >= slice_mip_initialized_.size() ||
591  mip_level >= kMaxTrackedMipLevels) {
592  return false;
593  }
594  return slice_mip_initialized_[slice].test(mip_level);
595 }
596 
598  if (!IsValid()) {
599  return false;
600  }
601 
602  auto type = GetTextureDescriptor().type;
603  switch (type) {
605  break;
607  VALIDATION_LOG << "Generating mipmaps for multisample textures is not "
608  "supported in the GLES backend.";
609  return false;
611  break;
613  break;
614  }
615 
616  if (!Bind()) {
617  return false;
618  }
619 
620  auto handle = GetGLHandle();
621  if (!handle.has_value()) {
622  return false;
623  }
624 
625  const auto& gl = reactor_->GetProcTable();
626  gl.GenerateMipmap(ToTextureType(type));
627  mipmap_generated_ = true;
628  return true;
629 }
630 
632  return type_;
633 }
634 
636  switch (point) {
638  return GL_COLOR_ATTACHMENT0;
640  return GL_DEPTH_ATTACHMENT;
642  return GL_STENCIL_ATTACHMENT;
643  }
644 }
645 
646 bool TextureGLES::EnsureSliceMipLevelStorage(size_t slice, size_t mip_level) {
647  if (IsSliceMipLevelInitialized(slice, mip_level)) {
648  return true;
649  }
650  // Renderbuffers and multisampled textures only have their single level
651  // allocated at init; only sampled 2D and cube textures allocate per-level.
652  if (type_ != Type::kTexture) {
653  return true;
654  }
655  auto handle = GetGLHandle();
656  if (!handle.has_value()) {
657  return false;
658  }
659  const auto& gl = reactor_->GetProcTable();
660  const auto& desc = GetTextureDescriptor();
661  std::optional<PixelFormatGLES> gles_format = ToPixelFormatGLES(
662  desc.format,
663  gl.GetDescription()->HasExtension("GL_EXT_texture_format_BGRA8888"));
664  if (!gles_format.has_value()) {
665  return false;
666  }
667  ISize size = GetSize();
668  bool is_cube = desc.type == TextureType::kTextureCube;
669  GLenum image_target =
670  is_cube ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice : GL_TEXTURE_2D;
671  gl.BindTexture(is_cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, handle.value());
672  gl.TexImage2D(image_target, // target
673  static_cast<GLint>(mip_level), // LOD level
674  gles_format->internal_format, // internal
675  static_cast<GLsizei>(
676  std::max<int64_t>(1, size.width >> mip_level)), // width
677  static_cast<GLsizei>(
678  std::max<int64_t>(1, size.height >> mip_level)), // height
679  0u, // border
680  gles_format->external_format, // format
681  gles_format->type, // type
682  nullptr // data
683  );
684  MarkSliceMipLevelInitialized(slice, mip_level);
685  return true;
686 }
687 
689  AttachmentType attachment_type,
690  uint32_t mip_level,
691  uint32_t slice) {
692  if (!IsValid()) {
693  return false;
694  }
695  InitializeContentsIfNecessary();
696  const auto& gl = reactor_->GetProcTable();
697  if (mip_level > 0 &&
698  !gl.GetCapabilities()->SupportsFramebufferRenderMipmap()) {
699  VALIDATION_LOG << "Rendering into a non-zero mip level is not supported on "
700  "the GLES backend.";
701  return false;
702  }
703  if (!EnsureSliceMipLevelStorage(slice, mip_level)) {
704  return false;
705  }
706  auto handle = GetGLHandle();
707  if (!handle.has_value()) {
708  return false;
709  }
710  const GLint level = static_cast<GLint>(mip_level);
711 
712  switch (ComputeTypeForBinding(target)) {
713  case Type::kTexture: {
714  // Cube maps attach a specific face; 2D textures attach the 2D target.
715  GLenum textarget =
717  ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice
718  : GL_TEXTURE_2D;
719  gl.FramebufferTexture2D(target, // target
720  ToAttachmentType(attachment_type), // attachment
721  textarget, // textarget
722  handle.value(), // texture
723  level // level
724  );
725  break;
726  }
728  gl.FramebufferTexture2DMultisampleEXT(
729  target, // target
730  ToAttachmentType(attachment_type), // attachment
731  GL_TEXTURE_2D, // textarget
732  handle.value(), // texture
733  level, // level
734  4 // samples
735  );
736  break;
737  case Type::kRenderBuffer:
739  gl.FramebufferRenderbuffer(
740  target, // target
741  ToAttachmentType(attachment_type), // attachment
742  GL_RENDERBUFFER, // render-buffer target
743  handle.value() // render-buffer
744  );
745  break;
746  }
747 
748  return true;
749 }
750 
752  return is_wrapped_;
753 }
754 
755 std::optional<GLuint> TextureGLES::GetFBO() const {
756  return wrapped_fbo_;
757 }
758 
760  FML_DCHECK(!fence_.IsValid());
761  fence_ = UniqueHandleGLES(reactor_, fence);
762 }
763 
764 // Visible for testing.
765 std::optional<HandleGLES> TextureGLES::GetSyncFence() const {
766  return fence_.IsValid() ? std::optional(fence_.Get()) : std::nullopt;
767 }
768 
770  cached_fbo_ = UniqueHandleGLES(reactor_, fbo);
771 }
772 
774  return cached_fbo_.Get();
775 }
776 
777 void TextureGLES::SetCachedFBOSubresource(uint32_t mip_level, uint32_t slice) {
778  cached_fbo_mip_level_ = mip_level;
779  cached_fbo_slice_ = slice;
780 }
781 
783  uint32_t slice) const {
784  return cached_fbo_mip_level_ == mip_level && cached_fbo_slice_ == slice;
785 }
786 
787 } // namespace impeller
Represents a handle to an underlying OpenGL object. Unlike OpenGL object handles, these handles can b...
Definition: handle_gles.h:42
constexpr bool IsDead() const
Determines if the handle is dead.
Definition: handle_gles.h:58
HandleType GetType() const
Definition: handle_gles.h:79
std::function< void(const ReactorGLES &reactor)> Operation
Definition: reactor_gles.h:214
void MarkSliceInitialized(size_t slice)
Indicates that a specific texture slice has been initialized.
static std::shared_ptr< TextureGLES > WrapFBO(std::shared_ptr< ReactorGLES > reactor, TextureDescriptor desc, GLuint fbo)
Create a texture by wrapping an external framebuffer object whose lifecycle is owned by the caller.
Definition: texture_gles.cc:95
void MarkContentsInitialized()
Indicates that all texture storage has already been allocated and contents initialized.
const HandleGLES & GetCachedFBO() const
Retrieve the cached FBO object, or a dead handle if there is no object.
std::optional< HandleGLES > GetSyncFence() const
bool IsSliceMipLevelInitialized(size_t slice, size_t mip_level) const
bool CachedFBOMatchesSubresource(uint32_t mip_level, uint32_t slice) const
bool IsSliceInitialized(size_t slice) const
void SetCachedFBOSubresource(uint32_t mip_level, uint32_t slice)
Records the subresource the cached FBO is currently bound to.
void MarkSliceMipLevelInitialized(size_t slice, size_t mip_level)
Indicates that storage for mip_level of slice has been allocated by a glTexImage2D call (or equivalen...
bool IsValid() const override
void SetFence(HandleGLES fence)
Attach a sync fence to this texture that will be waited on before encoding a rendering operation that...
void Leak()
Reset the internal texture state so that the reactor will not free the associated handle.
void SetCachedFBO(HandleGLES fbo)
TextureGLES(std::shared_ptr< ReactorGLES > reactor, TextureDescriptor desc, bool threadsafe=false)
static std::shared_ptr< TextureGLES > CreatePlaceholder(std::shared_ptr< ReactorGLES > reactor, TextureDescriptor desc)
Create a "texture" that is never expected to be bound/unbound explicitly or initialized in any way....
bool SetAsFramebufferAttachment(GLenum target, AttachmentType attachment_type, uint32_t mip_level=0, uint32_t slice=0)
std::optional< GLuint > GetFBO() const
Type ComputeTypeForBinding(GLenum target) const
std::optional< GLuint > GetGLHandle() const
static std::shared_ptr< TextureGLES > WrapTexture(std::shared_ptr< ReactorGLES > reactor, TextureDescriptor desc, HandleGLES external_handle)
Create a texture by wrapping an external OpenGL texture handle. Ownership of the texture handle is as...
bool IsWrapped() const
const TextureDescriptor & GetTextureDescriptor() const
Definition: texture.cc:55
bool mipmap_generated_
Definition: texture.h:69
A unique handle to an OpenGL object. The collection of this handle scheduled the destruction of the a...
const HandleGLES & Get() const
void Reset()
Collect the managed handle and replace it with a dead handle.
HandleGLES Release()
Release ownership of the handle.
int32_t value
const ProcTable & GetProcTable()
Definition: proc_table.cc:12
std::optional< PixelFormatGLES > ToPixelFormatGLES(PixelFormat pixel_format, bool supports_bgra)
Definition: formats_gles.cc:76
std::shared_ptr< fml::Mapping > CreateMappingWithCopy(const uint8_t *contents, Bytes length)
Creates a mapping with copy of the bytes.
Definition: allocation.cc:93
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:190
static std::optional< GLenum > ToRenderBufferFormat(PixelFormat format)
constexpr std::optional< GLenum > ToTextureTarget(TextureType type)
Definition: formats_gles.h:204
ISize64 ISize
Definition: size.h:162
static GLenum ToAttachmentType(TextureGLES::AttachmentType point)
Mask< TextureUsage > TextureUsageMask
Definition: formats.h:496
HandleType ToHandleType(TextureGLES::Type type)
Definition: texture_gles.cc:83
Definition: comparable.h:93
std::shared_ptr< ReactorGLES > reactor
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
#define VALIDATION_LOG
Definition: validation.h:91