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"
16 
17 namespace impeller {
18 
20  const TextureDescriptor& desc) {
21  const auto usage = static_cast<TextureUsageMask>(desc.usage);
22  const auto render_target =
24  if (usage == render_target) {
26  }
28 }
29 
31  switch (type) {
33  return HandleType::kTexture;
35  // MSAA textures are treated as render buffers.
38  }
39  FML_UNREACHABLE();
40 }
41 
43  : TextureGLES(std::move(reactor), desc, false) {}
44 
46  TextureDescriptor desc,
47  enum IsWrapped wrapped)
48  : TextureGLES(std::move(reactor), desc, true) {}
49 
50 TextureGLES::TextureGLES(std::shared_ptr<ReactorGLES> reactor,
51  TextureDescriptor desc,
52  bool is_wrapped)
53  : Texture(desc),
54  reactor_(std::move(reactor)),
55  type_(GetTextureTypeFromDescriptor(GetTextureDescriptor())),
56  handle_(reactor_->CreateHandle(ToHandleType(type_))),
57  is_wrapped_(is_wrapped) {
58  // Ensure the texture descriptor itself is valid.
59  if (!GetTextureDescriptor().IsValid()) {
60  VALIDATION_LOG << "Invalid texture descriptor.";
61  return;
62  }
63  // Ensure the texture doesn't exceed device capabilities.
64  const auto tex_size = GetTextureDescriptor().size;
65  const auto max_size =
66  reactor_->GetProcTable().GetCapabilities()->max_texture_size;
67  if (tex_size.Max(max_size) != max_size) {
68  VALIDATION_LOG << "Texture of size " << tex_size
69  << " would exceed max supported size of " << max_size << ".";
70  return;
71  }
72  is_valid_ = true;
73 }
74 
75 // |Texture|
77  reactor_->CollectHandle(handle_);
78 }
79 
80 // |Texture|
81 bool TextureGLES::IsValid() const {
82  return is_valid_;
83 }
84 
85 // |Texture|
86 void TextureGLES::SetLabel(std::string_view label) {
87  reactor_->SetDebugLabel(handle_, std::string{label.data(), label.size()});
88 }
89 
91  GLint internal_format = 0;
92  GLenum external_format = GL_NONE;
93  GLenum type = GL_NONE;
94  std::shared_ptr<const fml::Mapping> data;
95 
96  explicit TexImage2DData(PixelFormat pixel_format) {
97  switch (pixel_format) {
99  internal_format = GL_ALPHA;
100  external_format = GL_ALPHA;
101  type = GL_UNSIGNED_BYTE;
102  break;
107  internal_format = GL_RGBA;
108  external_format = GL_RGBA;
109  type = GL_UNSIGNED_BYTE;
110  break;
112  internal_format = GL_RGBA;
113  external_format = GL_RGBA;
114  type = GL_FLOAT;
115  break;
117  internal_format = GL_RGBA;
118  external_format = GL_RGBA;
119  type = GL_HALF_FLOAT;
120  break;
130  return;
131  }
132  is_valid_ = true;
133  }
134 
136  std::shared_ptr<const fml::Mapping> mapping) {
137  switch (pixel_format) {
139  return;
141  internal_format = GL_ALPHA;
142  external_format = GL_ALPHA;
143  type = GL_UNSIGNED_BYTE;
144  data = std::move(mapping);
145  break;
146  }
148  internal_format = GL_RGBA;
149  external_format = GL_RGBA;
150  type = GL_UNSIGNED_BYTE;
151  data = std::move(mapping);
152  break;
153  }
155  internal_format = GL_RGBA;
156  external_format = GL_RGBA;
157  type = GL_FLOAT;
158  data = std::move(mapping);
159  break;
160  }
162  internal_format = GL_RGBA;
163  external_format = GL_RGBA;
164  type = GL_HALF_FLOAT;
165  data = std::move(mapping);
166  break;
167  }
179  return;
180  }
181  is_valid_ = true;
182  }
183 
184  bool IsValid() const { return is_valid_; }
185 
186  private:
187  bool is_valid_ = false;
188 };
189 
190 // |Texture|
191 bool TextureGLES::OnSetContents(const uint8_t* contents,
192  size_t length,
193  size_t slice) {
194  return OnSetContents(CreateMappingWithCopy(contents, length), slice);
195 }
196 
197 // |Texture|
198 bool TextureGLES::OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
199  size_t slice) {
200  if (!mapping) {
201  return false;
202  }
203 
204  if (mapping->GetSize() == 0u) {
205  return true;
206  }
207 
208  if (mapping->GetMapping() == nullptr) {
209  return false;
210  }
211 
212  if (GetType() != Type::kTexture) {
213  VALIDATION_LOG << "Incorrect texture usage flags for setting contents on "
214  "this texture object.";
215  return false;
216  }
217 
218  if (is_wrapped_) {
219  VALIDATION_LOG << "Cannot set the contents of a wrapped texture.";
220  return false;
221  }
222 
223  const auto& tex_descriptor = GetTextureDescriptor();
224 
225  if (tex_descriptor.size.IsEmpty()) {
226  return true;
227  }
228 
229  if (!tex_descriptor.IsValid()) {
230  return false;
231  }
232 
233  if (mapping->GetSize() < tex_descriptor.GetByteSizeOfBaseMipLevel()) {
234  return false;
235  }
236 
237  GLenum texture_type;
238  GLenum texture_target;
239  switch (tex_descriptor.type) {
241  texture_type = GL_TEXTURE_2D;
242  texture_target = GL_TEXTURE_2D;
243  break;
245  VALIDATION_LOG << "Multisample texture uploading is not supported for "
246  "the OpenGLES backend.";
247  return false;
249  texture_type = GL_TEXTURE_CUBE_MAP;
250  texture_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
251  break;
253  texture_type = GL_TEXTURE_EXTERNAL_OES;
254  texture_target = GL_TEXTURE_EXTERNAL_OES;
255  break;
256  }
257 
258  auto data = std::make_shared<TexImage2DData>(tex_descriptor.format,
259  std::move(mapping));
260  if (!data || !data->IsValid()) {
261  VALIDATION_LOG << "Invalid texture format.";
262  return false;
263  }
264 
265  ReactorGLES::Operation texture_upload = [handle = handle_, //
266  data, //
267  size = tex_descriptor.size, //
268  texture_type, //
269  texture_target //
270  ](const auto& reactor) {
271  auto gl_handle = reactor.GetGLHandle(handle);
272  if (!gl_handle.has_value()) {
274  << "Texture was collected before it could be uploaded to the GPU.";
275  return;
276  }
277  const auto& gl = reactor.GetProcTable();
278  gl.BindTexture(texture_type, gl_handle.value());
279  const GLvoid* tex_data = nullptr;
280  if (data->data) {
281  tex_data = data->data->GetMapping();
282  }
283 
284  {
285  TRACE_EVENT1("impeller", "TexImage2DUpload", "Bytes",
286  std::to_string(data->data->GetSize()).c_str());
287  gl.TexImage2D(texture_target, // target
288  0u, // LOD level
289  data->internal_format, // internal format
290  size.width, // width
291  size.height, // height
292  0u, // border
293  data->external_format, // external format
294  data->type, // type
295  tex_data // data
296  );
297  }
298  };
299 
300  contents_initialized_ = reactor_->AddOperation(texture_upload);
301  return contents_initialized_;
302 }
303 
304 // |Texture|
305 ISize TextureGLES::GetSize() const {
306  return GetTextureDescriptor().size;
307 }
308 
309 static std::optional<GLenum> ToRenderBufferFormat(PixelFormat format) {
310  switch (format) {
313  return GL_RGBA4;
315  return GL_RGBA32F;
317  return GL_RGBA16F;
319  return GL_STENCIL_INDEX8;
321  return GL_DEPTH24_STENCIL8;
323  return GL_DEPTH32F_STENCIL8;
333  return std::nullopt;
334  }
335  FML_UNREACHABLE();
336 }
337 
338 void TextureGLES::InitializeContentsIfNecessary() const {
339  if (!IsValid()) {
340  return;
341  }
342  if (contents_initialized_) {
343  return;
344  }
345  contents_initialized_ = true;
346 
347  if (is_wrapped_) {
348  return;
349  }
350 
351  auto size = GetSize();
352 
353  if (size.IsEmpty()) {
354  return;
355  }
356 
357  const auto& gl = reactor_->GetProcTable();
358  auto handle = reactor_->GetGLHandle(handle_);
359  if (!handle.has_value()) {
360  VALIDATION_LOG << "Could not initialize the contents of texture.";
361  return;
362  }
363 
364  switch (type_) {
365  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 
386  } break;
387  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  gl.RenderbufferStorage(GL_RENDERBUFFER, // target
398  render_buffer_format.value(), // internal format
399  size.width, // width
400  size.height // height
401  );
402  }
403  } break;
405  auto render_buffer_msaa =
407  if (!render_buffer_msaa.has_value()) {
408  VALIDATION_LOG << "Invalid format for render-buffer MSAA image.";
409  return;
410  }
411  gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
412  {
413  TRACE_EVENT0("impeller", "RenderBufferStorageInitialization");
414  gl.RenderbufferStorageMultisampleEXT(
415  GL_RENDERBUFFER, // target
416  4, // samples
417  render_buffer_msaa.value(), // internal format
418  size.width, // width
419  size.height // height
420  );
421  }
422  break;
423  }
424  }
425 }
426 
427 std::optional<GLuint> TextureGLES::GetGLHandle() const {
428  if (!IsValid()) {
429  return std::nullopt;
430  }
431  return reactor_->GetGLHandle(handle_);
432 }
433 
434 bool TextureGLES::Bind() const {
435  auto handle = GetGLHandle();
436  if (!handle.has_value()) {
437  return false;
438  }
439  const auto& gl = reactor_->GetProcTable();
440  switch (type_) {
441  case Type::kTexture: {
442  const auto target = ToTextureTarget(GetTextureDescriptor().type);
443  if (!target.has_value()) {
444  VALIDATION_LOG << "Could not bind texture of this type.";
445  return false;
446  }
447  gl.BindTexture(target.value(), handle.value());
448  } break;
449  case Type::kRenderBuffer:
450  // MSAA textures are treated as render buffers.
452  gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
453  break;
454  }
455  InitializeContentsIfNecessary();
456  return true;
457 }
458 
460  if (!IsValid()) {
461  return false;
462  }
463 
464  auto type = GetTextureDescriptor().type;
465  switch (type) {
467  break;
469  VALIDATION_LOG << "Generating mipmaps for multisample textures is not "
470  "supported in the GLES backend.";
471  return false;
473  break;
475  break;
476  }
477 
478  if (!Bind()) {
479  return false;
480  }
481 
482  auto handle = GetGLHandle();
483  if (!handle.has_value()) {
484  return false;
485  }
486 
487  const auto& gl = reactor_->GetProcTable();
488  gl.GenerateMipmap(ToTextureType(type));
489  mipmap_generated_ = true;
490  return true;
491 }
492 
494  return type_;
495 }
496 
498  switch (point) {
500  return GL_COLOR_ATTACHMENT0;
502  return GL_DEPTH_ATTACHMENT;
504  return GL_STENCIL_ATTACHMENT;
505  }
506 }
507 
509  GLuint fbo,
510  AttachmentPoint point) const {
511  if (!IsValid()) {
512  return false;
513  }
514  InitializeContentsIfNecessary();
515  auto handle = GetGLHandle();
516  if (!handle.has_value()) {
517  return false;
518  }
519  const auto& gl = reactor_->GetProcTable();
520  switch (type_) {
521  case Type::kTexture:
522  gl.FramebufferTexture2D(target, // target
523  ToAttachmentPoint(point), // attachment
524  GL_TEXTURE_2D, // textarget
525  handle.value(), // texture
526  0 // level
527  );
528  break;
529  case Type::kRenderBuffer:
530  gl.FramebufferRenderbuffer(target, // target
531  ToAttachmentPoint(point), // attachment
532  GL_RENDERBUFFER, // render-buffer target
533  handle.value() // render-buffer
534  );
535  break;
537  // Assume that when MSAA is enabled, we're using 4x MSAA.
538  FML_DCHECK(GetTextureDescriptor().sample_count == SampleCount::kCount4);
539  gl.FramebufferTexture2DMultisampleEXT(
540  target, // target
541  ToAttachmentPoint(point), // attachment
542  GL_TEXTURE_2D, // textarget
543  handle.value(), // texture
544  0, // level
545  4 // samples
546  );
547  break;
548  }
549  return true;
550 }
551 
552 // |Texture|
553 Scalar TextureGLES::GetYCoordScale() const {
554  switch (GetCoordinateSystem()) {
556  return 1.0;
558  return -1.0;
559  }
560  FML_UNREACHABLE();
561 }
562 
563 } // namespace impeller
impeller::PixelFormat::kB8G8R8A8UNormIntSRGB
@ kB8G8R8A8UNormIntSRGB
impeller::ReactorGLES::Operation
std::function< void(const ReactorGLES &reactor)> Operation
Definition: reactor_gles.h:53
impeller::TexImage2DData::IsValid
bool IsValid() const
Definition: texture_gles.cc:184
impeller::TextureType::kTextureExternalOES
@ kTextureExternalOES
impeller::ToAttachmentPoint
static GLenum ToAttachmentPoint(TextureGLES::AttachmentPoint point)
Definition: texture_gles.cc:497
impeller::TexImage2DData::TexImage2DData
TexImage2DData(PixelFormat pixel_format)
Definition: texture_gles.cc:96
impeller::HandleType::kRenderBuffer
@ kRenderBuffer
impeller::TextureGLES::Type
Type
Definition: texture_gles.h:18
impeller::TextureUsageMask
uint64_t TextureUsageMask
Definition: formats.h:274
impeller::PixelFormat::kB10G10R10XR
@ kB10G10R10XR
impeller::Scalar
float Scalar
Definition: scalar.h:15
impeller::TextureGLES::AttachmentPoint::kDepth
@ kDepth
impeller::TextureGLES::GenerateMipmap
bool GenerateMipmap()
Definition: texture_gles.cc:459
impeller::PixelFormat::kB10G10R10XRSRGB
@ kB10G10R10XRSRGB
allocation.h
impeller::PixelFormat::kR8G8B8A8UNormIntSRGB
@ kR8G8B8A8UNormIntSRGB
impeller::TextureGLES::AttachmentPoint
AttachmentPoint
Definition: texture_gles.h:43
impeller::ReactorGLES::Ref
std::shared_ptr< ReactorGLES > Ref
Definition: reactor_gles.h:31
impeller::Texture::GetTextureDescriptor
const TextureDescriptor & GetTextureDescriptor() const
Definition: texture.cc:57
impeller::HandleType
HandleType
Definition: handle_gles.h:21
impeller::TextureGLES::GetGLHandle
std::optional< GLuint > GetGLHandle() const
Definition: texture_gles.cc:427
impeller::HandleType::kTexture
@ kTexture
formats.h
texture_gles.h
impeller::TextureUsage::kRenderTarget
@ kRenderTarget
impeller::PixelFormat::kR16G16B16A16Float
@ kR16G16B16A16Float
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
impeller::TexImage2DData
Definition: texture_gles.cc:90
impeller::TextureGLES::Type::kRenderBufferMultisampled
@ kRenderBufferMultisampled
impeller::TexImage2DData::internal_format
GLint internal_format
Definition: texture_gles.cc:91
validation.h
impeller::TextureDescriptor::usage
TextureUsageMask usage
Definition: texture_descriptor.h:45
impeller::SampleCount::kCount4
@ kCount4
impeller::TextureGLES::AttachmentPoint::kColor0
@ kColor0
impeller::TextureCoordinateSystem::kUploadFromHost
@ kUploadFromHost
impeller::TextureDescriptor::type
TextureType type
Definition: texture_descriptor.h:41
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:42
impeller::GetTextureTypeFromDescriptor
static TextureGLES::Type GetTextureTypeFromDescriptor(const TextureDescriptor &desc)
Definition: texture_gles.cc:19
impeller::PixelFormat::kD32FloatS8UInt
@ kD32FloatS8UInt
impeller::PixelFormat::kUnknown
@ kUnknown
impeller::TextureType::kTextureCube
@ kTextureCube
impeller::PixelFormat::kR8G8UNormInt
@ kR8G8UNormInt
impeller::PixelFormat::kD24UnormS8Uint
@ kD24UnormS8Uint
impeller::ToHandleType
HandleType ToHandleType(TextureGLES::Type type)
Definition: texture_gles.cc:30
impeller::ToTextureType
constexpr GLenum ToTextureType(TextureType type)
Definition: formats_gles.h:169
impeller::Texture::mipmap_generated_
bool mipmap_generated_
Definition: texture.h:61
impeller::TextureGLES::AttachmentPoint::kStencil
@ kStencil
impeller::PixelFormat::kB8G8R8A8UNormInt
@ kB8G8R8A8UNormInt
impeller::TextureType::kTexture2D
@ kTexture2D
impeller::ISize
TSize< int64_t > ISize
Definition: size.h:136
formats_gles.h
impeller::TextureDescriptor::size
ISize size
Definition: texture_descriptor.h:43
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:60
impeller::TextureGLES::GetType
Type GetType() const
Definition: texture_gles.cc:493
impeller::PixelFormat::kB10G10R10A10XR
@ kB10G10R10A10XR
impeller::TextureGLES::~TextureGLES
~TextureGLES() override
Definition: texture_gles.cc:76
std
Definition: comparable.h:98
impeller::CreateMappingWithCopy
std::shared_ptr< fml::Mapping > CreateMappingWithCopy(const uint8_t *contents, size_t length)
Definition: allocation.cc:84
impeller::TexImage2DData::type
GLenum type
Definition: texture_gles.cc:93
impeller::PixelFormat::kS8UInt
@ kS8UInt
impeller::PixelFormat::kA8UNormInt
@ kA8UNormInt
impeller::PixelFormat::kR8UNormInt
@ kR8UNormInt
impeller::TextureDescriptor
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
Definition: texture_descriptor.h:39
impeller::ToTextureTarget
constexpr std::optional< GLenum > ToTextureTarget(TextureType type)
Definition: formats_gles.h:183
impeller::TextureGLES::IsWrapped
IsWrapped
Definition: texture_gles.h:24
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:135
impeller::PixelFormat
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:94
impeller::TextureGLES::Bind
bool Bind() const
Definition: texture_gles.cc:434
impeller::TexImage2DData::data
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:94
impeller::TextureGLES::Type::kTexture
@ kTexture
impeller::Texture::GetCoordinateSystem
TextureCoordinateSystem GetCoordinateSystem() const
Definition: texture.cc:77
impeller
Definition: aiks_context.cc:10
impeller::TextureGLES::SetAsFramebufferAttachment
bool SetAsFramebufferAttachment(GLenum target, GLuint fbo, AttachmentPoint point) const
Definition: texture_gles.cc:508
impeller::ToRenderBufferFormat
static std::optional< GLenum > ToRenderBufferFormat(PixelFormat format)
Definition: texture_gles.cc:309
impeller::PixelFormat::kR32G32B32A32Float
@ kR32G32B32A32Float
impeller::TexImage2DData::external_format
GLenum external_format
Definition: texture_gles.cc:92