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
7#include <algorithm>
8
17
18namespace impeller {
19
20namespace {
21static void FlipImage(uint8_t* buffer,
22 size_t width,
23 size_t height,
24 size_t stride) {
25 if (buffer == nullptr || stride == 0) {
26 return;
27 }
28
29 const auto byte_width = width * stride;
30
31 for (size_t top = 0; top < height; top++) {
32 size_t bottom = height - top - 1;
33 if (top >= bottom) {
34 break;
35 }
36 auto* top_row = buffer + byte_width * top;
37 auto* bottom_row = buffer + byte_width * bottom;
38 std::swap_ranges(top_row, top_row + byte_width, bottom_row);
39 }
40}
41} // namespace
42
44
45static void DeleteFBO(const ProcTableGLES& gl, GLuint fbo, GLenum type) {
46 if (fbo != GL_NONE) {
47 gl.BindFramebuffer(type, GL_NONE);
48 gl.DeleteFramebuffers(1u, &fbo);
49 }
50};
51
52static std::optional<GLuint> ConfigureFBO(
53 const ProcTableGLES& gl,
54 const std::shared_ptr<Texture>& texture,
55 GLenum fbo_type) {
56 auto handle = TextureGLES::Cast(texture.get())->GetGLHandle();
57 if (!handle.has_value()) {
58 return std::nullopt;
59 }
60
61 if (TextureGLES::Cast(*texture).IsWrapped()) {
62 // The texture is attached to the default FBO, so there's no need to
63 // create/configure one.
64 gl.BindFramebuffer(fbo_type, 0);
65 return 0;
66 }
67
68 GLuint fbo;
69 gl.GenFramebuffers(1u, &fbo);
70 gl.BindFramebuffer(fbo_type, fbo);
71
74 VALIDATION_LOG << "Could not attach texture to framebuffer.";
75 DeleteFBO(gl, fbo, fbo_type);
76 return std::nullopt;
77 }
78
79 GLenum status = gl.CheckFramebufferStatus(fbo_type);
80 if (status != GL_FRAMEBUFFER_COMPLETE) {
81 VALIDATION_LOG << "Could not create a complete framebuffer: "
82 << DebugToFramebufferError(status);
83 DeleteFBO(gl, fbo, fbo_type);
84 return std::nullopt;
85 }
86
87 return fbo;
88};
89
91 default;
92
94 return label;
95}
96
98 const ReactorGLES& reactor) const {
99 const auto& gl = reactor.GetProcTable();
100
101 // glBlitFramebuffer is a GLES3 proc. Since we target GLES2, we need to
102 // emulate the blit when it's not available in the driver.
103 if (!gl.BlitFramebuffer.IsAvailable()) {
104 // TODO(157064): Emulate the blit using a raster draw call here.
105 VALIDATION_LOG << "Texture blit fallback not implemented yet for GLES2.";
106 return false;
107 }
108
109 GLuint read_fbo = GL_NONE;
110 GLuint draw_fbo = GL_NONE;
111 fml::ScopedCleanupClosure delete_fbos([&gl, &read_fbo, &draw_fbo]() {
112 DeleteFBO(gl, read_fbo, GL_READ_FRAMEBUFFER);
113 DeleteFBO(gl, draw_fbo, GL_DRAW_FRAMEBUFFER);
114 });
115
116 {
117 auto read = ConfigureFBO(gl, source, GL_READ_FRAMEBUFFER);
118 if (!read.has_value()) {
119 return false;
120 }
121 read_fbo = read.value();
122 }
123
124 {
125 auto draw = ConfigureFBO(gl, destination, GL_DRAW_FRAMEBUFFER);
126 if (!draw.has_value()) {
127 return false;
128 }
129 draw_fbo = draw.value();
130 }
131
132 gl.Disable(GL_SCISSOR_TEST);
133 gl.Disable(GL_DEPTH_TEST);
134 gl.Disable(GL_STENCIL_TEST);
135
136 gl.BlitFramebuffer(source_region.GetX(), // srcX0
137 source_region.GetY(), // srcY0
138 source_region.GetWidth(), // srcX1
139 source_region.GetHeight(), // srcY1
140 destination_origin.x, // dstX0
141 destination_origin.y, // dstY0
142 source_region.GetWidth(), // dstX1
143 source_region.GetHeight(), // dstY1
144 GL_COLOR_BUFFER_BIT, // mask
145 GL_NEAREST // filter
146 );
147
148 return true;
149};
150
152 default;
153
155 return label;
156}
157
159 const ReactorGLES& reactor) const {
160 TextureGLES& texture_gles = TextureGLES::Cast(*destination);
161
162 if (texture_gles.GetType() != TextureGLES::Type::kTexture) {
163 VALIDATION_LOG << "Incorrect texture usage flags for setting contents on "
164 "this texture object.";
165 return false;
166 }
167
168 if (texture_gles.IsWrapped()) {
169 VALIDATION_LOG << "Cannot set the contents of a wrapped texture.";
170 return false;
171 }
172
173 const auto& tex_descriptor = texture_gles.GetTextureDescriptor();
174
175 if (tex_descriptor.size.IsEmpty()) {
176 return true;
177 }
178
179 if (!tex_descriptor.IsValid() ||
181 BytesPerPixelForPixelFormat(tex_descriptor.format) *
183 return false;
184 }
185
187
188 GLenum texture_type;
189 GLenum texture_target;
190 switch (tex_descriptor.type) {
192 texture_type = GL_TEXTURE_2D;
193 texture_target = GL_TEXTURE_2D;
194 break;
196 VALIDATION_LOG << "Multisample texture uploading is not supported for "
197 "the OpenGLES backend.";
198 return false;
200 texture_type = GL_TEXTURE_CUBE_MAP;
201 texture_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
202 break;
204 texture_type = GL_TEXTURE_EXTERNAL_OES;
205 texture_target = GL_TEXTURE_EXTERNAL_OES;
206 break;
207 }
208
209 std::optional<PixelFormatGLES> gles_format =
210 ToPixelFormatGLES(tex_descriptor.format,
211 /*supports_bgra=*/
213 "GL_EXT_texture_format_BGRA8888"));
214 if (!gles_format.has_value()) {
215 VALIDATION_LOG << "Invalid texture format.";
216 return false;
217 }
218
219 auto gl_handle = texture_gles.GetGLHandle();
220 if (!gl_handle.has_value()) {
222 << "Texture was collected before it could be uploaded to the GPU.";
223 return false;
224 }
225 const auto& gl = reactor.GetProcTable();
226 gl.BindTexture(texture_type, gl_handle.value());
227 const GLvoid* tex_data =
229
230 // GL_INVALID_OPERATION if the requested mip level has not been defined by
231 // a previous glTexImage2D operation. Allocate the requested mip lazily on
232 // first write, only for the level the upload is actually targeting. The
233 // snapshot pipeline (single base-level allocation followed by
234 // glGenerateMipmap) keeps its existing GL footprint, and per-level uploads
235 // pay only for the levels they touch.
236 if (!texture_gles.IsSliceMipLevelInitialized(slice, mip_level)) {
237 const auto level_width =
238 std::max<int32_t>(1, tex_descriptor.size.width >> mip_level);
239 const auto level_height =
240 std::max<int32_t>(1, tex_descriptor.size.height >> mip_level);
241 gl.TexImage2D(texture_target, // target
242 mip_level, // LOD level
243 gles_format->internal_format, // internal format
244 level_width, // width
245 level_height, // height
246 0u, // border
247 gles_format->external_format, // format
248 gles_format->type, // type
249 nullptr); // data
251 }
252
253 {
254 gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
255 gl.TexSubImage2D(texture_target, // target
256 mip_level, // LOD level
257 destination_region.GetX(), // xoffset
258 destination_region.GetY(), // yoffset
259 destination_region.GetWidth(), // width
260 destination_region.GetHeight(), // height
261 gles_format->external_format, // format
262 gles_format->type, // type
263 tex_data); // data
264 }
265 return true;
266}
267
269 default;
270
272 return label;
273}
274
276 const ReactorGLES& reactor) const {
277 const auto& gl = reactor.GetProcTable();
278
279 PixelFormat source_format = source->GetTextureDescriptor().format;
280 std::optional<PixelFormatGLES> gles_format =
281 ToPixelFormatGLES(source_format,
282 /*supports_bgra=*/
284 "GL_EXT_texture_format_BGRA8888"));
285
286 if (!gles_format.has_value()) {
287 VALIDATION_LOG << "Texture has unsupported pixel format.";
288 return false;
289 }
290
291 TextureCoordinateSystem coord_system = source->GetCoordinateSystem();
292
293 GLuint read_fbo = GL_NONE;
294 fml::ScopedCleanupClosure delete_fbos(
295 [&gl, &read_fbo]() { DeleteFBO(gl, read_fbo, GL_FRAMEBUFFER); });
296
297 {
298 auto read = ConfigureFBO(gl, source, GL_FRAMEBUFFER);
299 if (!read.has_value()) {
300 return false;
301 }
302 read_fbo = read.value();
303 }
304
307 [&gl, //
308 this, //
309 format = gles_format->external_format, //
310 type = gles_format->type, //
311 coord_system, //
312 bytes_per_pixel = BytesPerPixelForPixelFormat(source_format) //
313 ](uint8_t* data, size_t length) {
314 gl.ReadPixels(source_region.GetX(), source_region.GetY(),
317 switch (coord_system) {
319 break;
321 // The texture is upside down, and must be inverted when copying
322 // byte data out.
323 FlipImage(data + destination_offset, source_region.GetWidth(),
324 source_region.GetHeight(), bytes_per_pixel);
325 }
326 });
327
328 return true;
329};
330
332
334 return label;
335}
336
338 auto texture_gles = TextureGLES::Cast(texture.get());
339 if (!texture_gles->GenerateMipmap()) {
340 return false;
341 }
342
343 return true;
344};
345
346////// BlitResizeTextureCommandGLES
347//////////////////////////////////////////////////////
348
350
352 return "Resize Texture";
353}
354
356 const auto& gl = reactor.GetProcTable();
357
358 // glBlitFramebuffer is a GLES3 proc. Since we target GLES2, we need to
359 // emulate the blit when it's not available in the driver.
360 if (!gl.BlitFramebuffer.IsAvailable()) {
361 // TODO(157064): Emulate the blit using a raster draw call here.
362 VALIDATION_LOG << "Texture blit fallback not implemented yet for GLES2.";
363 return false;
364 }
365
366 destination->SetCoordinateSystem(source->GetCoordinateSystem());
367
368 GLuint read_fbo = GL_NONE;
369 GLuint draw_fbo = GL_NONE;
370 fml::ScopedCleanupClosure delete_fbos([&gl, &read_fbo, &draw_fbo]() {
371 DeleteFBO(gl, read_fbo, GL_READ_FRAMEBUFFER);
372 DeleteFBO(gl, draw_fbo, GL_DRAW_FRAMEBUFFER);
373 });
374
375 {
376 auto read = ConfigureFBO(gl, source, GL_READ_FRAMEBUFFER);
377 if (!read.has_value()) {
378 return false;
379 }
380 read_fbo = read.value();
381 }
382
383 {
384 auto draw = ConfigureFBO(gl, destination, GL_DRAW_FRAMEBUFFER);
385 if (!draw.has_value()) {
386 return false;
387 }
388 draw_fbo = draw.value();
389 }
390
391 gl.Disable(GL_SCISSOR_TEST);
392 gl.Disable(GL_DEPTH_TEST);
393 gl.Disable(GL_STENCIL_TEST);
394
395 const IRect source_region = IRect::MakeSize(source->GetSize());
396 const IRect destination_region = IRect::MakeSize(destination->GetSize());
397
398 gl.BlitFramebuffer(source_region.GetX(), // srcX0
399 source_region.GetY(), // srcY0
400 source_region.GetWidth(), // srcX1
401 source_region.GetHeight(), // srcY1
402 destination_region.GetX(), // dstX0
403 destination_region.GetY(), // dstY0
404 destination_region.GetWidth(), // dstX1
405 destination_region.GetHeight(), // dstY1
406 GL_COLOR_BUFFER_BIT, // mask
407 GL_LINEAR // filter
408 );
409
410 return true;
411}
412
413} // namespace impeller
Wraps a closure that is invoked in the destructor unless released by the caller.
Definition closure.h:32
static TextureGLES & Cast(Texture &base)
bool HasExtension(const std::string &ext) const
void UpdateBufferData(const std::function< void(uint8_t *, size_t length)> &update_buffer_data)
virtual uint8_t * OnGetContents() const =0
const DescriptionGLES * GetDescription() const
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 SetAsFramebufferAttachment(GLenum target, AttachmentType attachment_type)
bool IsSliceMipLevelInitialized(size_t slice, size_t mip_level) const
void MarkSliceMipLevelInitialized(size_t slice, size_t mip_level)
Indicates that storage for mip_level of slice has been allocated by a glTexImage2D call (or equivalen...
std::optional< GLuint > GetGLHandle() const
const TextureDescriptor & GetTextureDescriptor() const
Definition texture.cc:57
uint32_t uint32_t * format
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::optional< PixelFormatGLES > ToPixelFormatGLES(PixelFormat pixel_format, bool supports_bgra)
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
impeller::ShaderType type
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
bool Encode(const ReactorGLES &reactor) const override
std::shared_ptr< Texture > texture
bool Encode(const ReactorGLES &reactor) const override
std::string GetLabel() const override
std::shared_ptr< Texture > destination
std::shared_ptr< Texture > source
Range GetRange() const
Definition buffer_view.h:27
const DeviceBuffer * GetBuffer() const
size_t length
Definition range.h:15
size_t offset
Definition range.h:14
constexpr Type GetY() const
Returns the Y coordinate of the upper left corner, equivalent to |GetOrigin().y|.
Definition rect.h:371
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
Definition rect.h:381
constexpr T Area() const
Get the area of the rectangle, equivalent to |GetSize().Area()|.
Definition rect.h:410
constexpr Type GetX() const
Returns the X coordinate of the upper left corner, equivalent to |GetOrigin().x|.
Definition rect.h:367
static constexpr TRect MakeSize(const TSize< U > &size)
Definition rect.h:150
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
Definition rect.h:375
#define VALIDATION_LOG
Definition validation.h:91