Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
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
15
16namespace impeller {
17
18namespace {
19static void FlipImage(uint8_t* buffer,
20 size_t width,
21 size_t height,
22 size_t stride) {
23 if (buffer == nullptr || stride == 0) {
24 return;
25 }
26
27 const auto byte_width = width * stride;
28
29 for (size_t top = 0; top < height; top++) {
30 size_t bottom = height - top - 1;
31 if (top >= bottom) {
32 break;
33 }
34 auto* top_row = buffer + byte_width * top;
35 auto* bottom_row = buffer + byte_width * bottom;
36 std::swap_ranges(top_row, top_row + byte_width, bottom_row);
37 }
38}
39} // namespace
40
42
43static void DeleteFBO(const ProcTableGLES& gl, GLuint fbo, GLenum type) {
44 if (fbo != GL_NONE) {
45 gl.BindFramebuffer(type, GL_NONE);
46 gl.DeleteFramebuffers(1u, &fbo);
47 }
48};
49
50static std::optional<GLuint> ConfigureFBO(
51 const ProcTableGLES& gl,
52 const std::shared_ptr<Texture>& texture,
53 GLenum fbo_type) {
54 auto handle = TextureGLES::Cast(texture.get())->GetGLHandle();
55 if (!handle.has_value()) {
56 return std::nullopt;
57 }
58
59 if (TextureGLES::Cast(*texture).IsWrapped()) {
60 // The texture is attached to the default FBO, so there's no need to
61 // create/configure one.
62 gl.BindFramebuffer(fbo_type, 0);
63 return 0;
64 }
65
66 GLuint fbo;
67 gl.GenFramebuffers(1u, &fbo);
68 gl.BindFramebuffer(fbo_type, fbo);
69
72 VALIDATION_LOG << "Could not attach texture to framebuffer.";
73 DeleteFBO(gl, fbo, fbo_type);
74 return std::nullopt;
75 }
76
77 GLenum status = gl.CheckFramebufferStatus(fbo_type);
78 if (status != GL_FRAMEBUFFER_COMPLETE) {
79 VALIDATION_LOG << "Could not create a complete framebuffer: "
80 << DebugToFramebufferError(status);
81 DeleteFBO(gl, fbo, fbo_type);
82 return std::nullopt;
83 }
84
85 return fbo;
86};
87
89 default;
90
92 return label;
93}
94
96 const ReactorGLES& reactor) const {
97 const auto& gl = reactor.GetProcTable();
98
99 // glBlitFramebuffer is a GLES3 proc. Since we target GLES2, we need to
100 // emulate the blit when it's not available in the driver.
101 if (!gl.BlitFramebuffer.IsAvailable()) {
102 // TODO(157064): Emulate the blit using a raster draw call here.
103 VALIDATION_LOG << "Texture blit fallback not implemented yet for GLES2.";
104 return false;
105 }
106
107 GLuint read_fbo = GL_NONE;
108 GLuint draw_fbo = GL_NONE;
109 fml::ScopedCleanupClosure delete_fbos([&gl, &read_fbo, &draw_fbo]() {
110 DeleteFBO(gl, read_fbo, GL_READ_FRAMEBUFFER);
111 DeleteFBO(gl, draw_fbo, GL_DRAW_FRAMEBUFFER);
112 });
113
114 {
115 auto read = ConfigureFBO(gl, source, GL_READ_FRAMEBUFFER);
116 if (!read.has_value()) {
117 return false;
118 }
119 read_fbo = read.value();
120 }
121
122 {
123 auto draw = ConfigureFBO(gl, destination, GL_DRAW_FRAMEBUFFER);
124 if (!draw.has_value()) {
125 return false;
126 }
127 draw_fbo = draw.value();
128 }
129
130 gl.Disable(GL_SCISSOR_TEST);
131 gl.Disable(GL_DEPTH_TEST);
132 gl.Disable(GL_STENCIL_TEST);
133
134 gl.BlitFramebuffer(source_region.GetX(), // srcX0
135 source_region.GetY(), // srcY0
136 source_region.GetWidth(), // srcX1
137 source_region.GetHeight(), // srcY1
138 destination_origin.x, // dstX0
139 destination_origin.y, // dstY0
140 source_region.GetWidth(), // dstX1
141 source_region.GetHeight(), // dstY1
142 GL_COLOR_BUFFER_BIT, // mask
143 GL_NEAREST // filter
144 );
145
146 return true;
147};
148
149namespace {
150struct TexImage2DData {
152 GLenum external_format = GL_NONE;
153 GLenum type = GL_NONE;
154 BufferView buffer_view;
155
156 explicit TexImage2DData(PixelFormat pixel_format) {
157 switch (pixel_format) {
159 internal_format = GL_ALPHA;
160 external_format = GL_ALPHA;
161 type = GL_UNSIGNED_BYTE;
162 break;
164 internal_format = GL_RED;
165 external_format = GL_RED;
166 type = GL_UNSIGNED_BYTE;
167 break;
172 internal_format = GL_RGBA;
173 external_format = GL_RGBA;
174 type = GL_UNSIGNED_BYTE;
175 break;
177 internal_format = GL_RGBA;
178 external_format = GL_RGBA;
179 type = GL_FLOAT;
180 break;
182 internal_format = GL_RED;
183 external_format = GL_RED;
184 type = GL_FLOAT;
185 break;
187 internal_format = GL_RGBA;
188 external_format = GL_RGBA;
189 type = GL_HALF_FLOAT;
190 break;
192 // Pure stencil textures are only available in OpenGL 4.4+, which is
193 // ~0% of mobile devices. Instead, we use a depth-stencil texture and
194 // only use the stencil component.
195 //
196 // https://registry.khronos.org/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml
198 internal_format = GL_DEPTH_STENCIL;
199 external_format = GL_DEPTH_STENCIL;
200 type = GL_UNSIGNED_INT_24_8;
201 break;
208 return;
209 }
210 is_valid_ = true;
211 }
212
213 TexImage2DData(PixelFormat pixel_format, BufferView p_buffer_view)
214 : TexImage2DData(pixel_format) {
215 buffer_view = std::move(p_buffer_view);
216 }
217
218 bool IsValid() const { return is_valid_; }
219
220 private:
221 bool is_valid_ = false;
222};
223} // namespace
224
226 default;
227
229 return label;
230}
231
233 const ReactorGLES& reactor) const {
234 TextureGLES& texture_gles = TextureGLES::Cast(*destination);
235
236 if (texture_gles.GetType() != TextureGLES::Type::kTexture) {
237 VALIDATION_LOG << "Incorrect texture usage flags for setting contents on "
238 "this texture object.";
239 return false;
240 }
241
242 if (texture_gles.IsWrapped()) {
243 VALIDATION_LOG << "Cannot set the contents of a wrapped texture.";
244 return false;
245 }
246
247 const auto& tex_descriptor = texture_gles.GetTextureDescriptor();
248
249 if (tex_descriptor.size.IsEmpty()) {
250 return true;
251 }
252
253 if (!tex_descriptor.IsValid() ||
255 BytesPerPixelForPixelFormat(tex_descriptor.format) *
257 return false;
258 }
259
261
262 GLenum texture_type;
263 GLenum texture_target;
264 switch (tex_descriptor.type) {
266 texture_type = GL_TEXTURE_2D;
267 texture_target = GL_TEXTURE_2D;
268 break;
270 VALIDATION_LOG << "Multisample texture uploading is not supported for "
271 "the OpenGLES backend.";
272 return false;
274 texture_type = GL_TEXTURE_CUBE_MAP;
275 texture_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
276 break;
278 texture_type = GL_TEXTURE_EXTERNAL_OES;
279 texture_target = GL_TEXTURE_EXTERNAL_OES;
280 break;
281 }
282
283 TexImage2DData data = TexImage2DData(tex_descriptor.format, source);
284 if (!data.IsValid()) {
285 VALIDATION_LOG << "Invalid texture format.";
286 return false;
287 }
288
289 auto gl_handle = texture_gles.GetGLHandle();
290 if (!gl_handle.has_value()) {
292 << "Texture was collected before it could be uploaded to the GPU.";
293 return false;
294 }
295 const auto& gl = reactor.GetProcTable();
296 gl.BindTexture(texture_type, gl_handle.value());
297 const GLvoid* tex_data = data.buffer_view.GetBuffer()->OnGetContents() +
298 data.buffer_view.GetRange().offset;
299
300 // GL_INVALID_OPERATION if the texture array has not been
301 // defined by a previous glTexImage2D operation.
302 if (!texture_gles.IsSliceInitialized(slice)) {
303 gl.TexImage2D(texture_target, // target
304 mip_level, // LOD level
305 data.internal_format, // internal format
306 tex_descriptor.size.width, // width
307 tex_descriptor.size.height, // height
308 0u, // border
309 data.external_format, // external format
310 data.type, // type
311 nullptr // data
312 );
313 texture_gles.MarkSliceInitialized(slice);
314 }
315
316 {
317 gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
318 gl.TexSubImage2D(texture_target, // target
319 mip_level, // LOD level
320 destination_region.GetX(), // xoffset
321 destination_region.GetY(), // yoffset
322 destination_region.GetWidth(), // width
323 destination_region.GetHeight(), // height
324 data.external_format, // external format
325 data.type, // type
326 tex_data // data
327
328 );
329 }
330 return true;
331}
332
334 default;
335
337 return label;
338}
339
341 const ReactorGLES& reactor) const {
342 if (source->GetTextureDescriptor().format != PixelFormat::kR8G8B8A8UNormInt) {
343 VALIDATION_LOG << "Only textures with pixel format RGBA are supported yet.";
344 return false;
345 }
346
347 const auto& gl = reactor.GetProcTable();
348 TextureCoordinateSystem coord_system = source->GetCoordinateSystem();
349
350 GLuint read_fbo = GL_NONE;
351 fml::ScopedCleanupClosure delete_fbos(
352 [&gl, &read_fbo]() { DeleteFBO(gl, read_fbo, GL_FRAMEBUFFER); });
353
354 {
355 auto read = ConfigureFBO(gl, source, GL_FRAMEBUFFER);
356 if (!read.has_value()) {
357 return false;
358 }
359 read_fbo = read.value();
360 }
361
363 .UpdateBufferData([&gl, this, coord_system,
364 rows = source->GetSize().height](uint8_t* data,
365
366 size_t length) {
367 gl.ReadPixels(source_region.GetX(), source_region.GetY(),
368 source_region.GetWidth(), source_region.GetHeight(),
369 GL_RGBA, GL_UNSIGNED_BYTE, data + destination_offset);
370 switch (coord_system) {
371 case TextureCoordinateSystem::kUploadFromHost:
372 break;
373 case TextureCoordinateSystem::kRenderToTexture:
374 // The texture is upside down, and must be inverted when copying
375 // byte data out.
376 FlipImage(data + destination_offset, source_region.GetWidth(),
377 source_region.GetHeight(), 4);
378 }
379 });
380
381 return true;
382};
383
384BlitGenerateMipmapCommandGLES::~BlitGenerateMipmapCommandGLES() = default;
385
386std::string BlitGenerateMipmapCommandGLES::GetLabel() const {
387 return label;
388}
389
390bool BlitGenerateMipmapCommandGLES::Encode(const ReactorGLES& reactor) const {
391 auto texture_gles = TextureGLES::Cast(texture.get());
392 if (!texture_gles->GenerateMipmap()) {
393 return false;
394 }
395
396 return true;
397};
398
399////// BlitResizeTextureCommandGLES
400//////////////////////////////////////////////////////
401
402BlitResizeTextureCommandGLES::~BlitResizeTextureCommandGLES() = default;
403
404std::string BlitResizeTextureCommandGLES::GetLabel() const {
405 return "Resize Texture";
406}
407
408bool BlitResizeTextureCommandGLES::Encode(const ReactorGLES& reactor) const {
409 const auto& gl = reactor.GetProcTable();
410
411 // glBlitFramebuffer is a GLES3 proc. Since we target GLES2, we need to
412 // emulate the blit when it's not available in the driver.
413 if (!gl.BlitFramebuffer.IsAvailable()) {
414 // TODO(157064): Emulate the blit using a raster draw call here.
415 VALIDATION_LOG << "Texture blit fallback not implemented yet for GLES2.";
416 return false;
417 }
418
419 destination->SetCoordinateSystem(source->GetCoordinateSystem());
420
421 GLuint read_fbo = GL_NONE;
422 GLuint draw_fbo = GL_NONE;
423 fml::ScopedCleanupClosure delete_fbos([&gl, &read_fbo, &draw_fbo]() {
424 DeleteFBO(gl, read_fbo, GL_READ_FRAMEBUFFER);
425 DeleteFBO(gl, draw_fbo, GL_DRAW_FRAMEBUFFER);
426 });
427
428 {
429 auto read = ConfigureFBO(gl, source, GL_READ_FRAMEBUFFER);
430 if (!read.has_value()) {
431 return false;
432 }
433 read_fbo = read.value();
434 }
435
436 {
437 auto draw = ConfigureFBO(gl, destination, GL_DRAW_FRAMEBUFFER);
438 if (!draw.has_value()) {
439 return false;
440 }
441 draw_fbo = draw.value();
442 }
443
444 gl.Disable(GL_SCISSOR_TEST);
445 gl.Disable(GL_DEPTH_TEST);
446 gl.Disable(GL_STENCIL_TEST);
447
448 const IRect source_region = IRect::MakeSize(source->GetSize());
449 const IRect destination_region = IRect::MakeSize(destination->GetSize());
450
451 gl.BlitFramebuffer(source_region.GetX(), // srcX0
452 source_region.GetY(), // srcY0
453 source_region.GetWidth(), // srcX1
454 source_region.GetHeight(), // srcY1
455 destination_region.GetX(), // dstX0
456 destination_region.GetY(), // dstY0
457 destination_region.GetWidth(), // dstX1
458 destination_region.GetHeight(), // dstY1
459 GL_COLOR_BUFFER_BIT, // mask
460 GL_LINEAR // filter
461 );
462
463 return true;
464}
465
466} // namespace impeller
GLenum type
GLenum external_format
GLint internal_format
BufferView buffer_view
Wraps a closure that is invoked in the destructor unless released by the caller.
Definition closure.h:32
static TextureGLES & Cast(Texture &base)
void UpdateBufferData(const std::function< void(uint8_t *, size_t length)> &update_buffer_data)
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
const ProcTableGLES & GetProcTable() const
Get the OpenGL proc. table the reactor uses to manage handles.
bool IsSliceInitialized(size_t slice) const
bool SetAsFramebufferAttachment(GLenum target, AttachmentType attachment_type) const
void MarkSliceInitialized(size_t slice) const
Indicates that a specific texture slice has been initialized.
std::optional< GLuint > GetGLHandle() const
const TextureDescriptor & GetTextureDescriptor() const
Definition texture.cc:57
size_t length
FlTexture * texture
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set profile Make the profiler discard new samples once the profiler sample buffer is full When this flag is not the profiler sample buffer is used as a ring buffer
Definition switch_defs.h:98
constexpr size_t BytesPerPixelForPixelFormat(PixelFormat format)
Definition formats.h:469
std::string DebugToFramebufferError(int status)
static std::optional< GLuint > ConfigureFBO(const ProcTableGLES &gl, const std::shared_ptr< Texture > &texture, GLenum fbo_type)
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition formats.h:99
static void DeleteFBO(const ProcTableGLES &gl, GLuint fbo, GLenum type)
TextureCoordinateSystem
Definition formats.h:330
int32_t height
int32_t width
bool Encode(const ReactorGLES &reactor) const override
std::shared_ptr< Texture > destination
bool Encode(const ReactorGLES &reactor) const override
std::shared_ptr< DeviceBuffer > destination
std::shared_ptr< Texture > source
bool Encode(const ReactorGLES &reactor) const override
std::shared_ptr< Texture > destination
std::shared_ptr< Texture > source
Range GetRange() const
Definition buffer_view.h:27
size_t length
Definition range.h:15
constexpr Type GetY() const
Returns the Y coordinate of the upper left corner, equivalent to |GetOrigin().y|.
Definition rect.h:337
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
Definition rect.h:347
constexpr T Area() const
Get the area of the rectangle, equivalent to |GetSize().Area()|.
Definition rect.h:376
constexpr Type GetX() const
Returns the X coordinate of the upper left corner, equivalent to |GetOrigin().x|.
Definition rect.h:333
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
Definition rect.h:341
std::shared_ptr< const fml::Mapping > data
#define VALIDATION_LOG
Definition validation.h:91