10 #include "flutter/fml/logging.h"
11 #include "flutter/fml/mapping.h"
12 #include "flutter/fml/trace_event.h"
24 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()
64 struct TexImage2DData {
68 std::shared_ptr<const fml::Mapping>
data;
71 switch (pixel_format) {
75 type = GL_UNSIGNED_BYTE;
80 type = GL_UNSIGNED_BYTE;
88 type = GL_UNSIGNED_BYTE;
109 type = GL_UNSIGNED_INT_24_8;
123 std::shared_ptr<const fml::Mapping> mapping)
124 : TexImage2DData(pixel_format) {
125 data = std::move(mapping);
128 bool IsValid()
const {
return is_valid_; }
131 bool is_valid_ =
false;
148 std::shared_ptr<ReactorGLES> reactor,
151 auto texture = std::shared_ptr<TextureGLES>(
152 new TextureGLES(std::move(reactor), desc, fbo, std::nullopt));
153 if (!texture->IsValid()) {
160 std::shared_ptr<ReactorGLES> reactor,
163 if (external_handle.
IsDead()) {
171 auto texture = std::shared_ptr<TextureGLES>(
172 new TextureGLES(std::move(reactor), desc, std::nullopt, external_handle));
173 if (!texture->IsValid()) {
180 std::shared_ptr<ReactorGLES> reactor,
195 std::optional<GLuint> fbo,
196 std::optional<HandleGLES> external_handle)
198 reactor_(
std::move(reactor)),
199 type_(GetTextureTypeFromDescriptor(
200 GetTextureDescriptor(),
202 handle_(external_handle.has_value()
203 ? external_handle.
value()
204 : reactor_->CreateUntrackedHandle(
ToHandleType(type_))),
205 is_wrapped_(fbo.has_value() || external_handle.has_value()),
214 const auto max_size =
215 reactor_->GetProcTable().GetCapabilities()->max_texture_size;
216 if (tex_size.Max(max_size) != max_size) {
218 <<
" would exceed max supported size of " << max_size <<
".";
227 reactor_->CollectHandle(handle_);
228 if (!cached_fbo_.
IsDead()) {
229 reactor_->CollectHandle(cached_fbo_);
243 void TextureGLES::SetLabel(std::string_view label) {
244 #ifdef IMPELLER_DEBUG
245 reactor_->SetDebugLabel(handle_, label);
250 void TextureGLES::SetLabel(std::string_view label, std::string_view trailing) {
251 #ifdef IMPELLER_DEBUG
252 if (reactor_->CanSetDebugLabels()) {
253 reactor_->SetDebugLabel(handle_,
254 SPrintF(
"%s %s", label.data(), trailing.data()));
260 bool TextureGLES::OnSetContents(
const uint8_t* contents,
267 bool TextureGLES::OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
273 if (mapping->GetSize() == 0u) {
277 if (mapping->GetMapping() ==
nullptr) {
282 VALIDATION_LOG <<
"Incorrect texture usage flags for setting contents on "
283 "this texture object.";
288 VALIDATION_LOG <<
"Cannot set the contents of a wrapped texture.";
294 if (tex_descriptor.size.IsEmpty()) {
298 if (!tex_descriptor.IsValid() ||
299 mapping->GetSize() < tex_descriptor.GetByteSizeOfBaseMipLevel()) {
304 GLenum texture_target;
305 switch (tex_descriptor.type) {
307 texture_type = GL_TEXTURE_2D;
308 texture_target = GL_TEXTURE_2D;
311 VALIDATION_LOG <<
"Multisample texture uploading is not supported for "
312 "the OpenGLES backend.";
315 texture_type = GL_TEXTURE_CUBE_MAP;
316 texture_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
319 texture_type = GL_TEXTURE_EXTERNAL_OES;
320 texture_target = GL_TEXTURE_EXTERNAL_OES;
324 auto data = std::make_shared<TexImage2DData>(tex_descriptor.format,
333 size = tex_descriptor.size,
336 ](
const auto& reactor) {
337 auto gl_handle = reactor.GetGLHandle(handle);
338 if (!gl_handle.has_value()) {
340 <<
"Texture was collected before it could be uploaded to the GPU.";
343 const auto& gl = reactor.GetProcTable();
344 gl.BindTexture(texture_type, gl_handle.value());
345 const GLvoid* tex_data =
nullptr;
347 tex_data =
data->data->GetMapping();
351 TRACE_EVENT1(
"impeller",
"TexImage2DUpload",
"Bytes",
352 std::to_string(
data->data->GetSize()).c_str());
353 gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
354 gl.TexImage2D(texture_target,
356 data->internal_format,
360 data->external_format,
367 slices_initialized_ = reactor_->AddOperation(texture_upload);
368 return slices_initialized_[0];
372 ISize TextureGLES::GetSize()
const {
386 return GL_STENCIL_INDEX8;
388 return GL_DEPTH24_STENCIL8;
390 return GL_DEPTH32F_STENCIL8;
414 void TextureGLES::InitializeContentsIfNecessary()
const {
415 if (!
IsValid() || slices_initialized_[0]) {
418 slices_initialized_[0] =
true;
424 auto size = GetSize();
426 if (size.IsEmpty()) {
430 const auto& gl = reactor_->GetProcTable();
431 std::optional<GLuint> handle = reactor_->GetGLHandle(handle_);
432 if (!handle.has_value()) {
433 VALIDATION_LOG <<
"Could not initialize the contents of texture.";
441 if (!tex_data.IsValid()) {
445 gl.BindTexture(GL_TEXTURE_2D, handle.value());
447 TRACE_EVENT0(
"impeller",
"TexImage2DInitialization");
448 gl.TexImage2D(GL_TEXTURE_2D,
450 tex_data.internal_format,
454 tex_data.external_format,
462 auto render_buffer_format =
464 if (!render_buffer_format.has_value()) {
468 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
474 if (gl.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
475 gl.RenderbufferStorageMultisampleEXT(
478 render_buffer_format.value(),
483 gl.RenderbufferStorageMultisample(
486 render_buffer_format.value(),
492 gl.RenderbufferStorage(
494 render_buffer_format.value(),
508 return reactor_->GetGLHandle(handle_);
513 if (!handle.has_value()) {
516 const auto& gl = reactor_->GetProcTable();
518 if (fence_.has_value()) {
519 std::optional<GLsync> fence = reactor_->GetGLFence(fence_.value());
520 if (fence.has_value()) {
521 gl.WaitSync(fence.value(), 0, GL_TIMEOUT_IGNORED);
523 reactor_->CollectHandle(fence_.value());
524 fence_ = std::nullopt;
531 if (!target.has_value()) {
535 gl.BindTexture(target.value(), handle.value());
539 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
542 InitializeContentsIfNecessary();
547 for (
size_t i = 0; i < slices_initialized_.size(); i++) {
548 slices_initialized_[i] =
true;
553 slices_initialized_[slice] =
true;
557 return slices_initialized_[slice];
570 VALIDATION_LOG <<
"Generating mipmaps for multisample textures is not "
571 "supported in the GLES backend.";
584 if (!handle.has_value()) {
588 const auto& gl = reactor_->GetProcTable();
601 return GL_COLOR_ATTACHMENT0;
603 return GL_DEPTH_ATTACHMENT;
605 return GL_STENCIL_ATTACHMENT;
615 InitializeContentsIfNecessary();
617 if (!handle.has_value()) {
620 const auto& gl = reactor_->GetProcTable();
624 gl.FramebufferTexture2D(target,
632 gl.FramebufferTexture2DMultisampleEXT(
643 gl.FramebufferRenderbuffer(
656 Scalar TextureGLES::GetYCoordScale()
const {
675 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)
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....
TextureGLES(std::shared_ptr< ReactorGLES > reactor, TextureDescriptor desc)
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
std::string SPrintF(const char *format,...)
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