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/mapping.h"
11 #include "flutter/fml/trace_event.h"
14 #include "impeller/core/formats.h"
17 
18 namespace impeller {
19 
21  const TextureDescriptor& desc) {
22  const auto usage = static_cast<TextureUsageMask>(desc.usage);
23  const auto render_target =
25  const auto is_msaa = desc.sample_count == SampleCount::kCount4;
26  if (usage == render_target && desc.format == PixelFormat::kS8UInt) {
29  }
32 }
33 
35  switch (type) {
38  return HandleType::kTexture;
42  }
43  FML_UNREACHABLE();
44 }
45 
47  : TextureGLES(std::move(reactor), desc, false) {}
48 
50  TextureDescriptor desc,
51  enum IsWrapped wrapped)
52  : TextureGLES(std::move(reactor), desc, true) {}
53 
54 TextureGLES::TextureGLES(std::shared_ptr<ReactorGLES> reactor,
55  TextureDescriptor desc,
56  bool is_wrapped)
57  : Texture(desc),
58  reactor_(std::move(reactor)),
59  type_(GetTextureTypeFromDescriptor(GetTextureDescriptor())),
60  handle_(reactor_->CreateHandle(ToHandleType(type_))),
61  is_wrapped_(is_wrapped) {
62  // Ensure the texture descriptor itself is valid.
63  if (!GetTextureDescriptor().IsValid()) {
64  VALIDATION_LOG << "Invalid texture descriptor.";
65  return;
66  }
67  // Ensure the texture doesn't exceed device capabilities.
68  const auto tex_size = GetTextureDescriptor().size;
69  const auto max_size =
70  reactor_->GetProcTable().GetCapabilities()->max_texture_size;
71  if (tex_size.Max(max_size) != max_size) {
72  VALIDATION_LOG << "Texture of size " << tex_size
73  << " would exceed max supported size of " << max_size << ".";
74  return;
75  }
76 
77  is_valid_ = true;
78 }
79 
80 // |Texture|
82  reactor_->CollectHandle(handle_);
83 }
84 
85 // |Texture|
86 bool TextureGLES::IsValid() const {
87  return is_valid_;
88 }
89 
90 // |Texture|
91 void TextureGLES::SetLabel(std::string_view label) {
92  reactor_->SetDebugLabel(handle_, std::string{label.data(), label.size()});
93 }
94 
96  GLint internal_format = 0;
97  GLenum external_format = GL_NONE;
98  GLenum type = GL_NONE;
99  std::shared_ptr<const fml::Mapping> data;
100 
101  explicit TexImage2DData(PixelFormat pixel_format) {
102  switch (pixel_format) {
104  internal_format = GL_ALPHA;
105  external_format = GL_ALPHA;
106  type = GL_UNSIGNED_BYTE;
107  break;
112  internal_format = GL_RGBA;
113  external_format = GL_RGBA;
114  type = GL_UNSIGNED_BYTE;
115  break;
117  internal_format = GL_RGBA;
118  external_format = GL_RGBA;
119  type = GL_FLOAT;
120  break;
122  internal_format = GL_RGBA;
123  external_format = GL_RGBA;
124  type = GL_HALF_FLOAT;
125  break;
127  // Pure stencil textures are only available in OpenGL 4.4+, which is
128  // ~0% of mobile devices. Instead, we use a depth-stencil texture and
129  // only use the stencil component.
130  //
131  // https://registry.khronos.org/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml
132  internal_format = GL_DEPTH_STENCIL;
133  external_format = GL_DEPTH_STENCIL;
134  type = GL_UNSIGNED_INT_24_8;
135  break;
144  return;
145  }
146  is_valid_ = true;
147  }
148 
150  std::shared_ptr<const fml::Mapping> mapping)
151  : TexImage2DData(pixel_format) {
152  data = std::move(mapping);
153  }
154 
155  bool IsValid() const { return is_valid_; }
156 
157  private:
158  bool is_valid_ = false;
159 };
160 
161 // |Texture|
162 bool TextureGLES::OnSetContents(const uint8_t* contents,
163  size_t length,
164  size_t slice) {
165  return OnSetContents(CreateMappingWithCopy(contents, length), slice);
166 }
167 
168 // |Texture|
169 bool TextureGLES::OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
170  size_t slice) {
171  if (!mapping) {
172  return false;
173  }
174 
175  if (mapping->GetSize() == 0u) {
176  return true;
177  }
178 
179  if (mapping->GetMapping() == nullptr) {
180  return false;
181  }
182 
183  if (GetType() != Type::kTexture) {
184  VALIDATION_LOG << "Incorrect texture usage flags for setting contents on "
185  "this texture object.";
186  return false;
187  }
188 
189  if (is_wrapped_) {
190  VALIDATION_LOG << "Cannot set the contents of a wrapped texture.";
191  return false;
192  }
193 
194  const auto& tex_descriptor = GetTextureDescriptor();
195 
196  if (tex_descriptor.size.IsEmpty()) {
197  return true;
198  }
199 
200  if (!tex_descriptor.IsValid()) {
201  return false;
202  }
203 
204  if (mapping->GetSize() < tex_descriptor.GetByteSizeOfBaseMipLevel()) {
205  return false;
206  }
207 
208  GLenum texture_type;
209  GLenum texture_target;
210  switch (tex_descriptor.type) {
212  texture_type = GL_TEXTURE_2D;
213  texture_target = GL_TEXTURE_2D;
214  break;
216  VALIDATION_LOG << "Multisample texture uploading is not supported for "
217  "the OpenGLES backend.";
218  return false;
220  texture_type = GL_TEXTURE_CUBE_MAP;
221  texture_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
222  break;
224  texture_type = GL_TEXTURE_EXTERNAL_OES;
225  texture_target = GL_TEXTURE_EXTERNAL_OES;
226  break;
227  }
228 
229  auto data = std::make_shared<TexImage2DData>(tex_descriptor.format,
230  std::move(mapping));
231  if (!data || !data->IsValid()) {
232  VALIDATION_LOG << "Invalid texture format.";
233  return false;
234  }
235 
236  ReactorGLES::Operation texture_upload = [handle = handle_, //
237  data, //
238  size = tex_descriptor.size, //
239  texture_type, //
240  texture_target //
241  ](const auto& reactor) {
242  auto gl_handle = reactor.GetGLHandle(handle);
243  if (!gl_handle.has_value()) {
245  << "Texture was collected before it could be uploaded to the GPU.";
246  return;
247  }
248  const auto& gl = reactor.GetProcTable();
249  gl.BindTexture(texture_type, gl_handle.value());
250  const GLvoid* tex_data = nullptr;
251  if (data->data) {
252  tex_data = data->data->GetMapping();
253  }
254 
255  {
256  TRACE_EVENT1("impeller", "TexImage2DUpload", "Bytes",
257  std::to_string(data->data->GetSize()).c_str());
258  gl.TexImage2D(texture_target, // target
259  0u, // LOD level
260  data->internal_format, // internal format
261  size.width, // width
262  size.height, // height
263  0u, // border
264  data->external_format, // external format
265  data->type, // type
266  tex_data // data
267  );
268  }
269  };
270 
271  contents_initialized_ = reactor_->AddOperation(texture_upload);
272  return contents_initialized_;
273 }
274 
275 // |Texture|
276 ISize TextureGLES::GetSize() const {
277  return GetTextureDescriptor().size;
278 }
279 
280 static std::optional<GLenum> ToRenderBufferFormat(PixelFormat format) {
281  switch (format) {
284  return GL_RGBA4;
286  return GL_RGBA32F;
288  return GL_RGBA16F;
290  return GL_STENCIL_INDEX8;
292  return GL_DEPTH24_STENCIL8;
294  return GL_DEPTH32F_STENCIL8;
304  return std::nullopt;
305  }
306  FML_UNREACHABLE();
307 }
308 
309 void TextureGLES::InitializeContentsIfNecessary() const {
310  if (!IsValid()) {
311  return;
312  }
313  if (contents_initialized_) {
314  return;
315  }
316  contents_initialized_ = true;
317 
318  if (is_wrapped_) {
319  return;
320  }
321 
322  auto size = GetSize();
323 
324  if (size.IsEmpty()) {
325  return;
326  }
327 
328  const auto& gl = reactor_->GetProcTable();
329  auto handle = reactor_->GetGLHandle(handle_);
330  if (!handle.has_value()) {
331  VALIDATION_LOG << "Could not initialize the contents of texture.";
332  return;
333  }
334 
335  switch (type_) {
336  case Type::kTexture:
338  TexImage2DData tex_data(GetTextureDescriptor().format);
339  if (!tex_data.IsValid()) {
340  VALIDATION_LOG << "Invalid format for texture image.";
341  return;
342  }
343  gl.BindTexture(GL_TEXTURE_2D, handle.value());
344  {
345  TRACE_EVENT0("impeller", "TexImage2DInitialization");
346  gl.TexImage2D(GL_TEXTURE_2D, // target
347  0u, // LOD level (base mip level size checked)
348  tex_data.internal_format, // internal format
349  size.width, // width
350  size.height, // height
351  0u, // border
352  tex_data.external_format, // format
353  tex_data.type, // type
354  nullptr // data
355  );
356  }
357  } break;
358  case Type::kRenderBuffer:
360  auto render_buffer_format =
362  if (!render_buffer_format.has_value()) {
363  VALIDATION_LOG << "Invalid format for render-buffer image.";
364  return;
365  }
366  gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
367  {
368  TRACE_EVENT0("impeller", "RenderBufferStorageInitialization");
369  if (type_ == Type::kRenderBufferMultisampled) {
370  gl.RenderbufferStorageMultisampleEXT(
371  GL_RENDERBUFFER, // target
372  4, // samples
373  render_buffer_format.value(), // internal format
374  size.width, // width
375  size.height // height
376  );
377  } else {
378  gl.RenderbufferStorage(
379  GL_RENDERBUFFER, // target
380  render_buffer_format.value(), // internal format
381  size.width, // width
382  size.height // height
383  );
384  }
385  }
386  } break;
387  }
388 }
389 
390 std::optional<GLuint> TextureGLES::GetGLHandle() const {
391  if (!IsValid()) {
392  return std::nullopt;
393  }
394  return reactor_->GetGLHandle(handle_);
395 }
396 
397 bool TextureGLES::Bind() const {
398  auto handle = GetGLHandle();
399  if (!handle.has_value()) {
400  return false;
401  }
402  const auto& gl = reactor_->GetProcTable();
403  switch (type_) {
404  case Type::kTexture:
406  const auto target = ToTextureTarget(GetTextureDescriptor().type);
407  if (!target.has_value()) {
408  VALIDATION_LOG << "Could not bind texture of this type.";
409  return false;
410  }
411  gl.BindTexture(target.value(), handle.value());
412  } break;
413  case Type::kRenderBuffer:
415  gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
416  break;
417  }
418  InitializeContentsIfNecessary();
419  return true;
420 }
421 
423  if (!IsValid()) {
424  return false;
425  }
426 
427  auto type = GetTextureDescriptor().type;
428  switch (type) {
430  break;
432  VALIDATION_LOG << "Generating mipmaps for multisample textures is not "
433  "supported in the GLES backend.";
434  return false;
436  break;
438  break;
439  }
440 
441  if (!Bind()) {
442  return false;
443  }
444 
445  auto handle = GetGLHandle();
446  if (!handle.has_value()) {
447  return false;
448  }
449 
450  const auto& gl = reactor_->GetProcTable();
451  gl.GenerateMipmap(ToTextureType(type));
452  mipmap_generated_ = true;
453  return true;
454 }
455 
457  return type_;
458 }
459 
461  switch (point) {
463  return GL_COLOR_ATTACHMENT0;
465  return GL_DEPTH_ATTACHMENT;
467  return GL_STENCIL_ATTACHMENT;
468  }
469 }
470 
472  AttachmentPoint point) const {
473  if (!IsValid()) {
474  return false;
475  }
476  InitializeContentsIfNecessary();
477  auto handle = GetGLHandle();
478  if (!handle.has_value()) {
479  return false;
480  }
481  const auto& gl = reactor_->GetProcTable();
482 
483  switch (type_) {
484  case Type::kTexture:
485  gl.FramebufferTexture2D(target, // target
486  ToAttachmentPoint(point), // attachment
487  GL_TEXTURE_2D, // textarget
488  handle.value(), // texture
489  0 // level
490  );
491  break;
493  gl.FramebufferTexture2DMultisampleEXT(
494  target, // target
495  ToAttachmentPoint(point), // attachment
496  GL_TEXTURE_2D, // textarget
497  handle.value(), // texture
498  0, // level
499  4 // samples
500  );
501  break;
502  case Type::kRenderBuffer:
504  gl.FramebufferRenderbuffer(target, // target
505  ToAttachmentPoint(point), // attachment
506  GL_RENDERBUFFER, // render-buffer target
507  handle.value() // render-buffer
508  );
509  break;
510  }
511 
512  return true;
513 }
514 
515 // |Texture|
516 Scalar TextureGLES::GetYCoordScale() const {
517  switch (GetCoordinateSystem()) {
519  return 1.0;
521  return -1.0;
522  }
523  FML_UNREACHABLE();
524 }
525 
526 } // 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:155
impeller::PixelFormat::kS8UInt
@ kS8UInt
impeller::TextureType::kTextureExternalOES
@ kTextureExternalOES
impeller::ToAttachmentPoint
static GLenum ToAttachmentPoint(TextureGLES::AttachmentPoint point)
Definition: texture_gles.cc:460
impeller::TexImage2DData::TexImage2DData
TexImage2DData(PixelFormat pixel_format)
Definition: texture_gles.cc:101
impeller::HandleType::kRenderBuffer
@ kRenderBuffer
impeller::TextureGLES::Type
Type
Definition: texture_gles.h:18
impeller::TextureGLES::Type::kTextureMultisampled
@ kTextureMultisampled
impeller::TextureUsageMask
uint64_t TextureUsageMask
Definition: formats.h:295
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::TextureGLES::AttachmentPoint::kDepth
@ kDepth
impeller::TextureGLES::GenerateMipmap
bool GenerateMipmap()
Definition: texture_gles.cc:422
impeller::PixelFormat::kB10G10R10A10XR
@ kB10G10R10A10XR
impeller::PixelFormat::kB8G8R8A8UNormIntSRGB
@ kB8G8R8A8UNormIntSRGB
impeller::PixelFormat::kA8UNormInt
@ kA8UNormInt
allocation.h
impeller::PixelFormat::kR8UNormInt
@ kR8UNormInt
impeller::TextureGLES::AttachmentPoint
AttachmentPoint
Definition: texture_gles.h:44
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:390
texture_descriptor.h
impeller::HandleType::kTexture
@ kTexture
formats.h
texture_gles.h
impeller::TextureUsage::kRenderTarget
@ kRenderTarget
impeller::TexImage2DData
Definition: texture_gles.cc:95
impeller::TextureGLES::Type::kRenderBufferMultisampled
@ kRenderBufferMultisampled
impeller::TexImage2DData::internal_format
GLint internal_format
Definition: texture_gles.cc:96
impeller::TextureDescriptor::sample_count
SampleCount sample_count
Definition: texture_descriptor.h:45
validation.h
impeller::TextureDescriptor::usage
TextureUsageMask usage
Definition: texture_descriptor.h:43
impeller::TextureGLES::AttachmentPoint::kColor0
@ kColor0
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:94
impeller::TextureCoordinateSystem::kUploadFromHost
@ kUploadFromHost
impeller::TextureDescriptor::type
TextureType type
Definition: texture_descriptor.h:39
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:46
impeller::GetTextureTypeFromDescriptor
static TextureGLES::Type GetTextureTypeFromDescriptor(const TextureDescriptor &desc)
Definition: texture_gles.cc:20
impeller::TextureGLES::SetAsFramebufferAttachment
bool SetAsFramebufferAttachment(GLenum target, AttachmentPoint point) const
Definition: texture_gles.cc:471
impeller::PixelFormat::kR8G8UNormInt
@ kR8G8UNormInt
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:34
impeller::ToTextureType
constexpr GLenum ToTextureType(TextureType type)
Definition: formats_gles.h:170
impeller::Texture::mipmap_generated_
bool mipmap_generated_
Definition: texture.h:61
impeller::TextureGLES::AttachmentPoint::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:67
impeller::TextureGLES::GetType
Type GetType() const
Definition: texture_gles.cc:456
impeller::TextureGLES::~TextureGLES
~TextureGLES() override
Definition: texture_gles.cc:81
impeller::PixelFormat::kR8G8B8A8UNormIntSRGB
@ kR8G8B8A8UNormIntSRGB
std
Definition: comparable.h:95
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:98
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:149
impeller::TextureGLES::Bind
bool Bind() const
Definition: texture_gles.cc:397
impeller::PixelFormat::kB8G8R8A8UNormInt
@ kB8G8R8A8UNormInt
impeller::TexImage2DData::data
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:99
impeller::TextureGLES::Type::kTexture
@ kTexture
impeller::Texture::GetCoordinateSystem
TextureCoordinateSystem GetCoordinateSystem() const
Definition: texture.cc:77
impeller
Definition: aiks_context.cc:10
impeller::ToRenderBufferFormat
static std::optional< GLenum > ToRenderBufferFormat(PixelFormat format)
Definition: texture_gles.cc:280
impeller::TexImage2DData::external_format
GLenum external_format
Definition: texture_gles.cc:97