Flutter Impeller
blit_command_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 "flutter/fml/closure.h"
8 #include "fml/trace_event.h"
14 
15 namespace impeller {
16 
18 
19 static void DeleteFBO(const ProcTableGLES& gl, GLuint fbo, GLenum type) {
20  if (fbo != GL_NONE) {
21  gl.BindFramebuffer(type, GL_NONE);
22  gl.DeleteFramebuffers(1u, &fbo);
23  }
24 };
25 
26 static std::optional<GLuint> ConfigureFBO(
27  const ProcTableGLES& gl,
28  const std::shared_ptr<Texture>& texture,
29  GLenum fbo_type) {
30  auto handle = TextureGLES::Cast(texture.get())->GetGLHandle();
31  if (!handle.has_value()) {
32  return std::nullopt;
33  }
34 
35  if (TextureGLES::Cast(*texture).IsWrapped()) {
36  // The texture is attached to the default FBO, so there's no need to
37  // create/configure one.
38  gl.BindFramebuffer(fbo_type, 0);
39  return 0;
40  }
41 
42  GLuint fbo;
43  gl.GenFramebuffers(1u, &fbo);
44  gl.BindFramebuffer(fbo_type, fbo);
45 
48  VALIDATION_LOG << "Could not attach texture to framebuffer.";
49  DeleteFBO(gl, fbo, fbo_type);
50  return std::nullopt;
51  }
52 
53  if (gl.CheckFramebufferStatus(fbo_type) != GL_FRAMEBUFFER_COMPLETE) {
54  VALIDATION_LOG << "Could not create a complete framebuffer.";
55  DeleteFBO(gl, fbo, fbo_type);
56  return std::nullopt;
57  }
58 
59  return fbo;
60 };
61 
63  default;
64 
66  return label;
67 }
68 
70  const ReactorGLES& reactor) const {
71  const auto& gl = reactor.GetProcTable();
72 
73  // glBlitFramebuffer is a GLES3 proc. Since we target GLES2, we need to
74  // emulate the blit when it's not available in the driver.
75  if (!gl.BlitFramebuffer.IsAvailable()) {
76  // TODO(135818): Emulate the blit using a raster draw call here.
77  VALIDATION_LOG << "Texture blit fallback not implemented yet for GLES2.";
78  return false;
79  }
80 
81  GLuint read_fbo = GL_NONE;
82  GLuint draw_fbo = GL_NONE;
83  fml::ScopedCleanupClosure delete_fbos([&gl, &read_fbo, &draw_fbo]() {
84  DeleteFBO(gl, read_fbo, GL_READ_FRAMEBUFFER);
85  DeleteFBO(gl, draw_fbo, GL_DRAW_FRAMEBUFFER);
86  });
87 
88  {
89  auto read = ConfigureFBO(gl, source, GL_READ_FRAMEBUFFER);
90  if (!read.has_value()) {
91  return false;
92  }
93  read_fbo = read.value();
94  }
95 
96  {
97  auto draw = ConfigureFBO(gl, destination, GL_DRAW_FRAMEBUFFER);
98  if (!draw.has_value()) {
99  return false;
100  }
101  draw_fbo = draw.value();
102  }
103 
104  gl.Disable(GL_SCISSOR_TEST);
105  gl.Disable(GL_DEPTH_TEST);
106  gl.Disable(GL_STENCIL_TEST);
107 
108  gl.BlitFramebuffer(source_region.GetX(), // srcX0
109  source_region.GetY(), // srcY0
110  source_region.GetWidth(), // srcX1
111  source_region.GetHeight(), // srcY1
112  destination_origin.x, // dstX0
113  destination_origin.y, // dstY0
114  source_region.GetWidth(), // dstX1
115  source_region.GetHeight(), // dstY1
116  GL_COLOR_BUFFER_BIT, // mask
117  GL_NEAREST // filter
118  );
119 
120  return true;
121 };
122 
123 namespace {
124 struct TexImage2DData {
125  GLint internal_format = 0;
126  GLenum external_format = GL_NONE;
127  GLenum type = GL_NONE;
128  BufferView buffer_view;
129 
130  explicit TexImage2DData(PixelFormat pixel_format) {
131  switch (pixel_format) {
133  internal_format = GL_ALPHA;
134  external_format = GL_ALPHA;
135  type = GL_UNSIGNED_BYTE;
136  break;
138  internal_format = GL_RED;
139  external_format = GL_RED;
140  type = GL_UNSIGNED_BYTE;
141  break;
146  internal_format = GL_RGBA;
147  external_format = GL_RGBA;
148  type = GL_UNSIGNED_BYTE;
149  break;
151  internal_format = GL_RGBA;
152  external_format = GL_RGBA;
153  type = GL_FLOAT;
154  break;
156  internal_format = GL_RGBA;
157  external_format = GL_RGBA;
158  type = GL_HALF_FLOAT;
159  break;
161  // Pure stencil textures are only available in OpenGL 4.4+, which is
162  // ~0% of mobile devices. Instead, we use a depth-stencil texture and
163  // only use the stencil component.
164  //
165  // https://registry.khronos.org/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml
167  internal_format = GL_DEPTH_STENCIL;
168  external_format = GL_DEPTH_STENCIL;
169  type = GL_UNSIGNED_INT_24_8;
170  break;
177  return;
178  }
179  is_valid_ = true;
180  }
181 
182  TexImage2DData(PixelFormat pixel_format, BufferView p_buffer_view)
183  : TexImage2DData(pixel_format) {
184  buffer_view = std::move(p_buffer_view);
185  }
186 
187  bool IsValid() const { return is_valid_; }
188 
189  private:
190  bool is_valid_ = false;
191 };
192 } // namespace
193 
195  default;
196 
198  return label;
199 }
200 
202  const ReactorGLES& reactor) const {
203  TextureGLES& texture_gles = TextureGLES::Cast(*destination);
204 
205  if (texture_gles.GetType() != TextureGLES::Type::kTexture) {
206  VALIDATION_LOG << "Incorrect texture usage flags for setting contents on "
207  "this texture object.";
208  return false;
209  }
210 
211  if (texture_gles.IsWrapped()) {
212  VALIDATION_LOG << "Cannot set the contents of a wrapped texture.";
213  return false;
214  }
215 
216  const auto& tex_descriptor = texture_gles.GetTextureDescriptor();
217 
218  if (tex_descriptor.size.IsEmpty()) {
219  return true;
220  }
221 
222  if (!tex_descriptor.IsValid() ||
223  source.range.length !=
224  BytesPerPixelForPixelFormat(tex_descriptor.format) *
226  return false;
227  }
228 
230 
231  GLenum texture_type;
232  GLenum texture_target;
233  switch (tex_descriptor.type) {
235  texture_type = GL_TEXTURE_2D;
236  texture_target = GL_TEXTURE_2D;
237  break;
239  VALIDATION_LOG << "Multisample texture uploading is not supported for "
240  "the OpenGLES backend.";
241  return false;
243  texture_type = GL_TEXTURE_CUBE_MAP;
244  texture_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
245  break;
247  texture_type = GL_TEXTURE_EXTERNAL_OES;
248  texture_target = GL_TEXTURE_EXTERNAL_OES;
249  break;
250  }
251 
252  TexImage2DData data = TexImage2DData(tex_descriptor.format, source);
253  if (!data.IsValid()) {
254  VALIDATION_LOG << "Invalid texture format.";
255  return false;
256  }
257 
258  auto gl_handle = texture_gles.GetGLHandle();
259  if (!gl_handle.has_value()) {
261  << "Texture was collected before it could be uploaded to the GPU.";
262  return false;
263  }
264  const auto& gl = reactor.GetProcTable();
265  gl.BindTexture(texture_type, gl_handle.value());
266  const GLvoid* tex_data =
267  data.buffer_view.buffer->OnGetContents() + data.buffer_view.range.offset;
268 
269  // GL_INVALID_OPERATION if the texture array has not been
270  // defined by a previous glTexImage2D operation.
271  if (!texture_gles.IsSliceInitialized(slice)) {
272  gl.TexImage2D(texture_target, // target
273  0u, // LOD level
274  data.internal_format, // internal format
275  tex_descriptor.size.width, // width
276  tex_descriptor.size.height, // height
277  0u, // border
278  data.external_format, // external format
279  data.type, // type
280  nullptr // data
281  );
282  texture_gles.MarkSliceInitialized(slice);
283  }
284 
285  {
286  gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
287  gl.TexSubImage2D(texture_target, // target
288  0u, // LOD level
289  destination_region.GetX(), // xoffset
290  destination_region.GetY(), // yoffset
291  destination_region.GetWidth(), // width
292  destination_region.GetHeight(), // height
293  data.external_format, // external format
294  data.type, // type
295  tex_data // data
296 
297  );
298  }
299  return true;
300 }
301 
303  default;
304 
306  return label;
307 }
308 
310  const ReactorGLES& reactor) const {
311  if (source->GetTextureDescriptor().format != PixelFormat::kR8G8B8A8UNormInt) {
312  VALIDATION_LOG << "Only textures with pixel format RGBA are supported yet.";
313  return false;
314  }
315 
316  const auto& gl = reactor.GetProcTable();
317 
318  GLuint read_fbo = GL_NONE;
319  fml::ScopedCleanupClosure delete_fbos(
320  [&gl, &read_fbo]() { DeleteFBO(gl, read_fbo, GL_READ_FRAMEBUFFER); });
321 
322  {
323  auto read = ConfigureFBO(gl, source, GL_READ_FRAMEBUFFER);
324  if (!read.has_value()) {
325  return false;
326  }
327  read_fbo = read.value();
328  }
329 
331  .UpdateBufferData([&gl, this](uint8_t* data, size_t length) {
332  gl.ReadPixels(source_region.GetX(), source_region.GetY(),
334  GL_RGBA, GL_UNSIGNED_BYTE, data + destination_offset);
335  });
336 
337  return true;
338 };
339 
341 
343  return label;
344 }
345 
347  auto texture_gles = TextureGLES::Cast(texture.get());
348  if (!texture_gles->GenerateMipmap()) {
349  return false;
350  }
351 
352  return true;
353 };
354 
355 ////// BlitResizeTextureCommandGLES
356 //////////////////////////////////////////////////////
357 
359 
361  return "Resize Texture";
362 }
363 
365  const auto& gl = reactor.GetProcTable();
366 
367  // glBlitFramebuffer is a GLES3 proc. Since we target GLES2, we need to
368  // emulate the blit when it's not available in the driver.
369  if (!gl.BlitFramebuffer.IsAvailable()) {
370  // TODO(135818): Emulate the blit using a raster draw call here.
371  VALIDATION_LOG << "Texture blit fallback not implemented yet for GLES2.";
372  return false;
373  }
374 
375  GLuint read_fbo = GL_NONE;
376  GLuint draw_fbo = GL_NONE;
377  fml::ScopedCleanupClosure delete_fbos([&gl, &read_fbo, &draw_fbo]() {
378  DeleteFBO(gl, read_fbo, GL_READ_FRAMEBUFFER);
379  DeleteFBO(gl, draw_fbo, GL_DRAW_FRAMEBUFFER);
380  });
381 
382  {
383  auto read = ConfigureFBO(gl, source, GL_READ_FRAMEBUFFER);
384  if (!read.has_value()) {
385  return false;
386  }
387  read_fbo = read.value();
388  }
389 
390  {
391  auto draw = ConfigureFBO(gl, destination, GL_DRAW_FRAMEBUFFER);
392  if (!draw.has_value()) {
393  return false;
394  }
395  draw_fbo = draw.value();
396  }
397 
398  gl.Disable(GL_SCISSOR_TEST);
399  gl.Disable(GL_DEPTH_TEST);
400  gl.Disable(GL_STENCIL_TEST);
401 
402  const IRect source_region = IRect::MakeSize(source->GetSize());
403  const IRect destination_region = IRect::MakeSize(destination->GetSize());
404 
405  gl.BlitFramebuffer(source_region.GetX(), // srcX0
406  source_region.GetY(), // srcY0
407  source_region.GetWidth(), // srcX1
408  source_region.GetHeight(), // srcY1
409  destination_region.GetX(), // dstX0
410  destination_region.GetY(), // dstY0
411  destination_region.GetWidth(), // dstX1
412  destination_region.GetHeight(), // dstY1
413  GL_COLOR_BUFFER_BIT, // mask
414  GL_LINEAR // filter
415  );
416 
417  return true;
418 }
419 
420 } // namespace impeller
impeller::BlitResizeTextureCommand::destination
std::shared_ptr< Texture > destination
Definition: blit_command.h:27
impeller::PixelFormat::kS8UInt
@ kS8UInt
impeller::TextureType::kTextureExternalOES
@ kTextureExternalOES
impeller::ReactorGLES::GetProcTable
const ProcTableGLES & GetProcTable() const
Get the OpenGL proc. table the reactor uses to manage handles.
Definition: reactor_gles.cc:48
point.h
impeller::TPoint::y
Type y
Definition: point.h:31
impeller::BlitCopyTextureToTextureCommandGLES::Encode
bool Encode(const ReactorGLES &reactor) const override
Definition: blit_command_gles.cc:69
impeller::PixelFormat::kB10G10R10A10XR
@ kB10G10R10A10XR
impeller::PixelFormat::kB8G8R8A8UNormIntSRGB
@ kB8G8R8A8UNormIntSRGB
impeller::PixelFormat::kA8UNormInt
@ kA8UNormInt
impeller::DeleteFBO
static void DeleteFBO(const ProcTableGLES &gl, GLuint fbo, GLenum type)
Definition: blit_command_gles.cc:19
impeller::BlitCopyBufferToTextureCommandGLES::Encode
bool Encode(const ReactorGLES &reactor) const override
Definition: blit_command_gles.cc:201
external_format
GLenum external_format
Definition: blit_command_gles.cc:126
impeller::PixelFormat::kR8UNormInt
@ kR8UNormInt
data
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
impeller::TextureGLES::MarkSliceInitialized
void MarkSliceInitialized(size_t slice) const
Definition: texture_gles.cc:469
impeller::ConfigureFBO
static std::optional< GLuint > ConfigureFBO(const ProcTableGLES &gl, const std::shared_ptr< Texture > &texture, GLenum fbo_type)
Definition: blit_command_gles.cc:26
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
impeller::Texture::GetTextureDescriptor
const TextureDescriptor & GetTextureDescriptor() const
Definition: texture.cc:57
impeller::BlitCopyTextureToTextureCommand::destination
std::shared_ptr< Texture > destination
Definition: blit_command.h:20
impeller::TextureGLES::GetGLHandle
std::optional< GLuint > GetGLHandle() const
Definition: texture_gles.cc:437
texture_gles.h
buffer_view
BufferView buffer_view
Definition: blit_command_gles.cc:128
impeller::TRect::GetX
constexpr Type GetX() const
Returns the X coordinate of the upper left corner, equivalent to |GetOrigin().x|.
Definition: rect.h:327
impeller::TextureGLES::IsWrapped
IsWrapped
Definition: texture_gles.h:27
impeller::BlitCopyBufferToTextureCommand::destination_region
IRect destination_region
Definition: blit_command.h:40
impeller::BufferView::range
Range range
Definition: buffer_view.h:17
impeller::TRect::GetHeight
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
Definition: rect.h:341
impeller::TextureGLES::AttachmentType::kColor0
@ kColor0
validation.h
impeller::BlitCopyTextureToTextureCommand::destination_origin
IPoint destination_origin
Definition: blit_command.h:22
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:99
impeller::BlitCopyTextureToTextureCommandGLES::~BlitCopyTextureToTextureCommandGLES
~BlitCopyTextureToTextureCommandGLES() override
impeller::TextureCoordinateSystem::kUploadFromHost
@ kUploadFromHost
impeller::TextureGLES::IsSliceInitialized
bool IsSliceInitialized(size_t slice) const
Definition: texture_gles.cc:473
impeller::BlitGenerateMipmapCommand::texture
std::shared_ptr< Texture > texture
Definition: blit_command.h:45
impeller::TextureType::kTexture2DMultisample
@ kTexture2DMultisample
device_buffer_gles.h
impeller::BlitCommand::label
std::string label
Definition: blit_command.h:15
impeller::BlitGenerateMipmapCommandGLES::Encode
bool Encode(const ReactorGLES &reactor) const override
Definition: blit_command_gles.cc:346
impeller::BlitCopyBufferToTextureCommand::source
BufferView source
Definition: blit_command.h:38
internal_format
GLint internal_format
Definition: blit_command_gles.cc:125
impeller::BytesPerPixelForPixelFormat
constexpr size_t BytesPerPixelForPixelFormat(PixelFormat format)
Definition: formats.h:466
impeller::PixelFormat::kR8G8UNormInt
@ kR8G8UNormInt
impeller::BlitCopyBufferToTextureCommand::slice
uint32_t slice
Definition: blit_command.h:41
impeller::TRect::GetWidth
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
Definition: rect.h:335
impeller::PixelFormat::kB10G10R10XR
@ kB10G10R10XR
impeller::BlitCopyTextureToBufferCommand::destination_offset
size_t destination_offset
Definition: blit_command.h:34
impeller::PixelFormat::kD24UnormS8Uint
@ kD24UnormS8Uint
type
GLenum type
Definition: blit_command_gles.cc:127
impeller::BlitResizeTextureCommand::source
std::shared_ptr< Texture > source
Definition: blit_command.h:26
impeller::TextureType::kTextureCube
@ kTextureCube
impeller::BlitCopyTextureToBufferCommand::destination
std::shared_ptr< DeviceBuffer > destination
Definition: blit_command.h:32
impeller::BlitCopyTextureToBufferCommandGLES::GetLabel
std::string GetLabel() const override
Definition: blit_command_gles.cc:305
impeller::PixelFormat::kR16G16B16A16Float
@ kR16G16B16A16Float
impeller::BlitResizeTextureCommandGLES::Encode
bool Encode(const ReactorGLES &reactor) const override
Definition: blit_command_gles.cc:364
impeller::ProcTableGLES
Definition: proc_table_gles.h:226
impeller::BlitCopyTextureToTextureCommand::source
std::shared_ptr< Texture > source
Definition: blit_command.h:19
impeller::BlitCopyTextureToBufferCommandGLES::Encode
bool Encode(const ReactorGLES &reactor) const override
Definition: blit_command_gles.cc:309
impeller::TextureType::kTexture2D
@ kTexture2D
impeller::PixelFormat::kR32G32B32A32Float
@ kR32G32B32A32Float
impeller::DeviceBufferGLES::UpdateBufferData
void UpdateBufferData(const std::function< void(uint8_t *, size_t length)> &update_buffer_data)
Definition: device_buffer_gles.cc:129
impeller::TPoint::x
Type x
Definition: point.h:30
blit_command_gles.h
impeller::PixelFormat::kUnknown
@ kUnknown
impeller::BlitGenerateMipmapCommandGLES::GetLabel
std::string GetLabel() const override
Definition: blit_command_gles.cc:342
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:91
impeller::TextureGLES::GetType
Type GetType() const
Definition: texture_gles.cc:511
reactor_gles.h
impeller::BlitCopyTextureToBufferCommandGLES::~BlitCopyTextureToBufferCommandGLES
~BlitCopyTextureToBufferCommandGLES() override
impeller::PixelFormat::kR8G8B8A8UNormIntSRGB
@ kR8G8B8A8UNormIntSRGB
impeller::BlitCopyBufferToTextureCommandGLES::~BlitCopyBufferToTextureCommandGLES
~BlitCopyBufferToTextureCommandGLES() override
impeller::TRect::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
impeller::BackendCast< TextureGLES, Texture >::Cast
static TextureGLES & Cast(Texture &base)
Definition: backend_cast.h:13
impeller::BlitResizeTextureCommandGLES::~BlitResizeTextureCommandGLES
~BlitResizeTextureCommandGLES() override
impeller::BlitCopyTextureToBufferCommand::source
std::shared_ptr< Texture > source
Definition: blit_command.h:31
impeller::BlitCopyTextureToTextureCommand::source_region
IRect source_region
Definition: blit_command.h:21
impeller::TRect::Area
constexpr T Area() const
Get the area of the rectangle, equivalent to |GetSize().Area()|.
Definition: rect.h:370
impeller::ReactorGLES
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
Definition: reactor_gles.h:55
impeller::PixelFormat::kB10G10R10XRSRGB
@ kB10G10R10XRSRGB
impeller::TextureGLES
Definition: texture_gles.h:17
impeller::Range::length
size_t length
Definition: range.h:15
impeller::PixelFormat::kB8G8R8A8UNormInt
@ kB8G8R8A8UNormInt
impeller::TextureGLES::Type::kTexture
@ kTexture
impeller::BlitGenerateMipmapCommandGLES::~BlitGenerateMipmapCommandGLES
~BlitGenerateMipmapCommandGLES() override
impeller::BlitCopyTextureToTextureCommandGLES::GetLabel
std::string GetLabel() const override
Definition: blit_command_gles.cc:65
impeller::TRect::GetY
constexpr Type GetY() const
Returns the Y coordinate of the upper left corner, equivalent to |GetOrigin().y|.
Definition: rect.h:331
impeller
Definition: allocation.cc:12
impeller::BlitCopyTextureToBufferCommand::source_region
IRect source_region
Definition: blit_command.h:33
impeller::BlitResizeTextureCommandGLES::GetLabel
std::string GetLabel() const override
Definition: blit_command_gles.cc:360
impeller::TRect
Definition: rect.h:122
impeller::BlitCopyBufferToTextureCommand::destination
std::shared_ptr< Texture > destination
Definition: blit_command.h:39
impeller::BlitCopyBufferToTextureCommandGLES::GetLabel
std::string GetLabel() const override
Definition: blit_command_gles.cc:197
impeller::TextureGLES::SetAsFramebufferAttachment
bool SetAsFramebufferAttachment(GLenum target, AttachmentType attachment_type) const
Definition: texture_gles.cc:526
impeller::BlitEncodeGLES::~BlitEncodeGLES
virtual ~BlitEncodeGLES()