Flutter Impeller
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 
9 #include "flutter/fml/trace_event.h"
10 #include "fml/closure.h"
11 #include "fml/logging.h"
14 #include "impeller/core/formats.h"
23 
24 namespace impeller {
25 
26 RenderPassGLES::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|
34 RenderPassGLES::~RenderPassGLES() = default;
35 
36 // |RenderPass|
37 bool RenderPassGLES::IsValid() const {
38  return is_valid_;
39 }
40 
41 // |RenderPass|
42 void 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 
79 void 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 
148 static 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 
179 void 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 
192 [[nodiscard]] bool EncodeCommandsInReactor(
193  const RenderPassData& pass_data,
194  const ReactorGLES& reactor,
195  const std::vector<Command>& commands,
196  const std::vector<BufferView>& vertex_buffers,
197  const std::vector<TextureAndSampler>& bound_textures,
198  const std::vector<BufferResource>& bound_buffers,
199  const std::shared_ptr<GPUTracerGLES>& tracer,
200  const std::shared_ptr<const Context>& impeller_context) {
201  TRACE_EVENT0("impeller", "RenderPassGLES::EncodeCommandsInReactor");
202 
203  const auto& gl = reactor.GetProcTable();
204 #ifdef IMPELLER_DEBUG
205  tracer->MarkFrameStart(gl);
206 
207  fml::ScopedCleanupClosure pop_pass_debug_marker(
208  [&gl]() { gl.PopDebugGroup(); });
209  if (!pass_data.label.empty()) {
210  gl.PushDebugGroup(pass_data.label);
211  } else {
212  pop_pass_debug_marker.Release();
213  }
214 #endif // IMPELLER_DEBUG
215 
216  TextureGLES& color_gles = TextureGLES::Cast(*pass_data.color_attachment);
217  const bool is_wrapped_fbo = color_gles.IsWrapped();
218 
219  std::optional<GLuint> fbo = 0;
220  if (is_wrapped_fbo) {
221  if (color_gles.GetFBO().has_value()) {
222  // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
223  gl.BindFramebuffer(GL_FRAMEBUFFER, *color_gles.GetFBO());
224  }
225  } else {
226  // Create and bind an offscreen FBO.
227  if (!color_gles.GetCachedFBO().IsDead()) {
228  fbo = reactor.GetGLHandle(color_gles.GetCachedFBO());
229  if (!fbo.has_value()) {
230  return false;
231  }
232  gl.BindFramebuffer(GL_FRAMEBUFFER, fbo.value());
233  } else {
234  HandleGLES cached_fbo =
235  reactor.CreateUntrackedHandle(HandleType::kFrameBuffer);
236  color_gles.SetCachedFBO(cached_fbo);
237  fbo = reactor.GetGLHandle(cached_fbo);
238  if (!fbo.has_value()) {
239  return false;
240  }
241  gl.BindFramebuffer(GL_FRAMEBUFFER, fbo.value());
242 
243  if (!color_gles.SetAsFramebufferAttachment(
244  GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) {
245  return false;
246  }
247 
248  if (auto depth = TextureGLES::Cast(pass_data.depth_attachment.get())) {
249  if (!depth->SetAsFramebufferAttachment(
250  GL_FRAMEBUFFER, TextureGLES::AttachmentType::kDepth)) {
251  return false;
252  }
253  }
254  if (auto stencil =
255  TextureGLES::Cast(pass_data.stencil_attachment.get())) {
256  if (!stencil->SetAsFramebufferAttachment(
257  GL_FRAMEBUFFER, TextureGLES::AttachmentType::kStencil)) {
258  return false;
259  }
260  }
261 
262  auto status = gl.CheckFramebufferStatusDebug(GL_FRAMEBUFFER);
263  if (status != GL_FRAMEBUFFER_COMPLETE) {
264  VALIDATION_LOG << "Could not create a complete framebuffer: "
265  << DebugToFramebufferError(status);
266  return false;
267  }
268  }
269  }
270 
271  gl.ClearColor(pass_data.clear_color.red, // red
272  pass_data.clear_color.green, // green
273  pass_data.clear_color.blue, // blue
274  pass_data.clear_color.alpha // alpha
275  );
276  if (pass_data.depth_attachment) {
277  if (gl.DepthRangef.IsAvailable()) {
278  gl.ClearDepthf(pass_data.clear_depth);
279  } else {
280  gl.ClearDepth(pass_data.clear_depth);
281  }
282  }
283  if (pass_data.stencil_attachment) {
284  gl.ClearStencil(pass_data.clear_stencil);
285  }
286 
287  GLenum clear_bits = 0u;
288  if (pass_data.clear_color_attachment) {
289  clear_bits |= GL_COLOR_BUFFER_BIT;
290  }
291  if (pass_data.clear_depth_attachment) {
292  clear_bits |= GL_DEPTH_BUFFER_BIT;
293  }
294  if (pass_data.clear_stencil_attachment) {
295  clear_bits |= GL_STENCIL_BUFFER_BIT;
296  }
297 
298  RenderPassGLES::ResetGLState(gl);
299 
300  gl.Clear(clear_bits);
301 
302  // Both the viewport and scissor are specified in framebuffer coordinates.
303  // Impeller's framebuffer coordinate system is top left origin, but OpenGL's
304  // is bottom left origin, so we convert the coordinates here.
305  ISize target_size = pass_data.color_attachment->GetSize();
306 
307  //--------------------------------------------------------------------------
308  /// Setup the viewport.
309  ///
310  const auto& viewport = pass_data.viewport;
311  gl.Viewport(viewport.rect.GetX(), // x
312  target_size.height - viewport.rect.GetY() -
313  viewport.rect.GetHeight(), // y
314  viewport.rect.GetWidth(), // width
315  viewport.rect.GetHeight() // height
316  );
317  if (pass_data.depth_attachment) {
318  if (gl.DepthRangef.IsAvailable()) {
319  gl.DepthRangef(viewport.depth_range.z_near, viewport.depth_range.z_far);
320  } else {
321  gl.DepthRange(viewport.depth_range.z_near, viewport.depth_range.z_far);
322  }
323  }
324 
325  CullMode current_cull_mode = CullMode::kNone;
326  WindingOrder current_winding_order = WindingOrder::kClockwise;
327  gl.FrontFace(GL_CW);
328 
329  for (const auto& command : commands) {
330 #ifdef IMPELLER_DEBUG
331  fml::ScopedCleanupClosure pop_cmd_debug_marker(
332  [&gl]() { gl.PopDebugGroup(); });
333  if (!command.label.empty()) {
334  gl.PushDebugGroup(command.label);
335  } else {
336  pop_cmd_debug_marker.Release();
337  }
338 #endif // IMPELLER_DEBUG
339  const auto& pipeline = PipelineGLES::Cast(*command.pipeline);
340  impeller_context->GetPipelineLibrary()->LogPipelineUsage(
341  pipeline.GetDescriptor());
342  const auto* color_attachment =
343  pipeline.GetDescriptor().GetLegacyCompatibleColorAttachment();
344  if (!color_attachment) {
346  << "Color attachment is too complicated for a legacy renderer.";
347  return false;
348  }
349 
350  //--------------------------------------------------------------------------
351  /// Configure blending.
352  ///
353  ConfigureBlending(gl, color_attachment);
354 
355  //--------------------------------------------------------------------------
356  /// Setup stencil.
357  ///
358  ConfigureStencil(gl, pipeline.GetDescriptor(), command.stencil_reference);
359 
360  //--------------------------------------------------------------------------
361  /// Configure depth.
362  ///
363  if (auto depth =
364  pipeline.GetDescriptor().GetDepthStencilAttachmentDescriptor();
365  depth.has_value()) {
366  gl.Enable(GL_DEPTH_TEST);
367  gl.DepthFunc(ToCompareFunction(depth->depth_compare));
368  gl.DepthMask(depth->depth_write_enabled ? GL_TRUE : GL_FALSE);
369  } else {
370  gl.Disable(GL_DEPTH_TEST);
371  }
372 
373  //--------------------------------------------------------------------------
374  /// Setup the viewport.
375  ///
376  if (command.viewport.has_value()) {
377  gl.Viewport(viewport.rect.GetX(), // x
378  target_size.height - viewport.rect.GetY() -
379  viewport.rect.GetHeight(), // y
380  viewport.rect.GetWidth(), // width
381  viewport.rect.GetHeight() // height
382  );
383  if (pass_data.depth_attachment) {
384  if (gl.DepthRangef.IsAvailable()) {
385  gl.DepthRangef(viewport.depth_range.z_near,
386  viewport.depth_range.z_far);
387  } else {
388  gl.DepthRange(viewport.depth_range.z_near,
389  viewport.depth_range.z_far);
390  }
391  }
392  }
393 
394  //--------------------------------------------------------------------------
395  /// Setup the scissor rect.
396  ///
397  if (command.scissor.has_value()) {
398  const auto& scissor = command.scissor.value();
399  gl.Enable(GL_SCISSOR_TEST);
400  gl.Scissor(
401  scissor.GetX(), // x
402  target_size.height - scissor.GetY() - scissor.GetHeight(), // y
403  scissor.GetWidth(), // width
404  scissor.GetHeight() // height
405  );
406  }
407 
408  //--------------------------------------------------------------------------
409  /// Setup culling.
410  ///
411  CullMode pipeline_cull_mode = pipeline.GetDescriptor().GetCullMode();
412  if (current_cull_mode != pipeline_cull_mode) {
413  switch (pipeline_cull_mode) {
414  case CullMode::kNone:
415  gl.Disable(GL_CULL_FACE);
416  break;
417  case CullMode::kFrontFace:
418  gl.Enable(GL_CULL_FACE);
419  gl.CullFace(GL_FRONT);
420  break;
421  case CullMode::kBackFace:
422  gl.Enable(GL_CULL_FACE);
423  gl.CullFace(GL_BACK);
424  break;
425  }
426  current_cull_mode = pipeline_cull_mode;
427  }
428 
429  //--------------------------------------------------------------------------
430  /// Setup winding order.
431  ///
432  WindingOrder pipeline_winding_order =
433  pipeline.GetDescriptor().GetWindingOrder();
434  if (current_winding_order != pipeline_winding_order) {
435  switch (pipeline.GetDescriptor().GetWindingOrder()) {
436  case WindingOrder::kClockwise:
437  gl.FrontFace(GL_CW);
438  break;
439  case WindingOrder::kCounterClockwise:
440  gl.FrontFace(GL_CCW);
441  break;
442  }
443  current_winding_order = pipeline_winding_order;
444  }
445 
446  BufferBindingsGLES* vertex_desc_gles = pipeline.GetBufferBindings();
447 
448  //--------------------------------------------------------------------------
449  /// Bind vertex buffers.
450  ///
451  /// Note: There is no need to run `RenderPass::ValidateVertexBuffers` or
452  /// `RenderPass::ValidateIndexBuffer` here, as validation already runs
453  /// when the vertex/index buffers are set on the command.
454  ///
455  for (size_t i = 0; i < command.vertex_buffers.length; i++) {
456  if (!BindVertexBuffer(gl, vertex_desc_gles,
457  vertex_buffers[i + command.vertex_buffers.offset],
458  i)) {
459  return false;
460  }
461  }
462 
463  //--------------------------------------------------------------------------
464  /// Bind the pipeline program.
465  ///
466  if (!pipeline.BindProgram()) {
467  return false;
468  }
469 
470  //--------------------------------------------------------------------------
471  /// Bind uniform data.
472  ///
473  if (!vertex_desc_gles->BindUniformData(
474  gl, //
475  bound_textures, //
476  bound_buffers, //
477  /*texture_range=*/command.bound_textures, //
478  /*buffer_range=*/command.bound_buffers //
479  )) {
480  return false;
481  }
482 
483  //--------------------------------------------------------------------------
484  /// Determine the primitive type.
485  ///
486  // GLES doesn't support setting the fill mode, so override the primitive
487  // with GL_LINE_STRIP to somewhat emulate PolygonMode::kLine. This isn't
488  // correct; full triangle outlines won't be drawn and disconnected
489  // geometry may appear connected. However this can still be useful for
490  // wireframe debug views.
491  GLenum mode =
492  pipeline.GetDescriptor().GetPolygonMode() == PolygonMode::kLine
493  ? GL_LINE_STRIP
494  : ToMode(pipeline.GetDescriptor().GetPrimitiveType());
495 
496  //--------------------------------------------------------------------------
497  /// Finally! Invoke the draw call.
498  ///
499  if (command.index_type == IndexType::kNone) {
500  gl.DrawArrays(mode, command.base_vertex, command.element_count);
501  } else {
502  // Bind the index buffer if necessary.
503  auto index_buffer_view = command.index_buffer;
504  const DeviceBuffer* index_buffer = index_buffer_view.GetBuffer();
505  const auto& index_buffer_gles = DeviceBufferGLES::Cast(*index_buffer);
506  if (!index_buffer_gles.BindAndUploadDataIfNecessary(
507  DeviceBufferGLES::BindingType::kElementArrayBuffer)) {
508  return false;
509  }
510  gl.DrawElements(mode, // mode
511  command.element_count, // count
512  ToIndexType(command.index_type), // type
513  reinterpret_cast<const GLvoid*>(static_cast<GLsizei>(
514  index_buffer_view.GetRange().offset)) // indices
515  );
516  }
517 
518  //--------------------------------------------------------------------------
519  /// Unbind vertex attribs.
520  ///
521  if (!vertex_desc_gles->UnbindVertexAttributes(gl)) {
522  return false;
523  }
524  }
525 
526  if (pass_data.resolve_attachment &&
527  !gl.GetCapabilities()->SupportsImplicitResolvingMSAA() &&
528  !is_wrapped_fbo) {
529  FML_DCHECK(pass_data.resolve_attachment != pass_data.color_attachment);
530  // Perform multisample resolve via blit.
531  // Create and bind a resolve FBO.
532  GLuint resolve_fbo;
533  gl.GenFramebuffers(1u, &resolve_fbo);
534  gl.BindFramebuffer(GL_FRAMEBUFFER, resolve_fbo);
535 
536  if (!TextureGLES::Cast(*pass_data.resolve_attachment)
537  .SetAsFramebufferAttachment(
538  GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) {
539  return false;
540  }
541 
542  auto status = gl.CheckFramebufferStatusDebug(GL_FRAMEBUFFER);
543  if (status != GL_FRAMEBUFFER_COMPLETE) {
544  VALIDATION_LOG << "Could not create a complete frambuffer: "
545  << DebugToFramebufferError(status);
546  return false;
547  }
548 
549  // Bind MSAA renderbuffer to read framebuffer.
550  gl.BindFramebuffer(GL_READ_FRAMEBUFFER, fbo.value());
551  gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo);
552 
553  RenderPassGLES::ResetGLState(gl);
554  auto size = pass_data.color_attachment->GetSize();
555 
556  gl.BlitFramebuffer(/*srcX0=*/0,
557  /*srcY0=*/0,
558  /*srcX1=*/size.width,
559  /*srcY1=*/size.height,
560  /*dstX0=*/0,
561  /*dstY0=*/0,
562  /*dstX1=*/size.width,
563  /*dstY1=*/size.height,
564  /*mask=*/GL_COLOR_BUFFER_BIT,
565  /*filter=*/GL_NEAREST);
566 
567  gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, GL_NONE);
568  gl.BindFramebuffer(GL_READ_FRAMEBUFFER, GL_NONE);
569  gl.DeleteFramebuffers(1u, &resolve_fbo);
570  // Rebind the original FBO so that we can discard it below.
571  gl.BindFramebuffer(GL_FRAMEBUFFER, fbo.value());
572  }
573 
574  GLint framebuffer_id = 0;
575  gl.GetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer_id);
576  const bool is_default_fbo = framebuffer_id == 0;
577 
578  if (gl.DiscardFramebufferEXT.IsAvailable()) {
579  std::array<GLenum, 3> attachments;
580  size_t attachment_count = 0;
581 
582  // TODO(130048): discarding stencil or depth on the default fbo causes Angle
583  // to discard the entire render target. Until we know the reason, default to
584  // storing.
585  bool angle_safe = gl.GetCapabilities()->IsANGLE() ? !is_default_fbo : true;
586 
587  if (pass_data.discard_color_attachment) {
588  attachments[attachment_count++] =
589  (is_default_fbo ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0);
590  }
591 
592  if (pass_data.discard_depth_attachment && angle_safe) {
593  attachments[attachment_count++] =
594  (is_default_fbo ? GL_DEPTH_EXT : GL_DEPTH_ATTACHMENT);
595  }
596 
597  if (pass_data.discard_stencil_attachment && angle_safe) {
598  attachments[attachment_count++] =
599  (is_default_fbo ? GL_STENCIL_EXT : GL_STENCIL_ATTACHMENT);
600  }
601  gl.DiscardFramebufferEXT(GL_FRAMEBUFFER, // target
602  attachment_count, // attachments to discard
603  attachments.data() // size
604  );
605  }
606 
607 #ifdef IMPELLER_DEBUG
608  if (is_default_fbo) {
609  tracer->MarkFrameEnd(gl);
610  }
611 #endif // IMPELLER_DEBUG
612 
613  return true;
614 }
615 
616 // |RenderPass|
617 bool RenderPassGLES::OnEncodeCommands(const Context& context) const {
618  if (!IsValid()) {
619  return false;
620  }
621  const auto& render_target = GetRenderTarget();
622  if (!render_target.HasColorAttachment(0u)) {
623  return false;
624  }
625  const ColorAttachment& color0 = render_target.GetColorAttachment(0);
626  const std::optional<DepthAttachment>& depth0 =
627  render_target.GetDepthAttachment();
628  const std::optional<StencilAttachment>& stencil0 =
629  render_target.GetStencilAttachment();
630 
631  auto pass_data = std::make_shared<RenderPassData>();
632  pass_data->label = label_;
633  pass_data->viewport.rect = Rect::MakeSize(GetRenderTargetSize());
634 
635  //----------------------------------------------------------------------------
636  /// Setup color data.
637  ///
638  pass_data->color_attachment = color0.texture;
639  pass_data->resolve_attachment = color0.resolve_texture;
640  pass_data->clear_color = color0.clear_color;
641  pass_data->clear_color_attachment = CanClearAttachment(color0.load_action);
642  pass_data->discard_color_attachment =
643  CanDiscardAttachmentWhenDone(color0.store_action);
644 
645  // When we are using EXT_multisampled_render_to_texture, it is implicitly
646  // resolved when we bind the texture to the framebuffer. We don't need to
647  // discard the attachment when we are done. If not using
648  // EXT_multisampled_render_to_texture but still using MSAA we discard the
649  // attachment as normal.
650  if (color0.resolve_texture) {
651  pass_data->discard_color_attachment =
652  pass_data->discard_color_attachment &&
653  !context.GetCapabilities()->SupportsImplicitResolvingMSAA();
654  }
655 
656  //----------------------------------------------------------------------------
657  /// Setup depth data.
658  ///
659  if (depth0.has_value()) {
660  pass_data->depth_attachment = depth0->texture;
661  pass_data->clear_depth = depth0->clear_depth;
662  pass_data->clear_depth_attachment = CanClearAttachment(depth0->load_action);
663  pass_data->discard_depth_attachment =
664  CanDiscardAttachmentWhenDone(depth0->store_action);
665  }
666 
667  //----------------------------------------------------------------------------
668  /// Setup stencil data.
669  ///
670  if (stencil0.has_value()) {
671  pass_data->stencil_attachment = stencil0->texture;
672  pass_data->clear_stencil = stencil0->clear_stencil;
673  pass_data->clear_stencil_attachment =
674  CanClearAttachment(stencil0->load_action);
675  pass_data->discard_stencil_attachment =
676  CanDiscardAttachmentWhenDone(stencil0->store_action);
677  }
678 
679  return reactor_->AddOperation(
680  [pass_data = std::move(pass_data), render_pass = shared_from_this(),
681  tracer =
682  ContextGLES::Cast(context).GetGPUTracer()](const auto& reactor) {
683  auto result = EncodeCommandsInReactor(
684  /*pass_data=*/*pass_data, //
685  /*reactor=*/reactor, //
686  /*commands=*/render_pass->commands_, //
687  /*vertex_buffers=*/render_pass->vertex_buffers_, //
688  /*bound_textures=*/render_pass->bound_textures_, //
689  /*bound_buffers=*/render_pass->bound_buffers_, //
690  /*tracer=*/tracer, //
691  /*impeller_context=*/render_pass->context_);
692  FML_CHECK(result)
693  << "Must be able to encode GL commands without error.";
694  },
695  /*defer=*/true);
696 }
697 
698 } // namespace impeller
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
void PushDebugGroup(const std::string &string) const
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
Definition: reactor_gles.h:57
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.
void SetCachedFBO(HandleGLES fbo)
bool SetAsFramebufferAttachment(GLenum target, AttachmentType attachment_type) const
std::optional< GLuint > GetFBO() const
bool IsWrapped() const
bool EncodeCommandsInReactor(const RenderPassData &pass_data, const ReactorGLES &reactor, const std::vector< Command > &commands, const std::vector< BufferView > &vertex_buffers, const std::vector< TextureAndSampler > &bound_textures, const std::vector< BufferResource > &bound_buffers, const std::shared_ptr< GPUTracerGLES > &tracer, const std::shared_ptr< const Context > &impeller_context)
constexpr bool CanClearAttachment(LoadAction action)
Definition: formats.h:242
float Scalar
Definition: scalar.h:19
constexpr GLenum ToIndexType(IndexType type)
Definition: formats_gles.h:35
constexpr GLenum ToCompareFunction(CompareFunction func)
Definition: formats_gles.h:70
std::string DebugToFramebufferError(int status)
Definition: formats_gles.cc:9
constexpr GLenum ToStencilOp(StencilOperation op)
Definition: formats_gles.h:48
constexpr GLenum ToMode(PrimitiveType primitive_type)
Definition: formats_gles.h:17
WindingOrder
Definition: formats.h:22
void ConfigureBlending(const ProcTableGLES &gl, const ColorAttachmentDescriptor *color)
void ConfigureStencil(const ProcTableGLES &gl, const PipelineDescriptor &pipeline, uint32_t stencil_reference)
static bool BindVertexBuffer(const ProcTableGLES &gl, BufferBindingsGLES *vertex_desc_gles, const BufferView &vertex_buffer_view, size_t buffer_index)
constexpr GLenum ToBlendFactor(BlendFactor factor)
Definition: formats_gles.h:92
constexpr GLenum ToBlendOperation(BlendOperation op)
Definition: formats_gles.h:128
constexpr bool CanDiscardAttachmentWhenDone(StoreAction action)
Definition: formats.h:253
Definition: comparable.h:95
Range GetRange() const
Definition: buffer_view.h:27
const DeviceBuffer * GetBuffer() const
Definition: buffer_view.cc:17
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
StencilOperation depth_stencil_pass
Definition: formats.h:633
Type height
Definition: size.h:29
#define VALIDATION_LOG
Definition: validation.h:91