Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
render_pass_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 <cstdint>
8
10#include "fml/closure.h"
11#include "fml/logging.h"
23
24namespace impeller {
25
26RenderPassGLES::RenderPassGLES(std::shared_ptr<const Context> context,
27 const RenderTarget& target,
28 std::shared_ptr<ReactorGLES> reactor)
29 : RenderPass(std::move(context), target),
30 reactor_(std::move(reactor)),
31 is_valid_(reactor_ && reactor_->IsValid()) {}
32
33// |RenderPass|
34RenderPassGLES::~RenderPassGLES() = default;
35
36// |RenderPass|
37bool RenderPassGLES::IsValid() const {
38 return is_valid_;
39}
40
41// |RenderPass|
42void RenderPassGLES::OnSetLabel(std::string_view label) {
43 label_ = label;
44}
45
47 const ColorAttachmentDescriptor* color) {
48 if (color->blending_enabled) {
49 gl.Enable(GL_BLEND);
50 gl.BlendFuncSeparate(
51 ToBlendFactor(color->src_color_blend_factor), // src color
52 ToBlendFactor(color->dst_color_blend_factor), // dst color
53 ToBlendFactor(color->src_alpha_blend_factor), // src alpha
54 ToBlendFactor(color->dst_alpha_blend_factor) // dst alpha
55 );
56 gl.BlendEquationSeparate(
57 ToBlendOperation(color->color_blend_op), // mode color
58 ToBlendOperation(color->alpha_blend_op) // mode alpha
59 );
60 } else {
61 gl.Disable(GL_BLEND);
62 }
63
64 {
65 const auto is_set = [](ColorWriteMask mask,
66 ColorWriteMask check) -> GLboolean {
67 return (mask & check) ? GL_TRUE : GL_FALSE;
68 };
69
70 gl.ColorMask(
71 is_set(color->write_mask, ColorWriteMaskBits::kRed), // red
72 is_set(color->write_mask, ColorWriteMaskBits::kGreen), // green
73 is_set(color->write_mask, ColorWriteMaskBits::kBlue), // blue
74 is_set(color->write_mask, ColorWriteMaskBits::kAlpha) // alpha
75 );
76 }
77}
78
79void ConfigureStencil(GLenum face,
80 const ProcTableGLES& gl,
81 const StencilAttachmentDescriptor& stencil,
82 uint32_t stencil_reference) {
83 gl.StencilOpSeparate(
84 face, // face
85 ToStencilOp(stencil.stencil_failure), // stencil fail
86 ToStencilOp(stencil.depth_failure), // depth fail
87 ToStencilOp(stencil.depth_stencil_pass) // depth stencil pass
88 );
89 gl.StencilFuncSeparate(face, // face
90 ToCompareFunction(stencil.stencil_compare), // func
91 stencil_reference, // ref
92 stencil.read_mask // mask
93 );
94 gl.StencilMaskSeparate(face, stencil.write_mask);
95}
96
98 const PipelineDescriptor& pipeline,
99 uint32_t stencil_reference) {
100 if (!pipeline.HasStencilAttachmentDescriptors()) {
101 gl.Disable(GL_STENCIL_TEST);
102 return;
103 }
104
105 gl.Enable(GL_STENCIL_TEST);
106 const auto& front = pipeline.GetFrontStencilAttachmentDescriptor();
107 const auto& back = pipeline.GetBackStencilAttachmentDescriptor();
108
109 if (front.has_value() && back.has_value() && front == back) {
110 ConfigureStencil(GL_FRONT_AND_BACK, gl, *front, stencil_reference);
111 return;
112 }
113 if (front.has_value()) {
114 ConfigureStencil(GL_FRONT, gl, *front, stencil_reference);
115 }
116 if (back.has_value()) {
117 ConfigureStencil(GL_BACK, gl, *back, stencil_reference);
118 }
119}
120
121//------------------------------------------------------------------------------
122/// @brief Encapsulates data that will be needed in the reactor for the
123/// encoding of commands for this render pass.
124///
127
129 uint32_t clear_stencil = 0u;
130 Scalar clear_depth = 1.0;
131
132 std::shared_ptr<Texture> color_attachment;
133 std::shared_ptr<Texture> resolve_attachment;
134 std::shared_ptr<Texture> depth_attachment;
135 std::shared_ptr<Texture> stencil_attachment;
136
137 bool clear_color_attachment = true;
138 bool clear_depth_attachment = true;
139 bool clear_stencil_attachment = true;
140
141 bool discard_color_attachment = true;
142 bool discard_depth_attachment = true;
143 bool discard_stencil_attachment = true;
144
145 std::string label;
146};
147
148static bool BindVertexBuffer(const ProcTableGLES& gl,
149 BufferBindingsGLES* vertex_desc_gles,
150 const BufferView& vertex_buffer_view,
151 size_t buffer_index) {
152 if (!vertex_buffer_view) {
153 return false;
154 }
155
156 const DeviceBuffer* vertex_buffer = vertex_buffer_view.GetBuffer();
157
158 if (!vertex_buffer) {
159 return false;
160 }
161
162 const auto& vertex_buffer_gles = DeviceBufferGLES::Cast(*vertex_buffer);
163 if (!vertex_buffer_gles.BindAndUploadDataIfNecessary(
164 DeviceBufferGLES::BindingType::kArrayBuffer)) {
165 return false;
166 }
167
168 //--------------------------------------------------------------------------
169 /// Bind the vertex attributes associated with vertex buffer.
170 ///
171 if (!vertex_desc_gles->BindVertexAttributes(
172 gl, buffer_index, vertex_buffer_view.GetRange().offset)) {
173 return false;
174 }
175
176 return true;
177}
178
179void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) {
180 gl.Disable(GL_SCISSOR_TEST);
181 gl.Disable(GL_DEPTH_TEST);
182 gl.Disable(GL_STENCIL_TEST);
183 gl.Disable(GL_CULL_FACE);
184 gl.Disable(GL_BLEND);
185 gl.Disable(GL_DITHER);
186 gl.ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
187 gl.DepthMask(GL_TRUE);
188 gl.StencilMaskSeparate(GL_FRONT, 0xFFFFFFFF);
189 gl.StencilMaskSeparate(GL_BACK, 0xFFFFFFFF);
190}
191
192static void EncodeViewport(const ProcTableGLES& gl,
193 const RenderPassData& pass_data,
194 const std::optional<Viewport>& command_viewport,
195 const ISize& target_size,
196 std::optional<Viewport>& current_viewport) {
197 auto new_viewport = command_viewport.value_or(pass_data.viewport);
198
199 if (current_viewport.has_value() &&
200 current_viewport.value() == new_viewport) {
201 // The viewport is the same as the last command. Skip an unnecessary call.
202 return;
203 }
204
205 current_viewport = new_viewport;
206
207 gl.Viewport(new_viewport.rect.GetX(), // x
208 target_size.height - new_viewport.rect.GetY() -
209 new_viewport.rect.GetHeight(), // y
210 new_viewport.rect.GetWidth(), // width
211 new_viewport.rect.GetHeight() // height
212 );
213 if (pass_data.depth_attachment) {
214 if (gl.DepthRangef.IsAvailable()) {
215 gl.DepthRangef(new_viewport.depth_range.z_near,
216 new_viewport.depth_range.z_far);
217 } else {
218 gl.DepthRange(new_viewport.depth_range.z_near,
219 new_viewport.depth_range.z_far);
220 }
221 }
222}
223
224[[nodiscard]] bool EncodeCommandsInReactor(
225 const RenderPassData& pass_data,
226 const ReactorGLES& reactor,
227 const std::vector<Command>& commands,
228 const std::vector<BufferView>& vertex_buffers,
229 const std::vector<TextureAndSampler>& bound_textures,
230 const std::vector<BufferResource>& bound_buffers,
231 const std::shared_ptr<GPUTracerGLES>& tracer,
232 const std::shared_ptr<const Context>& impeller_context) {
233 TRACE_EVENT0("impeller", "RenderPassGLES::EncodeCommandsInReactor");
234
235 const auto& gl = reactor.GetProcTable();
236#ifdef IMPELLER_DEBUG
237 tracer->MarkFrameStart(gl);
238
239 fml::ScopedCleanupClosure pop_pass_debug_marker(
240 [&gl]() { gl.PopDebugGroup(); });
241 if (!pass_data.label.empty()) {
242 gl.PushDebugGroup(pass_data.label);
243 } else {
244 pop_pass_debug_marker.Release();
245 }
246#endif // IMPELLER_DEBUG
247
248 TextureGLES& color_gles = TextureGLES::Cast(*pass_data.color_attachment);
249 const bool is_wrapped_fbo = color_gles.IsWrapped();
250
251 std::optional<GLuint> fbo = 0;
252 if (is_wrapped_fbo) {
253 if (color_gles.GetFBO().has_value()) {
254 // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
255 gl.BindFramebuffer(GL_FRAMEBUFFER, *color_gles.GetFBO());
256 }
257 } else {
258 // Create and bind an offscreen FBO.
259 if (!color_gles.GetCachedFBO().IsDead()) {
260 fbo = reactor.GetGLHandle(color_gles.GetCachedFBO());
261 if (!fbo.has_value()) {
262 return false;
263 }
264 gl.BindFramebuffer(GL_FRAMEBUFFER, fbo.value());
265 } else {
266 HandleGLES cached_fbo =
267 reactor.CreateUntrackedHandle(HandleType::kFrameBuffer);
268 color_gles.SetCachedFBO(cached_fbo);
269 fbo = reactor.GetGLHandle(cached_fbo);
270 if (!fbo.has_value()) {
271 return false;
272 }
273 gl.BindFramebuffer(GL_FRAMEBUFFER, fbo.value());
274
275 if (!color_gles.SetAsFramebufferAttachment(
276 GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) {
277 return false;
278 }
279
280 if (auto depth = TextureGLES::Cast(pass_data.depth_attachment.get())) {
281 if (!depth->SetAsFramebufferAttachment(
282 GL_FRAMEBUFFER, TextureGLES::AttachmentType::kDepth)) {
283 return false;
284 }
285 }
286 if (auto stencil =
287 TextureGLES::Cast(pass_data.stencil_attachment.get())) {
288 if (!stencil->SetAsFramebufferAttachment(
289 GL_FRAMEBUFFER, TextureGLES::AttachmentType::kStencil)) {
290 return false;
291 }
292 }
293
294 auto status = gl.CheckFramebufferStatusDebug(GL_FRAMEBUFFER);
295 if (status != GL_FRAMEBUFFER_COMPLETE) {
296 VALIDATION_LOG << "Could not create a complete framebuffer: "
297 << DebugToFramebufferError(status);
298 return false;
299 }
300 }
301 }
302
303 gl.ClearColor(pass_data.clear_color.red, // red
304 pass_data.clear_color.green, // green
305 pass_data.clear_color.blue, // blue
306 pass_data.clear_color.alpha // alpha
307 );
308 if (pass_data.depth_attachment) {
309 if (gl.DepthRangef.IsAvailable()) {
310 gl.ClearDepthf(pass_data.clear_depth);
311 } else {
312 gl.ClearDepth(pass_data.clear_depth);
313 }
314 }
315 if (pass_data.stencil_attachment) {
316 gl.ClearStencil(pass_data.clear_stencil);
317 }
318
319 GLenum clear_bits = 0u;
320 if (pass_data.clear_color_attachment) {
321 clear_bits |= GL_COLOR_BUFFER_BIT;
322 }
323 if (pass_data.clear_depth_attachment) {
324 clear_bits |= GL_DEPTH_BUFFER_BIT;
325 }
326 if (pass_data.clear_stencil_attachment) {
327 clear_bits |= GL_STENCIL_BUFFER_BIT;
328 }
329
330 RenderPassGLES::ResetGLState(gl);
331
332 gl.Clear(clear_bits);
333
334 // Both the viewport and scissor are specified in framebuffer coordinates.
335 // Impeller's framebuffer coordinate system is top left origin, but OpenGL's
336 // is bottom left origin, so we convert the coordinates here.
337 ISize target_size = pass_data.color_attachment->GetSize();
338
339 std::optional<Viewport> current_viewport;
340 CullMode current_cull_mode = CullMode::kNone;
341 WindingOrder current_winding_order = WindingOrder::kClockwise;
342 gl.FrontFace(GL_CW);
343
344 for (const auto& command : commands) {
345#ifdef IMPELLER_DEBUG
346 fml::ScopedCleanupClosure pop_cmd_debug_marker(
347 [&gl]() { gl.PopDebugGroup(); });
348 if (!command.label.empty()) {
349 gl.PushDebugGroup(command.label);
350 } else {
351 pop_cmd_debug_marker.Release();
352 }
353#endif // IMPELLER_DEBUG
354 const auto& pipeline = PipelineGLES::Cast(*command.pipeline);
355 impeller_context->GetPipelineLibrary()->LogPipelineUsage(
356 pipeline.GetDescriptor());
357 const auto* color_attachment =
358 pipeline.GetDescriptor().GetLegacyCompatibleColorAttachment();
359 if (!color_attachment) {
361 << "Color attachment is too complicated for a legacy renderer.";
362 return false;
363 }
364
365 //--------------------------------------------------------------------------
366 /// Configure blending.
367 ///
368 ConfigureBlending(gl, color_attachment);
369
370 //--------------------------------------------------------------------------
371 /// Setup stencil.
372 ///
373 ConfigureStencil(gl, pipeline.GetDescriptor(), command.stencil_reference);
374
375 //--------------------------------------------------------------------------
376 /// Configure depth.
377 ///
378 if (auto depth =
379 pipeline.GetDescriptor().GetDepthStencilAttachmentDescriptor();
380 depth.has_value()) {
381 gl.Enable(GL_DEPTH_TEST);
382 gl.DepthFunc(ToCompareFunction(depth->depth_compare));
383 gl.DepthMask(depth->depth_write_enabled ? GL_TRUE : GL_FALSE);
384 } else {
385 gl.Disable(GL_DEPTH_TEST);
386 }
387
388 //--------------------------------------------------------------------------
389 /// Setup the viewport.
390 ///
391 EncodeViewport(gl, //
392 pass_data, //
393 command.viewport, //
394 target_size, //
395 current_viewport //
396 );
397
398 //--------------------------------------------------------------------------
399 /// Setup the scissor rect.
400 ///
401 if (command.scissor.has_value()) {
402 const auto& scissor = command.scissor.value();
403 gl.Enable(GL_SCISSOR_TEST);
404 gl.Scissor(
405 scissor.GetX(), // x
406 target_size.height - scissor.GetY() - scissor.GetHeight(), // y
407 scissor.GetWidth(), // width
408 scissor.GetHeight() // height
409 );
410 }
411
412 //--------------------------------------------------------------------------
413 /// Setup culling.
414 ///
415 CullMode pipeline_cull_mode = pipeline.GetDescriptor().GetCullMode();
416 if (current_cull_mode != pipeline_cull_mode) {
417 switch (pipeline_cull_mode) {
418 case CullMode::kNone:
419 gl.Disable(GL_CULL_FACE);
420 break;
421 case CullMode::kFrontFace:
422 gl.Enable(GL_CULL_FACE);
423 gl.CullFace(GL_FRONT);
424 break;
425 case CullMode::kBackFace:
426 gl.Enable(GL_CULL_FACE);
427 gl.CullFace(GL_BACK);
428 break;
429 }
430 current_cull_mode = pipeline_cull_mode;
431 }
432
433 //--------------------------------------------------------------------------
434 /// Setup winding order.
435 ///
436 WindingOrder pipeline_winding_order =
437 pipeline.GetDescriptor().GetWindingOrder();
438 if (current_winding_order != pipeline_winding_order) {
439 switch (pipeline.GetDescriptor().GetWindingOrder()) {
440 case WindingOrder::kClockwise:
441 gl.FrontFace(GL_CW);
442 break;
443 case WindingOrder::kCounterClockwise:
444 gl.FrontFace(GL_CCW);
445 break;
446 }
447 current_winding_order = pipeline_winding_order;
448 }
449
450 BufferBindingsGLES* vertex_desc_gles = pipeline.GetBufferBindings();
451
452 //--------------------------------------------------------------------------
453 /// Bind vertex buffers.
454 ///
455 /// Note: There is no need to run `RenderPass::ValidateVertexBuffers` or
456 /// `RenderPass::ValidateIndexBuffer` here, as validation already runs
457 /// when the vertex/index buffers are set on the command.
458 ///
459 for (size_t i = 0; i < command.vertex_buffers.length; i++) {
460 if (!BindVertexBuffer(gl, vertex_desc_gles,
461 vertex_buffers[i + command.vertex_buffers.offset],
462 i)) {
463 return false;
464 }
465 }
466
467 //--------------------------------------------------------------------------
468 /// Bind the pipeline program.
469 ///
470 if (!pipeline.BindProgram()) {
471 return false;
472 }
473
474 //--------------------------------------------------------------------------
475 /// Bind uniform data.
476 ///
477 if (!vertex_desc_gles->BindUniformData(
478 gl, //
479 bound_textures, //
480 bound_buffers, //
481 /*texture_range=*/command.bound_textures, //
482 /*buffer_range=*/command.bound_buffers //
483 )) {
484 return false;
485 }
486
487 //--------------------------------------------------------------------------
488 /// Determine the primitive type.
489 ///
490 // GLES doesn't support setting the fill mode, so override the primitive
491 // with GL_LINE_STRIP to somewhat emulate PolygonMode::kLine. This isn't
492 // correct; full triangle outlines won't be drawn and disconnected
493 // geometry may appear connected. However this can still be useful for
494 // wireframe debug views.
495 GLenum mode =
496 pipeline.GetDescriptor().GetPolygonMode() == PolygonMode::kLine
497 ? GL_LINE_STRIP
498 : ToMode(pipeline.GetDescriptor().GetPrimitiveType());
499
500 //--------------------------------------------------------------------------
501 /// Finally! Invoke the draw call.
502 ///
503 if (command.index_type == IndexType::kNone) {
504 gl.DrawArrays(mode, command.base_vertex, command.element_count);
505 } else {
506 // Bind the index buffer if necessary.
507 auto index_buffer_view = command.index_buffer;
508 const DeviceBuffer* index_buffer = index_buffer_view.GetBuffer();
509 const auto& index_buffer_gles = DeviceBufferGLES::Cast(*index_buffer);
510 if (!index_buffer_gles.BindAndUploadDataIfNecessary(
511 DeviceBufferGLES::BindingType::kElementArrayBuffer)) {
512 return false;
513 }
514 gl.DrawElements(mode, // mode
515 command.element_count, // count
516 ToIndexType(command.index_type), // type
517 reinterpret_cast<const GLvoid*>(static_cast<GLsizei>(
518 index_buffer_view.GetRange().offset)) // indices
519 );
520 }
521
522 //--------------------------------------------------------------------------
523 /// Unbind vertex attribs.
524 ///
525 if (!vertex_desc_gles->UnbindVertexAttributes(gl)) {
526 return false;
527 }
528 }
529
530 if (pass_data.resolve_attachment &&
531 !gl.GetCapabilities()->SupportsImplicitResolvingMSAA() &&
532 !is_wrapped_fbo) {
533 FML_DCHECK(pass_data.resolve_attachment != pass_data.color_attachment);
534 TextureGLES& resolve_gles =
535 TextureGLES::Cast(*pass_data.resolve_attachment);
536 std::optional<GLuint> resolve_fbo_opt;
537
538 if (!resolve_gles.GetCachedFBO().IsDead()) {
539 resolve_fbo_opt = reactor.GetGLHandle(resolve_gles.GetCachedFBO());
540 }
541
542 if (!resolve_fbo_opt.has_value()) {
543 HandleGLES cached_fbo =
544 reactor.CreateUntrackedHandle(HandleType::kFrameBuffer);
545 resolve_gles.SetCachedFBO(cached_fbo);
546 resolve_fbo_opt = reactor.GetGLHandle(cached_fbo);
547 gl.BindFramebuffer(GL_FRAMEBUFFER, resolve_fbo_opt.value());
548
549 if (!resolve_gles.SetAsFramebufferAttachment(
550 GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) {
551 return false;
552 }
553
554 auto status = gl.CheckFramebufferStatusDebug(GL_FRAMEBUFFER);
555 if (status != GL_FRAMEBUFFER_COMPLETE) {
556 VALIDATION_LOG << "Could not create a complete frambuffer: "
557 << DebugToFramebufferError(status);
558 return false;
559 }
560 } else {
561 gl.BindFramebuffer(GL_FRAMEBUFFER, resolve_fbo_opt.value());
562 }
563
564 // Bind MSAA renderbuffer to read framebuffer.
565 gl.BindFramebuffer(GL_READ_FRAMEBUFFER, fbo.value());
566 gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo_opt.value());
567
568 RenderPassGLES::ResetGLState(gl);
569 auto size = pass_data.color_attachment->GetSize();
570
571 gl.BlitFramebuffer(/*srcX0=*/0,
572 /*srcY0=*/0,
573 /*srcX1=*/size.width,
574 /*srcY1=*/size.height,
575 /*dstX0=*/0,
576 /*dstY0=*/0,
577 /*dstX1=*/size.width,
578 /*dstY1=*/size.height,
579 /*mask=*/GL_COLOR_BUFFER_BIT,
580 /*filter=*/GL_NEAREST);
581
582 gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, GL_NONE);
583 gl.BindFramebuffer(GL_READ_FRAMEBUFFER, GL_NONE);
584 // Rebind the original FBO so that we can discard it below.
585 gl.BindFramebuffer(GL_FRAMEBUFFER, fbo.value());
586 }
587
588 GLint framebuffer_id = 0;
589 gl.GetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer_id);
590 const bool is_default_fbo = framebuffer_id == 0;
591
592 if (gl.InvalidateFramebuffer.IsAvailable()) {
593 std::array<GLenum, 3> attachments;
594 size_t attachment_count = 0;
595
596 bool angle_safe = gl.GetCapabilities()->IsANGLE() ? !is_default_fbo : true;
597
598 if (pass_data.discard_color_attachment) {
599 attachments[attachment_count++] =
600 (is_default_fbo ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0);
601 }
602
603 if (pass_data.discard_depth_attachment && angle_safe) {
604 attachments[attachment_count++] =
605 (is_default_fbo ? GL_DEPTH_EXT : GL_DEPTH_ATTACHMENT);
606 }
607
608 if (pass_data.discard_stencil_attachment && angle_safe) {
609 attachments[attachment_count++] =
610 (is_default_fbo ? GL_STENCIL_EXT : GL_STENCIL_ATTACHMENT);
611 }
612 gl.InvalidateFramebuffer(GL_FRAMEBUFFER, // target
613 attachment_count, // attachments to discard
614 attachments.data() // size
615 );
616 } else if (gl.DiscardFramebufferEXT.IsAvailable()) {
617 std::array<GLenum, 3> attachments;
618 size_t attachment_count = 0;
619
620 // TODO(130048): discarding stencil or depth on the default fbo causes Angle
621 // to discard the entire render target. Until we know the reason, default to
622 // storing.
623 bool angle_safe = gl.GetCapabilities()->IsANGLE() ? !is_default_fbo : true;
624
625 if (pass_data.discard_color_attachment) {
626 attachments[attachment_count++] =
627 (is_default_fbo ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0);
628 }
629
630 if (pass_data.discard_depth_attachment && angle_safe) {
631 attachments[attachment_count++] =
632 (is_default_fbo ? GL_DEPTH_EXT : GL_DEPTH_ATTACHMENT);
633 }
634
635 if (pass_data.discard_stencil_attachment && angle_safe) {
636 attachments[attachment_count++] =
637 (is_default_fbo ? GL_STENCIL_EXT : GL_STENCIL_ATTACHMENT);
638 }
639 gl.DiscardFramebufferEXT(GL_FRAMEBUFFER, // target
640 attachment_count, // attachments to discard
641 attachments.data() // size
642 );
643 }
644
645#ifdef IMPELLER_DEBUG
646 if (is_default_fbo) {
647 tracer->MarkFrameEnd(gl);
648 }
649#endif // IMPELLER_DEBUG
650
651 return true;
652}
653
654// |RenderPass|
655bool RenderPassGLES::OnEncodeCommands(const Context& context) const {
656 if (!IsValid()) {
657 return false;
658 }
659 const auto& render_target = GetRenderTarget();
660 if (!render_target.HasColorAttachment(0u)) {
661 return false;
662 }
663 const ColorAttachment& color0 = render_target.GetColorAttachment(0);
664 const std::optional<DepthAttachment>& depth0 =
665 render_target.GetDepthAttachment();
666 const std::optional<StencilAttachment>& stencil0 =
667 render_target.GetStencilAttachment();
668
669 auto pass_data = std::make_shared<RenderPassData>();
670 pass_data->label = label_;
671 pass_data->viewport.rect = Rect::MakeSize(GetRenderTargetSize());
672
673 //----------------------------------------------------------------------------
674 /// Setup color data.
675 ///
676 pass_data->color_attachment = color0.texture;
677 pass_data->resolve_attachment = color0.resolve_texture;
678 pass_data->clear_color = color0.clear_color;
679 pass_data->clear_color_attachment = CanClearAttachment(color0.load_action);
680 pass_data->discard_color_attachment =
681 CanDiscardAttachmentWhenDone(color0.store_action);
682
683 // When we are using EXT_multisampled_render_to_texture, it is implicitly
684 // resolved when we bind the texture to the framebuffer. We don't need to
685 // discard the attachment when we are done. If not using
686 // EXT_multisampled_render_to_texture but still using MSAA we discard the
687 // attachment as normal.
688 if (color0.resolve_texture) {
689 pass_data->discard_color_attachment =
690 pass_data->discard_color_attachment &&
691 !context.GetCapabilities()->SupportsImplicitResolvingMSAA();
692 }
693
694 //----------------------------------------------------------------------------
695 /// Setup depth data.
696 ///
697 if (depth0.has_value()) {
698 pass_data->depth_attachment = depth0->texture;
699 pass_data->clear_depth = depth0->clear_depth;
700 pass_data->clear_depth_attachment = CanClearAttachment(depth0->load_action);
701 pass_data->discard_depth_attachment =
702 CanDiscardAttachmentWhenDone(depth0->store_action);
703 }
704
705 //----------------------------------------------------------------------------
706 /// Setup stencil data.
707 ///
708 if (stencil0.has_value()) {
709 pass_data->stencil_attachment = stencil0->texture;
710 pass_data->clear_stencil = stencil0->clear_stencil;
711 pass_data->clear_stencil_attachment =
712 CanClearAttachment(stencil0->load_action);
713 pass_data->discard_stencil_attachment =
714 CanDiscardAttachmentWhenDone(stencil0->store_action);
715 }
716
717 return reactor_->AddOperation(
718 [pass_data = std::move(pass_data), render_pass = shared_from_this(),
719 tracer =
720 ContextGLES::Cast(context).GetGPUTracer()](const auto& reactor) {
721 auto result = EncodeCommandsInReactor(
722 /*pass_data=*/*pass_data, //
723 /*reactor=*/reactor, //
724 /*commands=*/render_pass->commands_, //
725 /*vertex_buffers=*/render_pass->vertex_buffers_, //
726 /*bound_textures=*/render_pass->bound_textures_, //
727 /*bound_buffers=*/render_pass->bound_buffers_, //
728 /*tracer=*/tracer, //
729 /*impeller_context=*/render_pass->context_);
730 FML_CHECK(result)
731 << "Must be able to encode GL commands without error.";
732 },
733 /*defer=*/true);
734}
735
736} // namespace impeller
Wraps a closure that is invoked in the destructor unless released by the caller.
Definition closure.h:32
fml::closure Release()
Definition closure.h:58
Sets up stage bindings for single draw call in the OpenGLES backend.
bool BindVertexAttributes(const ProcTableGLES &gl, size_t binding, size_t vertex_offset)
bool UnbindVertexAttributes(const ProcTableGLES &gl)
bool BindUniformData(const ProcTableGLES &gl, const std::vector< TextureAndSampler > &bound_textures, const std::vector< BufferResource > &bound_buffers, Range texture_range, Range buffer_range)
Represents a handle to an underlying OpenGL object. Unlike OpenGL object handles, these handles can b...
Definition handle_gles.h:42
constexpr bool IsDead() const
Determines if the handle is dead.
Definition handle_gles.h:58
std::optional< StencilAttachmentDescriptor > GetBackStencilAttachmentDescriptor() const
std::optional< StencilAttachmentDescriptor > GetFrontStencilAttachmentDescriptor() const
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
std::optional< GLuint > GetGLHandle(const HandleGLES &handle) const
Returns the OpenGL handle for a reactor handle if one is available. This is typically only safe to ca...
HandleGLES CreateUntrackedHandle(HandleType type) const
Create a handle that is not managed by ReactorGLES.
const ProcTableGLES & GetProcTable() const
Get the OpenGL proc. table the reactor uses to manage handles.
const HandleGLES & GetCachedFBO() const
Retrieve the cached FBO object, or a dead handle if there is no object.
bool SetAsFramebufferAttachment(GLenum target, AttachmentType attachment_type)
void SetCachedFBO(HandleGLES fbo)
std::optional< GLuint > GetFBO() const
uint32_t framebuffer_id
uint32_t * target
#define FML_CHECK(condition)
Definition logging.h:104
#define FML_DCHECK(condition)
Definition logging.h:122
static void BindVertexBuffer(flutter::gpu::RenderPass *wrapper, const std::shared_ptr< const impeller::DeviceBuffer > &buffer, int offset_in_bytes, int length_in_bytes, int vertex_count, int slot)
constexpr bool CanClearAttachment(LoadAction action)
Definition formats.h:242
float Scalar
Definition scalar.h:19
constexpr GLenum ToIndexType(IndexType type)
constexpr GLenum ToCompareFunction(CompareFunction func)
std::string DebugToFramebufferError(int status)
constexpr GLenum ToStencilOp(StencilOperation op)
constexpr GLenum ToMode(PrimitiveType primitive_type)
static void EncodeViewport(const ProcTableGLES &gl, const RenderPassData &pass_data, const std::optional< Viewport > &command_viewport, const ISize &target_size, std::optional< Viewport > &current_viewport)
WindingOrder
Definition formats.h:22
void ConfigureBlending(const ProcTableGLES &gl, const ColorAttachmentDescriptor *color)
bool EncodeCommandsInReactor(const ReactorGLES &reactor, const std::vector< std::unique_ptr< BlitEncodeGLES > > &commands, const std::string &label)
constexpr GLenum ToBlendFactor(BlendFactor factor)
void ConfigureStencil(GLenum face, const ProcTableGLES &gl, const StencilAttachmentDescriptor &stencil, uint32_t stencil_reference)
constexpr GLenum ToBlendOperation(BlendOperation op)
constexpr bool CanDiscardAttachmentWhenDone(StoreAction action)
Definition formats.h:253
Definition ref_ptr.h:261
Range GetRange() const
Definition buffer_view.h:27
const DeviceBuffer * GetBuffer() const
Describe the color attachment that will be used with this pipeline.
Definition formats.h:522
Scalar blue
Definition color.h:138
Scalar alpha
Definition color.h:143
Scalar red
Definition color.h:128
Scalar green
Definition color.h:133
size_t offset
Definition range.h:14
Encapsulates data that will be needed in the reactor for the encoding of commands for this render pas...
std::shared_ptr< Texture > depth_attachment
std::shared_ptr< Texture > color_attachment
std::shared_ptr< Texture > stencil_attachment
std::shared_ptr< Texture > resolve_attachment
Type height
Definition size.h:29
#define TRACE_EVENT0(category_group, name)
#define VALIDATION_LOG
Definition validation.h:91