11 #include "flutter/fml/logging.h"
12 #include "flutter/fml/mapping.h"
13 #include "flutter/fml/trace_event.h"
24 static bool IsDepthStencilFormat(
PixelFormat format) {
50 const TextureDescriptor& desc,
51 const std::shared_ptr<const CapabilitiesGLES>& capabilities) {
55 if (usage == render_target && IsDepthStencilFormat(desc.format)) {
59 return is_msaa ? (capabilities->SupportsImplicitResolvingMSAA()
65 struct TexImage2DData {
69 std::shared_ptr<const fml::Mapping>
data;
72 switch (pixel_format) {
76 type = GL_UNSIGNED_BYTE;
81 type = GL_UNSIGNED_BYTE;
89 type = GL_UNSIGNED_BYTE;
104 type = GL_HALF_FLOAT;
115 type = GL_UNSIGNED_INT_24_8;
129 std::shared_ptr<const fml::Mapping> mapping)
130 : TexImage2DData(pixel_format) {
131 data = std::move(mapping);
134 bool IsValid()
const {
return is_valid_; }
137 bool is_valid_ =
false;
154 std::shared_ptr<ReactorGLES> reactor,
157 auto texture = std::shared_ptr<TextureGLES>(
158 new TextureGLES(std::move(reactor), desc,
false, fbo, std::nullopt));
159 if (!texture->IsValid()) {
166 std::shared_ptr<ReactorGLES> reactor,
169 if (external_handle.
IsDead()) {
177 auto texture = std::shared_ptr<TextureGLES>(
new TextureGLES(
178 std::move(reactor), desc,
false, std::nullopt, external_handle));
179 if (!texture->IsValid()) {
186 std::shared_ptr<ReactorGLES> reactor,
204 std::optional<GLuint> fbo,
205 std::optional<HandleGLES> external_handle)
207 reactor_(
std::move(reactor)),
208 type_(GetTextureTypeFromDescriptor(
209 GetTextureDescriptor(),
211 handle_(external_handle.has_value()
212 ? external_handle.
value()
213 : (threadsafe ? reactor_->CreateHandle(
ToHandleType(type_))
214 : reactor_->CreateUntrackedHandle(
216 is_wrapped_(fbo.has_value() || external_handle.has_value()),
225 const auto max_size =
226 reactor_->GetProcTable().GetCapabilities()->max_texture_size;
227 if (tex_size.Max(max_size) != max_size) {
229 <<
" would exceed max supported size of " << max_size <<
".";
238 reactor_->CollectHandle(handle_);
239 if (!cached_fbo_.
IsDead()) {
240 reactor_->CollectHandle(cached_fbo_);
254 void TextureGLES::SetLabel(std::string_view label) {
255 #ifdef IMPELLER_DEBUG
256 reactor_->SetDebugLabel(handle_, label);
261 void TextureGLES::SetLabel(std::string_view label, std::string_view trailing) {
262 #ifdef IMPELLER_DEBUG
263 if (reactor_->CanSetDebugLabels()) {
264 reactor_->SetDebugLabel(handle_, std::format(
"{} {}", label, trailing));
270 bool TextureGLES::OnSetContents(
const uint8_t* contents,
277 bool TextureGLES::OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
283 if (mapping->GetSize() == 0u) {
287 if (mapping->GetMapping() ==
nullptr) {
292 VALIDATION_LOG <<
"Incorrect texture usage flags for setting contents on "
293 "this texture object.";
298 VALIDATION_LOG <<
"Cannot set the contents of a wrapped texture.";
304 if (tex_descriptor.size.IsEmpty()) {
308 if (!tex_descriptor.IsValid() ||
309 mapping->GetSize() < tex_descriptor.GetByteSizeOfBaseMipLevel()) {
314 GLenum texture_target;
315 switch (tex_descriptor.type) {
317 texture_type = GL_TEXTURE_2D;
318 texture_target = GL_TEXTURE_2D;
321 VALIDATION_LOG <<
"Multisample texture uploading is not supported for "
322 "the OpenGLES backend.";
325 texture_type = GL_TEXTURE_CUBE_MAP;
326 texture_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
329 texture_type = GL_TEXTURE_EXTERNAL_OES;
330 texture_target = GL_TEXTURE_EXTERNAL_OES;
334 auto data = std::make_shared<TexImage2DData>(tex_descriptor.format,
343 size = tex_descriptor.size,
346 ](
const auto& reactor) {
347 auto gl_handle = reactor.GetGLHandle(handle);
348 if (!gl_handle.has_value()) {
350 <<
"Texture was collected before it could be uploaded to the GPU.";
353 const auto& gl = reactor.GetProcTable();
354 gl.BindTexture(texture_type, gl_handle.value());
355 const GLvoid* tex_data =
nullptr;
357 tex_data =
data->data->GetMapping();
361 TRACE_EVENT1(
"impeller",
"TexImage2DUpload",
"Bytes",
362 std::to_string(
data->data->GetSize()).c_str());
363 gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
364 gl.TexImage2D(texture_target,
366 data->internal_format,
370 data->external_format,
377 slices_initialized_ = reactor_->AddOperation(texture_upload);
378 return slices_initialized_[0];
382 ISize TextureGLES::GetSize()
const {
396 return GL_STENCIL_INDEX8;
398 return GL_DEPTH24_STENCIL8;
400 return GL_DEPTH32F_STENCIL8;
425 void TextureGLES::InitializeContentsIfNecessary()
const {
426 if (!
IsValid() || slices_initialized_[0]) {
429 slices_initialized_[0] =
true;
435 auto size = GetSize();
437 if (size.IsEmpty()) {
441 const auto& gl = reactor_->GetProcTable();
442 std::optional<GLuint> handle = reactor_->GetGLHandle(handle_);
443 if (!handle.has_value()) {
444 VALIDATION_LOG <<
"Could not initialize the contents of texture.";
452 if (!tex_data.IsValid()) {
456 gl.BindTexture(GL_TEXTURE_2D, handle.value());
458 TRACE_EVENT0(
"impeller",
"TexImage2DInitialization");
459 gl.TexImage2D(GL_TEXTURE_2D,
461 tex_data.internal_format,
465 tex_data.external_format,
473 auto render_buffer_format =
475 if (!render_buffer_format.has_value()) {
479 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
485 if (gl.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
486 gl.RenderbufferStorageMultisampleEXT(
489 render_buffer_format.value(),
494 gl.RenderbufferStorageMultisample(
497 render_buffer_format.value(),
503 gl.RenderbufferStorage(
505 render_buffer_format.value(),
519 return reactor_->GetGLHandle(handle_);
524 if (!handle.has_value()) {
527 const auto& gl = reactor_->GetProcTable();
529 if (fence_.has_value()) {
530 std::optional<GLsync> fence = reactor_->GetGLFence(fence_.value());
531 if (fence.has_value()) {
532 gl.WaitSync(fence.value(), 0, GL_TIMEOUT_IGNORED);
534 reactor_->CollectHandle(fence_.value());
535 fence_ = std::nullopt;
542 if (!target.has_value()) {
546 gl.BindTexture(target.value(), handle.value());
550 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
553 InitializeContentsIfNecessary();
558 for (
size_t i = 0; i < slices_initialized_.size(); i++) {
559 slices_initialized_[i] =
true;
564 slices_initialized_[slice] =
true;
568 return slices_initialized_[slice];
581 VALIDATION_LOG <<
"Generating mipmaps for multisample textures is not "
582 "supported in the GLES backend.";
595 if (!handle.has_value()) {
599 const auto& gl = reactor_->GetProcTable();
612 return GL_COLOR_ATTACHMENT0;
614 return GL_DEPTH_ATTACHMENT;
616 return GL_STENCIL_ATTACHMENT;
626 InitializeContentsIfNecessary();
628 if (!handle.has_value()) {
631 const auto& gl = reactor_->GetProcTable();
635 gl.FramebufferTexture2D(target,
643 gl.FramebufferTexture2DMultisampleEXT(
654 gl.FramebufferRenderbuffer(
667 Scalar TextureGLES::GetYCoordScale()
const {
686 FML_DCHECK(!fence_.has_value());
Represents a handle to an underlying OpenGL object. Unlike OpenGL object handles, these handles can b...
constexpr bool IsDead() const
Determines if the handle is dead.
HandleType GetType() const
static HandleGLES DeadHandle()
Creates a dead handle.
std::function< void(const ReactorGLES &reactor)> Operation
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.
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 IsSliceInitialized(size_t slice) const
@ kRenderBufferMultisampled
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)
bool SetAsFramebufferAttachment(GLenum target, AttachmentType attachment_type) const
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....
std::optional< GLuint > GetFBO() const
Type ComputeTypeForBinding(GLenum target) const
void MarkSliceInitialized(size_t slice) const
Indicates that a specific texture slice has been initialized.
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...
const TextureDescriptor & GetTextureDescriptor() const
TextureCoordinateSystem GetCoordinateSystem() const
const ProcTable & GetProcTable()
std::shared_ptr< fml::Mapping > CreateMappingWithCopy(const uint8_t *contents, Bytes length)
Creates a mapping with copy of the bytes.
AllocationSize< 1u > Bytes
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
constexpr GLenum ToTextureType(TextureType type)
static std::optional< GLenum > ToRenderBufferFormat(PixelFormat format)
constexpr std::optional< GLenum > ToTextureTarget(TextureType type)
static GLenum ToAttachmentType(TextureGLES::AttachmentType point)
Mask< TextureUsage > TextureUsageMask
HandleType ToHandleType(TextureGLES::Type type)
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
std::shared_ptr< const fml::Mapping > data