Flutter Impeller
texture_gles.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #include <optional>
8 #include <utility>
9 
10 #include "flutter/fml/logging.h"
11 #include "flutter/fml/mapping.h"
12 #include "flutter/fml/trace_event.h"
15 #include "impeller/core/formats.h"
18 
19 namespace impeller {
20 
21 static bool IsDepthStencilFormat(PixelFormat format) {
22  switch (format) {
26  return true;
40  return false;
41  }
42  FML_UNREACHABLE();
43 }
44 
46  const TextureDescriptor& desc) {
47  const auto usage = static_cast<TextureUsageMask>(desc.usage);
48  const auto render_target = TextureUsage::kRenderTarget;
49  const auto is_msaa = desc.sample_count == SampleCount::kCount4;
50  if (usage == render_target && IsDepthStencilFormat(desc.format)) {
53  }
56 }
57 
59  switch (type) {
62  return HandleType::kTexture;
66  }
67  FML_UNREACHABLE();
68 }
69 
71  : TextureGLES(std::move(reactor), desc, false) {}
72 
74  TextureDescriptor desc,
75  enum IsWrapped wrapped)
76  : TextureGLES(std::move(reactor), desc, true) {}
77 
78 TextureGLES::TextureGLES(std::shared_ptr<ReactorGLES> reactor,
79  TextureDescriptor desc,
80  bool is_wrapped)
81  : Texture(desc),
82  reactor_(std::move(reactor)),
83  type_(GetTextureTypeFromDescriptor(GetTextureDescriptor())),
84  handle_(reactor_->CreateHandle(ToHandleType(type_))),
85  is_wrapped_(is_wrapped) {
86  // Ensure the texture descriptor itself is valid.
87  if (!GetTextureDescriptor().IsValid()) {
88  VALIDATION_LOG << "Invalid texture descriptor.";
89  return;
90  }
91  // Ensure the texture doesn't exceed device capabilities.
92  const auto tex_size = GetTextureDescriptor().size;
93  const auto max_size =
94  reactor_->GetProcTable().GetCapabilities()->max_texture_size;
95  if (tex_size.Max(max_size) != max_size) {
96  VALIDATION_LOG << "Texture of size " << tex_size
97  << " would exceed max supported size of " << max_size << ".";
98  return;
99  }
100 
101  is_valid_ = true;
102 }
103 
104 // |Texture|
106  reactor_->CollectHandle(handle_);
107 }
108 
109 // |Texture|
110 bool TextureGLES::IsValid() const {
111  return is_valid_;
112 }
113 
114 // |Texture|
115 void TextureGLES::SetLabel(std::string_view label) {
116  reactor_->SetDebugLabel(handle_, std::string{label.data(), label.size()});
117 }
118 
120  GLint internal_format = 0;
121  GLenum external_format = GL_NONE;
122  GLenum type = GL_NONE;
123  std::shared_ptr<const fml::Mapping> data;
124 
125  explicit TexImage2DData(PixelFormat pixel_format) {
126  switch (pixel_format) {
128  internal_format = GL_ALPHA;
129  external_format = GL_ALPHA;
130  type = GL_UNSIGNED_BYTE;
131  break;
133  internal_format = GL_RED;
134  external_format = GL_RED;
135  type = GL_UNSIGNED_BYTE;
136  break;
141  internal_format = GL_RGBA;
142  external_format = GL_RGBA;
143  type = GL_UNSIGNED_BYTE;
144  break;
146  internal_format = GL_RGBA;
147  external_format = GL_RGBA;
148  type = GL_FLOAT;
149  break;
151  internal_format = GL_RGBA;
152  external_format = GL_RGBA;
153  type = GL_HALF_FLOAT;
154  break;
156  // Pure stencil textures are only available in OpenGL 4.4+, which is
157  // ~0% of mobile devices. Instead, we use a depth-stencil texture and
158  // only use the stencil component.
159  //
160  // https://registry.khronos.org/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml
162  internal_format = GL_DEPTH_STENCIL;
163  external_format = GL_DEPTH_STENCIL;
164  type = GL_UNSIGNED_INT_24_8;
165  break;
172  return;
173  }
174  is_valid_ = true;
175  }
176 
178  std::shared_ptr<const fml::Mapping> mapping)
179  : TexImage2DData(pixel_format) {
180  data = std::move(mapping);
181  }
182 
183  bool IsValid() const { return is_valid_; }
184 
185  private:
186  bool is_valid_ = false;
187 };
188 
189 // |Texture|
190 bool TextureGLES::OnSetContents(const uint8_t* contents,
191  size_t length,
192  size_t slice) {
193  return OnSetContents(CreateMappingWithCopy(contents, length), slice);
194 }
195 
196 // |Texture|
197 bool TextureGLES::OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
198  size_t slice) {
199  if (!mapping) {
200  return false;
201  }
202 
203  if (mapping->GetSize() == 0u) {
204  return true;
205  }
206 
207  if (mapping->GetMapping() == nullptr) {
208  return false;
209  }
210 
211  if (GetType() != Type::kTexture) {
212  VALIDATION_LOG << "Incorrect texture usage flags for setting contents on "
213  "this texture object.";
214  return false;
215  }
216 
217  if (is_wrapped_) {
218  VALIDATION_LOG << "Cannot set the contents of a wrapped texture.";
219  return false;
220  }
221 
222  const auto& tex_descriptor = GetTextureDescriptor();
223 
224  if (tex_descriptor.size.IsEmpty()) {
225  return true;
226  }
227 
228  if (!tex_descriptor.IsValid()) {
229  return false;
230  }
231 
232  if (mapping->GetSize() < tex_descriptor.GetByteSizeOfBaseMipLevel()) {
233  return false;
234  }
235 
236  GLenum texture_type;
237  GLenum texture_target;
238  switch (tex_descriptor.type) {
240  texture_type = GL_TEXTURE_2D;
241  texture_target = GL_TEXTURE_2D;
242  break;
244  VALIDATION_LOG << "Multisample texture uploading is not supported for "
245  "the OpenGLES backend.";
246  return false;
248  texture_type = GL_TEXTURE_CUBE_MAP;
249  texture_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
250  break;
252  texture_type = GL_TEXTURE_EXTERNAL_OES;
253  texture_target = GL_TEXTURE_EXTERNAL_OES;
254  break;
255  }
256 
257  auto data = std::make_shared<TexImage2DData>(tex_descriptor.format,
258  std::move(mapping));
259  if (!data || !data->IsValid()) {
260  VALIDATION_LOG << "Invalid texture format.";
261  return false;
262  }
263 
264  ReactorGLES::Operation texture_upload = [handle = handle_, //
265  data, //
266  size = tex_descriptor.size, //
267  texture_type, //
268  texture_target //
269  ](const auto& reactor) {
270  auto gl_handle = reactor.GetGLHandle(handle);
271  if (!gl_handle.has_value()) {
273  << "Texture was collected before it could be uploaded to the GPU.";
274  return;
275  }
276  const auto& gl = reactor.GetProcTable();
277  gl.BindTexture(texture_type, gl_handle.value());
278  const GLvoid* tex_data = nullptr;
279  if (data->data) {
280  tex_data = data->data->GetMapping();
281  }
282 
283  {
284  TRACE_EVENT1("impeller", "TexImage2DUpload", "Bytes",
285  std::to_string(data->data->GetSize()).c_str());
286  gl.TexImage2D(texture_target, // target
287  0u, // LOD level
288  data->internal_format, // internal format
289  size.width, // width
290  size.height, // height
291  0u, // border
292  data->external_format, // external format
293  data->type, // type
294  tex_data // data
295  );
296  }
297  };
298 
299  contents_initialized_ = reactor_->AddOperation(texture_upload);
300  return contents_initialized_;
301 }
302 
303 // |Texture|
304 ISize TextureGLES::GetSize() const {
305  return GetTextureDescriptor().size;
306 }
307 
308 static std::optional<GLenum> ToRenderBufferFormat(PixelFormat format) {
309  switch (format) {
312  return GL_RGBA4;
314  return GL_RGBA32F;
316  return GL_RGBA16F;
318  return GL_STENCIL_INDEX8;
320  return GL_DEPTH24_STENCIL8;
322  return GL_DEPTH32F_STENCIL8;
332  return std::nullopt;
333  }
334  FML_UNREACHABLE();
335 }
336 
337 void TextureGLES::InitializeContentsIfNecessary() const {
338  if (!IsValid()) {
339  return;
340  }
341  if (contents_initialized_) {
342  return;
343  }
344  contents_initialized_ = true;
345 
346  if (is_wrapped_) {
347  return;
348  }
349 
350  auto size = GetSize();
351 
352  if (size.IsEmpty()) {
353  return;
354  }
355 
356  const auto& gl = reactor_->GetProcTable();
357  auto handle = reactor_->GetGLHandle(handle_);
358  if (!handle.has_value()) {
359  VALIDATION_LOG << "Could not initialize the contents of texture.";
360  return;
361  }
362 
363  switch (type_) {
364  case Type::kTexture:
366  TexImage2DData tex_data(GetTextureDescriptor().format);
367  if (!tex_data.IsValid()) {
368  VALIDATION_LOG << "Invalid format for texture image.";
369  return;
370  }
371  gl.BindTexture(GL_TEXTURE_2D, handle.value());
372  {
373  TRACE_EVENT0("impeller", "TexImage2DInitialization");
374  gl.TexImage2D(GL_TEXTURE_2D, // target
375  0u, // LOD level (base mip level size checked)
376  tex_data.internal_format, // internal format
377  size.width, // width
378  size.height, // height
379  0u, // border
380  tex_data.external_format, // format
381  tex_data.type, // type
382  nullptr // data
383  );
384  }
385  } break;
386  case Type::kRenderBuffer:
388  auto render_buffer_format =
390  if (!render_buffer_format.has_value()) {
391  VALIDATION_LOG << "Invalid format for render-buffer image.";
392  return;
393  }
394  gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
395  {
396  TRACE_EVENT0("impeller", "RenderBufferStorageInitialization");
397  if (type_ == Type::kRenderBufferMultisampled) {
398  gl.RenderbufferStorageMultisampleEXT(
399  GL_RENDERBUFFER, // target
400  4, // samples
401  render_buffer_format.value(), // internal format
402  size.width, // width
403  size.height // height
404  );
405  } else {
406  gl.RenderbufferStorage(
407  GL_RENDERBUFFER, // target
408  render_buffer_format.value(), // internal format
409  size.width, // width
410  size.height // height
411  );
412  }
413  }
414  } break;
415  }
416 }
417 
418 std::optional<GLuint> TextureGLES::GetGLHandle() const {
419  if (!IsValid()) {
420  return std::nullopt;
421  }
422  return reactor_->GetGLHandle(handle_);
423 }
424 
425 bool TextureGLES::Bind() const {
426  auto handle = GetGLHandle();
427  if (!handle.has_value()) {
428  return false;
429  }
430  const auto& gl = reactor_->GetProcTable();
431  switch (type_) {
432  case Type::kTexture:
434  const auto target = ToTextureTarget(GetTextureDescriptor().type);
435  if (!target.has_value()) {
436  VALIDATION_LOG << "Could not bind texture of this type.";
437  return false;
438  }
439  gl.BindTexture(target.value(), handle.value());
440  } break;
441  case Type::kRenderBuffer:
443  gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
444  break;
445  }
446  InitializeContentsIfNecessary();
447  return true;
448 }
449 
451  if (!IsValid()) {
452  return false;
453  }
454 
455  auto type = GetTextureDescriptor().type;
456  switch (type) {
458  break;
460  VALIDATION_LOG << "Generating mipmaps for multisample textures is not "
461  "supported in the GLES backend.";
462  return false;
464  break;
466  break;
467  }
468 
469  if (!Bind()) {
470  return false;
471  }
472 
473  auto handle = GetGLHandle();
474  if (!handle.has_value()) {
475  return false;
476  }
477 
478  const auto& gl = reactor_->GetProcTable();
479  gl.GenerateMipmap(ToTextureType(type));
480  mipmap_generated_ = true;
481  return true;
482 }
483 
485  return type_;
486 }
487 
489  switch (point) {
491  return GL_COLOR_ATTACHMENT0;
493  return GL_DEPTH_ATTACHMENT;
495  return GL_STENCIL_ATTACHMENT;
496  }
497 }
498 
500  GLenum target,
501  AttachmentType attachment_type) const {
502  if (!IsValid()) {
503  return false;
504  }
505  InitializeContentsIfNecessary();
506  auto handle = GetGLHandle();
507  if (!handle.has_value()) {
508  return false;
509  }
510  const auto& gl = reactor_->GetProcTable();
511 
512  switch (type_) {
513  case Type::kTexture:
514  gl.FramebufferTexture2D(target, // target
515  ToAttachmentType(attachment_type), // attachment
516  GL_TEXTURE_2D, // textarget
517  handle.value(), // texture
518  0 // level
519  );
520  break;
522  gl.FramebufferTexture2DMultisampleEXT(
523  target, // target
524  ToAttachmentType(attachment_type), // attachment
525  GL_TEXTURE_2D, // textarget
526  handle.value(), // texture
527  0, // level
528  4 // samples
529  );
530  break;
531  case Type::kRenderBuffer:
533  gl.FramebufferRenderbuffer(
534  target, // target
535  ToAttachmentType(attachment_type), // attachment
536  GL_RENDERBUFFER, // render-buffer target
537  handle.value() // render-buffer
538  );
539  break;
540  }
541 
542  return true;
543 }
544 
545 // |Texture|
546 Scalar TextureGLES::GetYCoordScale() const {
547  switch (GetCoordinateSystem()) {
549  return 1.0;
551  return -1.0;
552  }
553  FML_UNREACHABLE();
554 }
555 
556 } // namespace impeller
impeller::ReactorGLES::Operation
std::function< void(const ReactorGLES &reactor)> Operation
Definition: reactor_gles.h:195
impeller::TexImage2DData::IsValid
bool IsValid() const
Definition: texture_gles.cc:183
impeller::PixelFormat::kS8UInt
@ kS8UInt
impeller::TextureType::kTextureExternalOES
@ kTextureExternalOES
impeller::TexImage2DData::TexImage2DData
TexImage2DData(PixelFormat pixel_format)
Definition: texture_gles.cc:125
impeller::HandleType::kRenderBuffer
@ kRenderBuffer
impeller::TextureGLES::Type
Type
Definition: texture_gles.h:18
impeller::TextureGLES::Type::kTextureMultisampled
@ kTextureMultisampled
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::TextureGLES::GenerateMipmap
bool GenerateMipmap()
Definition: texture_gles.cc:450
impeller::PixelFormat::kB10G10R10A10XR
@ kB10G10R10A10XR
impeller::PixelFormat::kB8G8R8A8UNormIntSRGB
@ kB8G8R8A8UNormIntSRGB
impeller::TextureGLES::AttachmentType::kDepth
@ kDepth
impeller::PixelFormat::kA8UNormInt
@ kA8UNormInt
allocation.h
impeller::PixelFormat::kR8UNormInt
@ kR8UNormInt
impeller::TextureDescriptor::format
PixelFormat format
Definition: texture_descriptor.h:40
impeller::ReactorGLES::Ref
std::shared_ptr< ReactorGLES > Ref
Definition: reactor_gles.h:87
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
impeller::Texture::GetTextureDescriptor
const TextureDescriptor & GetTextureDescriptor() const
Definition: texture.cc:57
impeller::HandleType
HandleType
Definition: handle_gles.h:22
impeller::TextureGLES::GetGLHandle
std::optional< GLuint > GetGLHandle() const
Definition: texture_gles.cc:418
texture_descriptor.h
impeller::HandleType::kTexture
@ kTexture
formats.h
texture_gles.h
impeller::TexImage2DData
Definition: texture_gles.cc:119
impeller::TextureGLES::Type::kRenderBufferMultisampled
@ kRenderBufferMultisampled
impeller::TextureUsage::kRenderTarget
@ kRenderTarget
impeller::TexImage2DData::internal_format
GLint internal_format
Definition: texture_gles.cc:120
impeller::TextureGLES::AttachmentType::kColor0
@ kColor0
impeller::TextureDescriptor::sample_count
SampleCount sample_count
Definition: texture_descriptor.h:44
validation.h
impeller::TextureDescriptor::usage
TextureUsageMask usage
Definition: texture_descriptor.h:43
impeller::PixelFormat::kD32FloatS8UInt
@ kD32FloatS8UInt
impeller::PixelFormat
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:100
impeller::TextureCoordinateSystem::kUploadFromHost
@ kUploadFromHost
impeller::TextureDescriptor::type
TextureType type
Definition: texture_descriptor.h:39
impeller::Mask< TextureUsage >
impeller::TextureType::kTexture2DMultisample
@ kTexture2DMultisample
impeller::TextureCoordinateSystem::kRenderToTexture
@ kRenderToTexture
impeller::Texture
Definition: texture.h:17
impeller::TextureGLES::Type::kRenderBuffer
@ kRenderBuffer
impeller::TextureGLES::TextureGLES
TextureGLES(ReactorGLES::Ref reactor, TextureDescriptor desc)
Definition: texture_gles.cc:70
impeller::GetTextureTypeFromDescriptor
static TextureGLES::Type GetTextureTypeFromDescriptor(const TextureDescriptor &desc)
Definition: texture_gles.cc:45
impeller::PixelFormat::kR8G8UNormInt
@ kR8G8UNormInt
impeller::IsDepthStencilFormat
static bool IsDepthStencilFormat(PixelFormat format)
Definition: texture_gles.cc:21
impeller::PixelFormat::kB10G10R10XR
@ kB10G10R10XR
impeller::PixelFormat::kD24UnormS8Uint
@ kD24UnormS8Uint
impeller::TextureType::kTextureCube
@ kTextureCube
impeller::PixelFormat::kR16G16B16A16Float
@ kR16G16B16A16Float
impeller::ToHandleType
HandleType ToHandleType(TextureGLES::Type type)
Definition: texture_gles.cc:58
impeller::ToTextureType
constexpr GLenum ToTextureType(TextureType type)
Definition: formats_gles.h:170
impeller::Texture::mipmap_generated_
bool mipmap_generated_
Definition: texture.h:64
impeller::TextureGLES::AttachmentType::kStencil
@ kStencil
impeller::TextureType::kTexture2D
@ kTexture2D
impeller::PixelFormat::kR32G32B32A32Float
@ kR32G32B32A32Float
impeller::PixelFormat::kUnknown
@ kUnknown
impeller::ISize
TSize< int64_t > ISize
Definition: size.h:138
formats_gles.h
impeller::TextureDescriptor::size
ISize size
Definition: texture_descriptor.h:41
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:73
impeller::TextureGLES::GetType
Type GetType() const
Definition: texture_gles.cc:484
impeller::TextureGLES::~TextureGLES
~TextureGLES() override
Definition: texture_gles.cc:105
impeller::PixelFormat::kR8G8B8A8UNormIntSRGB
@ kR8G8B8A8UNormIntSRGB
std
Definition: comparable.h:95
impeller::TextureGLES::AttachmentType
AttachmentType
Definition: texture_gles.h:44
impeller::CreateMappingWithCopy
std::shared_ptr< fml::Mapping > CreateMappingWithCopy(const uint8_t *contents, size_t length)
Definition: allocation.cc:83
impeller::TexImage2DData::type
GLenum type
Definition: texture_gles.cc:122
impeller::SampleCount::kCount4
@ kCount4
impeller::TextureDescriptor
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
Definition: texture_descriptor.h:37
impeller::ToTextureTarget
constexpr std::optional< GLenum > ToTextureTarget(TextureType type)
Definition: formats_gles.h:184
impeller::TextureGLES::IsWrapped
IsWrapped
Definition: texture_gles.h:25
impeller::PixelFormat::kB10G10R10XRSRGB
@ kB10G10R10XRSRGB
impeller::TextureGLES
Definition: texture_gles.h:15
impeller::TexImage2DData::TexImage2DData
TexImage2DData(PixelFormat pixel_format, std::shared_ptr< const fml::Mapping > mapping)
Definition: texture_gles.cc:177
impeller::TextureGLES::Bind
bool Bind() const
Definition: texture_gles.cc:425
impeller::PixelFormat::kB8G8R8A8UNormInt
@ kB8G8R8A8UNormInt
impeller::TexImage2DData::data
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:123
impeller::TextureGLES::Type::kTexture
@ kTexture
impeller::Texture::GetCoordinateSystem
TextureCoordinateSystem GetCoordinateSystem() const
Definition: texture.cc:77
impeller
Definition: aiks_blur_unittests.cc:20
impeller::ToRenderBufferFormat
static std::optional< GLenum > ToRenderBufferFormat(PixelFormat format)
Definition: texture_gles.cc:308
impeller::ToAttachmentType
static GLenum ToAttachmentType(TextureGLES::AttachmentType point)
Definition: texture_gles.cc:488
impeller::TextureGLES::SetAsFramebufferAttachment
bool SetAsFramebufferAttachment(GLenum target, AttachmentType attachment_type) const
Definition: texture_gles.cc:499
impeller::TexImage2DData::external_format
GLenum external_format
Definition: texture_gles.cc:121