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,
false, 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>(
new TextureGLES(
172 std::move(reactor), desc,
false, std::nullopt, external_handle));
173 if (!texture->IsValid()) {
180 std::shared_ptr<ReactorGLES> reactor,
198 std::optional<GLuint> fbo,
199 std::optional<HandleGLES> external_handle)
201 reactor_(
std::move(reactor)),
202 type_(GetTextureTypeFromDescriptor(
203 GetTextureDescriptor(),
205 handle_(external_handle.has_value()
206 ? external_handle.
value()
207 : (threadsafe ? reactor_->CreateHandle(
ToHandleType(type_))
208 : reactor_->CreateUntrackedHandle(
210 is_wrapped_(fbo.has_value() || external_handle.has_value()),
219 const auto max_size =
220 reactor_->GetProcTable().GetCapabilities()->max_texture_size;
221 if (tex_size.Max(max_size) != max_size) {
223 <<
" would exceed max supported size of " << max_size <<
".";
232 reactor_->CollectHandle(handle_);
233 if (!cached_fbo_.
IsDead()) {
234 reactor_->CollectHandle(cached_fbo_);
248 void TextureGLES::SetLabel(std::string_view label) {
249 #ifdef IMPELLER_DEBUG
250 reactor_->SetDebugLabel(handle_, label);
255 void TextureGLES::SetLabel(std::string_view label, std::string_view trailing) {
256 #ifdef IMPELLER_DEBUG
257 if (reactor_->CanSetDebugLabels()) {
258 reactor_->SetDebugLabel(handle_,
259 SPrintF(
"%s %s", label.data(), trailing.data()));
265 bool TextureGLES::OnSetContents(
const uint8_t* contents,
272 bool TextureGLES::OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
278 if (mapping->GetSize() == 0u) {
282 if (mapping->GetMapping() ==
nullptr) {
287 VALIDATION_LOG <<
"Incorrect texture usage flags for setting contents on "
288 "this texture object.";
293 VALIDATION_LOG <<
"Cannot set the contents of a wrapped texture.";
299 if (tex_descriptor.size.IsEmpty()) {
303 if (!tex_descriptor.IsValid() ||
304 mapping->GetSize() < tex_descriptor.GetByteSizeOfBaseMipLevel()) {
309 GLenum texture_target;
310 switch (tex_descriptor.type) {
312 texture_type = GL_TEXTURE_2D;
313 texture_target = GL_TEXTURE_2D;
316 VALIDATION_LOG <<
"Multisample texture uploading is not supported for "
317 "the OpenGLES backend.";
320 texture_type = GL_TEXTURE_CUBE_MAP;
321 texture_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
324 texture_type = GL_TEXTURE_EXTERNAL_OES;
325 texture_target = GL_TEXTURE_EXTERNAL_OES;
329 auto data = std::make_shared<TexImage2DData>(tex_descriptor.format,
338 size = tex_descriptor.size,
341 ](
const auto& reactor) {
342 auto gl_handle = reactor.GetGLHandle(handle);
343 if (!gl_handle.has_value()) {
345 <<
"Texture was collected before it could be uploaded to the GPU.";
348 const auto& gl = reactor.GetProcTable();
349 gl.BindTexture(texture_type, gl_handle.value());
350 const GLvoid* tex_data =
nullptr;
352 tex_data =
data->data->GetMapping();
356 TRACE_EVENT1(
"impeller",
"TexImage2DUpload",
"Bytes",
357 std::to_string(
data->data->GetSize()).c_str());
358 gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
359 gl.TexImage2D(texture_target,
361 data->internal_format,
365 data->external_format,
372 slices_initialized_ = reactor_->AddOperation(texture_upload);
373 return slices_initialized_[0];
377 ISize TextureGLES::GetSize()
const {
391 return GL_STENCIL_INDEX8;
393 return GL_DEPTH24_STENCIL8;
395 return GL_DEPTH32F_STENCIL8;
419 void TextureGLES::InitializeContentsIfNecessary()
const {
420 if (!
IsValid() || slices_initialized_[0]) {
423 slices_initialized_[0] =
true;
429 auto size = GetSize();
431 if (size.IsEmpty()) {
435 const auto& gl = reactor_->GetProcTable();
436 std::optional<GLuint> handle = reactor_->GetGLHandle(handle_);
437 if (!handle.has_value()) {
438 VALIDATION_LOG <<
"Could not initialize the contents of texture.";
446 if (!tex_data.IsValid()) {
450 gl.BindTexture(GL_TEXTURE_2D, handle.value());
452 TRACE_EVENT0(
"impeller",
"TexImage2DInitialization");
453 gl.TexImage2D(GL_TEXTURE_2D,
455 tex_data.internal_format,
459 tex_data.external_format,
467 auto render_buffer_format =
469 if (!render_buffer_format.has_value()) {
473 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
479 if (gl.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
480 gl.RenderbufferStorageMultisampleEXT(
483 render_buffer_format.value(),
488 gl.RenderbufferStorageMultisample(
491 render_buffer_format.value(),
497 gl.RenderbufferStorage(
499 render_buffer_format.value(),
513 return reactor_->GetGLHandle(handle_);
518 if (!handle.has_value()) {
521 const auto& gl = reactor_->GetProcTable();
523 if (fence_.has_value()) {
524 std::optional<GLsync> fence = reactor_->GetGLFence(fence_.value());
525 if (fence.has_value()) {
526 gl.WaitSync(fence.value(), 0, GL_TIMEOUT_IGNORED);
528 reactor_->CollectHandle(fence_.value());
529 fence_ = std::nullopt;
536 if (!target.has_value()) {
540 gl.BindTexture(target.value(), handle.value());
544 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
547 InitializeContentsIfNecessary();
552 for (
size_t i = 0; i < slices_initialized_.size(); i++) {
553 slices_initialized_[i] =
true;
558 slices_initialized_[slice] =
true;
562 return slices_initialized_[slice];
575 VALIDATION_LOG <<
"Generating mipmaps for multisample textures is not "
576 "supported in the GLES backend.";
589 if (!handle.has_value()) {
593 const auto& gl = reactor_->GetProcTable();
606 return GL_COLOR_ATTACHMENT0;
608 return GL_DEPTH_ATTACHMENT;
610 return GL_STENCIL_ATTACHMENT;
620 InitializeContentsIfNecessary();
622 if (!handle.has_value()) {
625 const auto& gl = reactor_->GetProcTable();
629 gl.FramebufferTexture2D(target,
637 gl.FramebufferTexture2DMultisampleEXT(
648 gl.FramebufferRenderbuffer(
661 Scalar TextureGLES::GetYCoordScale()
const {
680 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
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