10 #include "flutter/fml/logging.h"
11 #include "flutter/fml/mapping.h"
12 #include "flutter/fml/trace_event.h"
23 static bool IsDepthStencilFormat(
PixelFormat format) {
48 const TextureDescriptor& desc,
49 const std::shared_ptr<const CapabilitiesGLES>& capabilities) {
53 if (usage == render_target && IsDepthStencilFormat(desc.format)) {
57 return is_msaa ? (capabilities->SupportsImplicitResolvingMSAA()
63 struct TexImage2DData {
67 std::shared_ptr<const fml::Mapping>
data;
70 switch (pixel_format) {
74 type = GL_UNSIGNED_BYTE;
79 type = GL_UNSIGNED_BYTE;
87 type = GL_UNSIGNED_BYTE;
108 type = GL_UNSIGNED_INT_24_8;
122 std::shared_ptr<const fml::Mapping> mapping)
123 : TexImage2DData(pixel_format) {
124 data = std::move(mapping);
127 bool IsValid()
const {
return is_valid_; }
130 bool is_valid_ =
false;
147 std::shared_ptr<ReactorGLES> reactor,
150 auto texture = std::shared_ptr<TextureGLES>(
151 new TextureGLES(std::move(reactor), desc, fbo, std::nullopt));
152 if (!texture->IsValid()) {
159 std::shared_ptr<ReactorGLES> reactor,
162 if (external_handle.
IsDead()) {
170 auto texture = std::shared_ptr<TextureGLES>(
171 new TextureGLES(std::move(reactor), desc, std::nullopt, external_handle));
172 if (!texture->IsValid()) {
179 std::shared_ptr<ReactorGLES> reactor,
194 std::optional<GLuint> fbo,
195 std::optional<HandleGLES> external_handle)
197 reactor_(
std::move(reactor)),
198 type_(GetTextureTypeFromDescriptor(
199 GetTextureDescriptor(),
201 handle_(external_handle.has_value()
202 ? external_handle.
value()
203 : reactor_->CreateUntrackedHandle(
ToHandleType(type_))),
204 is_wrapped_(fbo.has_value() || external_handle.has_value()),
213 const auto max_size =
214 reactor_->GetProcTable().GetCapabilities()->max_texture_size;
215 if (tex_size.Max(max_size) != max_size) {
217 <<
" would exceed max supported size of " << max_size <<
".";
226 reactor_->CollectHandle(handle_);
227 if (!cached_fbo_.
IsDead()) {
228 reactor_->CollectHandle(cached_fbo_);
238 void TextureGLES::SetLabel(std::string_view label) {
239 #ifdef IMPELLER_DEBUG
240 reactor_->SetDebugLabel(handle_, label);
245 void TextureGLES::SetLabel(std::string_view label, std::string_view trailing) {
246 #ifdef IMPELLER_DEBUG
247 if (reactor_->CanSetDebugLabels()) {
248 reactor_->SetDebugLabel(handle_,
249 SPrintF(
"%s %s", label.data(), trailing.data()));
255 bool TextureGLES::OnSetContents(
const uint8_t* contents,
262 bool TextureGLES::OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
268 if (mapping->GetSize() == 0u) {
272 if (mapping->GetMapping() ==
nullptr) {
277 VALIDATION_LOG <<
"Incorrect texture usage flags for setting contents on "
278 "this texture object.";
283 VALIDATION_LOG <<
"Cannot set the contents of a wrapped texture.";
289 if (tex_descriptor.size.IsEmpty()) {
293 if (!tex_descriptor.IsValid() ||
294 mapping->GetSize() < tex_descriptor.GetByteSizeOfBaseMipLevel()) {
299 GLenum texture_target;
300 switch (tex_descriptor.type) {
302 texture_type = GL_TEXTURE_2D;
303 texture_target = GL_TEXTURE_2D;
306 VALIDATION_LOG <<
"Multisample texture uploading is not supported for "
307 "the OpenGLES backend.";
310 texture_type = GL_TEXTURE_CUBE_MAP;
311 texture_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
314 texture_type = GL_TEXTURE_EXTERNAL_OES;
315 texture_target = GL_TEXTURE_EXTERNAL_OES;
319 auto data = std::make_shared<TexImage2DData>(tex_descriptor.format,
328 size = tex_descriptor.size,
331 ](
const auto& reactor) {
332 auto gl_handle = reactor.GetGLHandle(handle);
333 if (!gl_handle.has_value()) {
335 <<
"Texture was collected before it could be uploaded to the GPU.";
338 const auto& gl = reactor.GetProcTable();
339 gl.BindTexture(texture_type, gl_handle.value());
340 const GLvoid* tex_data =
nullptr;
342 tex_data =
data->data->GetMapping();
346 TRACE_EVENT1(
"impeller",
"TexImage2DUpload",
"Bytes",
347 std::to_string(
data->data->GetSize()).c_str());
348 gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
349 gl.TexImage2D(texture_target,
351 data->internal_format,
355 data->external_format,
362 slices_initialized_ = reactor_->AddOperation(texture_upload);
363 return slices_initialized_[0];
367 ISize TextureGLES::GetSize()
const {
381 return GL_STENCIL_INDEX8;
383 return GL_DEPTH24_STENCIL8;
385 return GL_DEPTH32F_STENCIL8;
409 void TextureGLES::InitializeContentsIfNecessary()
const {
410 if (!
IsValid() || slices_initialized_[0]) {
413 slices_initialized_[0] =
true;
419 auto size = GetSize();
421 if (size.IsEmpty()) {
425 const auto& gl = reactor_->GetProcTable();
426 std::optional<GLuint> handle = reactor_->GetGLHandle(handle_);
427 if (!handle.has_value()) {
428 VALIDATION_LOG <<
"Could not initialize the contents of texture.";
436 if (!tex_data.IsValid()) {
440 gl.BindTexture(GL_TEXTURE_2D, handle.value());
442 TRACE_EVENT0(
"impeller",
"TexImage2DInitialization");
443 gl.TexImage2D(GL_TEXTURE_2D,
445 tex_data.internal_format,
449 tex_data.external_format,
457 auto render_buffer_format =
459 if (!render_buffer_format.has_value()) {
463 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
469 if (gl.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
470 gl.RenderbufferStorageMultisampleEXT(
473 render_buffer_format.value(),
478 gl.RenderbufferStorageMultisample(
481 render_buffer_format.value(),
487 gl.RenderbufferStorage(
489 render_buffer_format.value(),
503 return reactor_->GetGLHandle(handle_);
508 if (!handle.has_value()) {
511 const auto& gl = reactor_->GetProcTable();
513 if (fence_.has_value()) {
514 std::optional<GLsync> fence = reactor_->GetGLFence(fence_.value());
515 if (fence.has_value()) {
516 gl.WaitSync(fence.value(), 0, GL_TIMEOUT_IGNORED);
518 reactor_->CollectHandle(fence_.value());
519 fence_ = std::nullopt;
526 if (!target.has_value()) {
530 gl.BindTexture(target.value(), handle.value());
534 gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
537 InitializeContentsIfNecessary();
542 for (
size_t i = 0; i < slices_initialized_.size(); i++) {
543 slices_initialized_[i] =
true;
548 slices_initialized_[slice] =
true;
552 return slices_initialized_[slice];
565 VALIDATION_LOG <<
"Generating mipmaps for multisample textures is not "
566 "supported in the GLES backend.";
579 if (!handle.has_value()) {
583 const auto& gl = reactor_->GetProcTable();
596 return GL_COLOR_ATTACHMENT0;
598 return GL_DEPTH_ATTACHMENT;
600 return GL_STENCIL_ATTACHMENT;
610 InitializeContentsIfNecessary();
612 if (!handle.has_value()) {
615 const auto& gl = reactor_->GetProcTable();
619 gl.FramebufferTexture2D(target,
627 gl.FramebufferTexture2DMultisampleEXT(
638 gl.FramebufferRenderbuffer(
651 Scalar TextureGLES::GetYCoordScale()
const {
670 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
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 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