11 #include "flutter/fml/logging.h"
12 #include "flutter/fml/mapping.h"
13 #include "flutter/fml/trace_event.h"
23 static bool IsDepthStencilFormat(
PixelFormat format) {
66 const TextureDescriptor& desc,
67 const std::shared_ptr<const CapabilitiesGLES>& capabilities) {
71 if (usage == render_target && IsDepthStencilFormat(desc.format)) {
75 return is_msaa ? (capabilities->SupportsImplicitResolvingMSAA()
96 std::shared_ptr<ReactorGLES>
reactor,
99 auto texture = std::shared_ptr<TextureGLES>(
101 if (!texture->IsValid()) {
108 std::shared_ptr<ReactorGLES>
reactor,
111 if (external_handle.
IsDead()) {
119 auto texture = std::shared_ptr<TextureGLES>(
new TextureGLES(
120 std::move(
reactor), desc,
false, std::nullopt, external_handle));
121 if (!texture->IsValid()) {
128 std::shared_ptr<ReactorGLES>
reactor,
146 std::optional<GLuint> fbo,
147 std::optional<HandleGLES> external_handle)
150 type_(GetTextureTypeFromDescriptor(
151 GetTextureDescriptor(),
154 external_handle.has_value()
160 is_wrapped_(fbo.has_value() || external_handle.has_value()),
168 const auto max_size =
169 reactor_->GetProcTable().GetCapabilities()->max_texture_size;
170 if (tex_size.Max(max_size) != max_size) {
172 <<
" would exceed max supported size of " << max_size <<
".";
189 void TextureGLES::SetLabel(std::string_view label) {
190 #ifdef IMPELLER_DEBUG
191 reactor_->SetDebugLabel(handle_.
Get(), label);
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));
206 bool TextureGLES::OnSetContents(
const uint8_t* contents,
213 bool TextureGLES::OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
219 if (mapping->GetSize() == 0u) {
223 if (mapping->GetMapping() ==
nullptr) {
228 VALIDATION_LOG <<
"Incorrect texture usage flags for setting contents on "
229 "this texture object.";
234 VALIDATION_LOG <<
"Cannot set the contents of a wrapped texture.";
240 if (tex_descriptor.size.IsEmpty()) {
244 if (!tex_descriptor.IsValid() ||
245 mapping->GetSize() < tex_descriptor.GetByteSizeOfBaseMipLevel()) {
250 GLenum texture_target;
251 switch (tex_descriptor.type) {
253 texture_type = GL_TEXTURE_2D;
254 texture_target = GL_TEXTURE_2D;
257 VALIDATION_LOG <<
"Multisample texture uploading is not supported for "
258 "the OpenGLES backend.";
261 texture_type = GL_TEXTURE_CUBE_MAP;
262 texture_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
265 texture_type = GL_TEXTURE_EXTERNAL_OES;
266 texture_target = GL_TEXTURE_EXTERNAL_OES;
270 std::optional<PixelFormatGLES> gles_format =
273 reactor_->GetProcTable().GetDescription()->HasExtension(
274 "GL_EXT_texture_format_BGRA8888"));
275 if (!gles_format.has_value()) {
281 [handle = handle_.
Get(),
283 format = gles_format.value(),
284 size = tex_descriptor.size,
285 image_size = tex_descriptor.GetByteSizeOfBaseMipLevel(),
289 auto gl_handle =
reactor.GetGLHandle(handle);
290 if (!gl_handle.has_value()) {
291 VALIDATION_LOG <<
"Texture was collected before it could be uploaded "
295 const auto& gl =
reactor.GetProcTable();
296 gl.BindTexture(texture_type, gl_handle.value());
297 const GLvoid* tex_data =
nullptr;
299 tex_data = mapping->GetMapping();
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,
309 format.internal_format,
316 gl.TexImage2D(texture_target,
318 format.internal_format,
322 format.external_format,
329 const bool added = reactor_->AddOperation(texture_upload);
337 ISize TextureGLES::GetSize()
const {
351 return GL_STENCIL_INDEX8;
353 return GL_DEPTH24_STENCIL8;
355 return GL_DEPTH32F_STENCIL8;
397 void TextureGLES::InitializeContentsIfNecessary() {
408 auto size = GetSize();
410 if (size.IsEmpty()) {
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.";
429 reactor_->GetProcTable().GetDescription()->HasExtension(
430 "GL_EXT_texture_format_BGRA8888"));
431 if (!gles_format.has_value()) {
435 TRACE_EVENT0(
"impeller",
"TexImage2DInitialization");
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,
446 gles_format->internal_format,
450 gles_format->external_format,
463 gl.BindTexture(GL_TEXTURE_2D, handle.value());
464 gl.TexImage2D(GL_TEXTURE_2D,
466 gles_format->internal_format,
470 gles_format->external_format,
479 auto render_buffer_format =
481 if (!render_buffer_format.has_value()) {
485 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
491 if (gl.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
492 gl.RenderbufferStorageMultisampleEXT(
495 render_buffer_format.value(),
500 gl.RenderbufferStorageMultisample(
503 render_buffer_format.value(),
509 gl.RenderbufferStorage(
511 render_buffer_format.value(),
529 return reactor_->GetGLHandle(handle_.
Get());
534 if (!handle.has_value()) {
537 const auto& gl = reactor_->GetProcTable();
540 std::optional<GLsync> fence = reactor_->GetGLFence(fence_.
Get());
541 if (fence.has_value()) {
542 gl.WaitSync(fence.value(), 0, GL_TIMEOUT_IGNORED);
551 if (!target.has_value()) {
555 gl.BindTexture(target.value(), handle.value());
559 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
562 InitializeContentsIfNecessary();
567 for (
auto& slice_mips : slice_mip_initialized_) {
581 if (slice >= slice_mip_initialized_.size() ||
582 mip_level >= kMaxTrackedMipLevels) {
585 slice_mip_initialized_[slice].set(mip_level);
589 size_t mip_level)
const {
590 if (slice >= slice_mip_initialized_.size() ||
591 mip_level >= kMaxTrackedMipLevels) {
594 return slice_mip_initialized_[slice].test(mip_level);
607 VALIDATION_LOG <<
"Generating mipmaps for multisample textures is not "
608 "supported in the GLES backend.";
621 if (!handle.has_value()) {
625 const auto& gl = reactor_->GetProcTable();
638 return GL_COLOR_ATTACHMENT0;
640 return GL_DEPTH_ATTACHMENT;
642 return GL_STENCIL_ATTACHMENT;
646 bool TextureGLES::EnsureSliceMipLevelStorage(
size_t slice,
size_t mip_level) {
656 if (!handle.has_value()) {
659 const auto& gl = reactor_->GetProcTable();
663 gl.GetDescription()->HasExtension(
"GL_EXT_texture_format_BGRA8888"));
664 if (!gles_format.has_value()) {
667 ISize size = GetSize();
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,
673 static_cast<GLint
>(mip_level),
674 gles_format->internal_format,
675 static_cast<GLsizei
>(
676 std::max<int64_t>(1, size.width >> mip_level)),
677 static_cast<GLsizei
>(
678 std::max<int64_t>(1, size.height >> mip_level)),
680 gles_format->external_format,
695 InitializeContentsIfNecessary();
696 const auto& gl = reactor_->GetProcTable();
698 !gl.GetCapabilities()->SupportsFramebufferRenderMipmap()) {
699 VALIDATION_LOG <<
"Rendering into a non-zero mip level is not supported on "
703 if (!EnsureSliceMipLevelStorage(slice, mip_level)) {
707 if (!handle.has_value()) {
710 const GLint level =
static_cast<GLint
>(mip_level);
717 ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice
719 gl.FramebufferTexture2D(target,
728 gl.FramebufferTexture2DMultisampleEXT(
739 gl.FramebufferRenderbuffer(
766 return fence_.
IsValid() ? std::optional(fence_.
Get()) : std::nullopt;
774 return cached_fbo_.
Get();
778 cached_fbo_mip_level_ = mip_level;
779 cached_fbo_slice_ = slice;
783 uint32_t slice)
const {
784 return cached_fbo_mip_level_ == mip_level && cached_fbo_slice_ == slice;
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
std::function< void(const ReactorGLES &reactor)> Operation
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.
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.
@ kRenderBufferMultisampled
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...
const TextureDescriptor & GetTextureDescriptor() const
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.
const ProcTable & GetProcTable()
std::optional< PixelFormatGLES > ToPixelFormatGLES(PixelFormat pixel_format, bool supports_bgra)
std::shared_ptr< fml::Mapping > CreateMappingWithCopy(const uint8_t *contents, Bytes length)
Creates a mapping with copy of the 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)
std::shared_ptr< ReactorGLES > reactor
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...