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) {
49 const TextureDescriptor& desc,
50 const std::shared_ptr<const CapabilitiesGLES>& capabilities) {
54 if (usage == render_target && IsDepthStencilFormat(desc.format)) {
58 return is_msaa ? (capabilities->SupportsImplicitResolvingMSAA()
79 std::shared_ptr<ReactorGLES> reactor,
82 auto texture = std::shared_ptr<TextureGLES>(
83 new TextureGLES(std::move(reactor), desc,
false, fbo, std::nullopt));
84 if (!texture->IsValid()) {
91 std::shared_ptr<ReactorGLES> reactor,
94 if (external_handle.
IsDead()) {
102 auto texture = std::shared_ptr<TextureGLES>(
new TextureGLES(
103 std::move(reactor), desc,
false, std::nullopt, external_handle));
104 if (!texture->IsValid()) {
111 std::shared_ptr<ReactorGLES> reactor,
129 std::optional<GLuint> fbo,
130 std::optional<HandleGLES> external_handle)
132 reactor_(
std::move(reactor)),
133 type_(GetTextureTypeFromDescriptor(
134 GetTextureDescriptor(),
136 handle_(external_handle.has_value()
137 ? external_handle.
value()
138 : (threadsafe ? reactor_->CreateHandle(
ToHandleType(type_))
139 : reactor_->CreateUntrackedHandle(
141 is_wrapped_(fbo.has_value() || external_handle.has_value()),
149 const auto max_size =
150 reactor_->GetProcTable().GetCapabilities()->max_texture_size;
151 if (tex_size.Max(max_size) != max_size) {
153 <<
" would exceed max supported size of " << max_size <<
".";
162 reactor_->CollectHandle(handle_);
163 if (!cached_fbo_.
IsDead()) {
164 reactor_->CollectHandle(cached_fbo_);
178 void TextureGLES::SetLabel(std::string_view label) {
179 #ifdef IMPELLER_DEBUG
180 reactor_->SetDebugLabel(handle_, label);
185 void TextureGLES::SetLabel(std::string_view label, std::string_view trailing) {
186 #ifdef IMPELLER_DEBUG
187 if (reactor_->CanSetDebugLabels()) {
188 reactor_->SetDebugLabel(handle_, std::format(
"{} {}", label, trailing));
194 bool TextureGLES::OnSetContents(
const uint8_t* contents,
201 bool TextureGLES::OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
207 if (mapping->GetSize() == 0u) {
211 if (mapping->GetMapping() ==
nullptr) {
216 VALIDATION_LOG <<
"Incorrect texture usage flags for setting contents on "
217 "this texture object.";
222 VALIDATION_LOG <<
"Cannot set the contents of a wrapped texture.";
228 if (tex_descriptor.size.IsEmpty()) {
232 if (!tex_descriptor.IsValid() ||
233 mapping->GetSize() < tex_descriptor.GetByteSizeOfBaseMipLevel()) {
238 GLenum texture_target;
239 switch (tex_descriptor.type) {
241 texture_type = GL_TEXTURE_2D;
242 texture_target = GL_TEXTURE_2D;
245 VALIDATION_LOG <<
"Multisample texture uploading is not supported for "
246 "the OpenGLES backend.";
249 texture_type = GL_TEXTURE_CUBE_MAP;
250 texture_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
253 texture_type = GL_TEXTURE_EXTERNAL_OES;
254 texture_target = GL_TEXTURE_EXTERNAL_OES;
258 std::optional<PixelFormatGLES> gles_format =
261 reactor_->GetProcTable().GetDescription()->HasExtension(
262 "GL_EXT_texture_format_BGRA8888"));
263 if (!gles_format.has_value()) {
270 format = gles_format.value(),
271 size = tex_descriptor.size,
274 ](
const auto& reactor) {
275 auto gl_handle = reactor.GetGLHandle(handle);
276 if (!gl_handle.has_value()) {
278 <<
"Texture was collected before it could be uploaded to the GPU.";
281 const auto& gl = reactor.GetProcTable();
282 gl.BindTexture(texture_type, gl_handle.value());
283 const GLvoid* tex_data =
nullptr;
285 tex_data = mapping->GetMapping();
289 TRACE_EVENT1(
"impeller",
"TexImage2DUpload",
"Bytes",
290 std::to_string(mapping->GetSize()).c_str());
291 gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
292 gl.TexImage2D(texture_target,
294 format.internal_format,
298 format.external_format,
304 slices_initialized_ = reactor_->AddOperation(texture_upload);
305 return slices_initialized_[0];
309 ISize TextureGLES::GetSize()
const {
323 return GL_STENCIL_INDEX8;
325 return GL_DEPTH24_STENCIL8;
327 return GL_DEPTH32F_STENCIL8;
352 void TextureGLES::InitializeContentsIfNecessary()
const {
353 if (!
IsValid() || slices_initialized_[0]) {
356 slices_initialized_[0] =
true;
362 auto size = GetSize();
364 if (size.IsEmpty()) {
368 const auto& gl = reactor_->GetProcTable();
369 std::optional<GLuint> handle = reactor_->GetGLHandle(handle_);
370 if (!handle.has_value()) {
371 VALIDATION_LOG <<
"Could not initialize the contents of texture.";
381 reactor_->GetProcTable().GetDescription()->HasExtension(
382 "GL_EXT_texture_format_BGRA8888"));
383 if (!gles_format.has_value()) {
387 gl.BindTexture(GL_TEXTURE_2D, handle.value());
389 TRACE_EVENT0(
"impeller",
"TexImage2DInitialization");
390 gl.TexImage2D(GL_TEXTURE_2D,
392 gles_format->internal_format,
396 gles_format->external_format,
404 auto render_buffer_format =
406 if (!render_buffer_format.has_value()) {
410 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
416 if (gl.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
417 gl.RenderbufferStorageMultisampleEXT(
420 render_buffer_format.value(),
425 gl.RenderbufferStorageMultisample(
428 render_buffer_format.value(),
434 gl.RenderbufferStorage(
436 render_buffer_format.value(),
450 return reactor_->GetGLHandle(handle_);
455 if (!handle.has_value()) {
458 const auto& gl = reactor_->GetProcTable();
460 if (fence_.has_value()) {
461 std::optional<GLsync> fence = reactor_->GetGLFence(fence_.value());
462 if (fence.has_value()) {
463 gl.WaitSync(fence.value(), 0, GL_TIMEOUT_IGNORED);
465 reactor_->CollectHandle(fence_.value());
466 fence_ = std::nullopt;
473 if (!target.has_value()) {
477 gl.BindTexture(target.value(), handle.value());
481 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
484 InitializeContentsIfNecessary();
489 for (
size_t i = 0; i < slices_initialized_.size(); i++) {
490 slices_initialized_[i] =
true;
495 slices_initialized_[slice] =
true;
499 return slices_initialized_[slice];
512 VALIDATION_LOG <<
"Generating mipmaps for multisample textures is not "
513 "supported in the GLES backend.";
526 if (!handle.has_value()) {
530 const auto& gl = reactor_->GetProcTable();
543 return GL_COLOR_ATTACHMENT0;
545 return GL_DEPTH_ATTACHMENT;
547 return GL_STENCIL_ATTACHMENT;
557 InitializeContentsIfNecessary();
559 if (!handle.has_value()) {
562 const auto& gl = reactor_->GetProcTable();
566 gl.FramebufferTexture2D(target,
574 gl.FramebufferTexture2DMultisampleEXT(
585 gl.FramebufferRenderbuffer(
598 Scalar TextureGLES::GetYCoordScale()
const {
617 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::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.
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...