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> depth_attachment;
134  std::shared_ptr<Texture> stencil_attachment;
135 
136  bool clear_color_attachment = true;
137  bool clear_depth_attachment = true;
138  bool clear_stencil_attachment = true;
139 
140  bool discard_color_attachment = true;
141  bool discard_depth_attachment = true;
142  bool discard_stencil_attachment = true;
143 
144  std::string label;
145 };
146 
147 static bool BindVertexBuffer(const ProcTableGLES& gl,
148  BufferBindingsGLES* vertex_desc_gles,
149  const BufferView& vertex_buffer_view,
150  size_t buffer_index) {
151  if (!vertex_buffer_view) {
152  return false;
153  }
154 
155  const DeviceBuffer* vertex_buffer = vertex_buffer_view.GetBuffer();
156 
157  if (!vertex_buffer) {
158  return false;
159  }
160 
161  const auto& vertex_buffer_gles = DeviceBufferGLES::Cast(*vertex_buffer);
162  if (!vertex_buffer_gles.BindAndUploadDataIfNecessary(
163  DeviceBufferGLES::BindingType::kArrayBuffer)) {
164  return false;
165  }
166 
167  //--------------------------------------------------------------------------
168  /// Bind the vertex attributes associated with vertex buffer.
169  ///
170  if (!vertex_desc_gles->BindVertexAttributes(
171  gl, buffer_index, vertex_buffer_view.GetRange().offset)) {
172  return false;
173  }
174 
175  return true;
176 }
177 
178 void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) {
179  gl.Disable(GL_SCISSOR_TEST);
180  gl.Disable(GL_DEPTH_TEST);
181  gl.Disable(GL_STENCIL_TEST);
182  gl.Disable(GL_CULL_FACE);
183  gl.Disable(GL_BLEND);
184  gl.Disable(GL_DITHER);
185  gl.ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
186  gl.DepthMask(GL_TRUE);
187  gl.StencilMaskSeparate(GL_FRONT, 0xFFFFFFFF);
188  gl.StencilMaskSeparate(GL_BACK, 0xFFFFFFFF);
189 }
190 
191 [[nodiscard]] bool EncodeCommandsInReactor(
192  const RenderPassData& pass_data,
193  const ReactorGLES& reactor,
194  const std::vector<Command>& commands,
195  const std::vector<BufferView>& vertex_buffers,
196  const std::vector<TextureAndSampler>& bound_textures,
197  const std::vector<BufferResource>& bound_buffers,
198  const std::shared_ptr<GPUTracerGLES>& tracer) {
199  TRACE_EVENT0("impeller", "RenderPassGLES::EncodeCommandsInReactor");
200 
201  const auto& gl = reactor.GetProcTable();
202 #ifdef IMPELLER_DEBUG
203  tracer->MarkFrameStart(gl);
204 
205  fml::ScopedCleanupClosure pop_pass_debug_marker(
206  [&gl]() { gl.PopDebugGroup(); });
207  if (!pass_data.label.empty()) {
208  gl.PushDebugGroup(pass_data.label);
209  } else {
210  pop_pass_debug_marker.Release();
211  }
212 #endif // IMPELLER_DEBUG
213 
214  GLuint fbo = GL_NONE;
215  TextureGLES& color_gles = TextureGLES::Cast(*pass_data.color_attachment);
216  const bool is_default_fbo = color_gles.IsWrapped();
217 
218  if (is_default_fbo) {
219  if (color_gles.GetFBO().has_value()) {
220  // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
221  gl.BindFramebuffer(GL_FRAMEBUFFER, *color_gles.GetFBO());
222  }
223  } else {
224  // Create and bind an offscreen FBO.
225  GLuint cached_fbo = color_gles.GetCachedFBO();
226  if (cached_fbo != GL_NONE) {
227  fbo = cached_fbo;
228  gl.BindFramebuffer(GL_FRAMEBUFFER, fbo);
229  } else {
230  gl.GenFramebuffers(1u, &fbo);
231  color_gles.SetCachedFBO(fbo);
232  gl.BindFramebuffer(GL_FRAMEBUFFER, fbo);
233 
234  if (!color_gles.SetAsFramebufferAttachment(
235  GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) {
236  return false;
237  }
238 
239  if (auto depth = TextureGLES::Cast(pass_data.depth_attachment.get())) {
240  if (!depth->SetAsFramebufferAttachment(
241  GL_FRAMEBUFFER, TextureGLES::AttachmentType::kDepth)) {
242  return false;
243  }
244  }
245  if (auto stencil =
246  TextureGLES::Cast(pass_data.stencil_attachment.get())) {
247  if (!stencil->SetAsFramebufferAttachment(
248  GL_FRAMEBUFFER, TextureGLES::AttachmentType::kStencil)) {
249  return false;
250  }
251  }
252 
253  auto status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER);
254  if (status != GL_FRAMEBUFFER_COMPLETE) {
255  VALIDATION_LOG << "Could not create a complete frambuffer: "
256  << DebugToFramebufferError(status);
257  return false;
258  }
259  }
260  }
261 
262  gl.ClearColor(pass_data.clear_color.red, // red
263  pass_data.clear_color.green, // green
264  pass_data.clear_color.blue, // blue
265  pass_data.clear_color.alpha // alpha
266  );
267  if (pass_data.depth_attachment) {
268  if (gl.DepthRangef.IsAvailable()) {
269  gl.ClearDepthf(pass_data.clear_depth);
270  } else {
271  gl.ClearDepth(pass_data.clear_depth);
272  }
273  }
274  if (pass_data.stencil_attachment) {
275  gl.ClearStencil(pass_data.clear_stencil);
276  }
277 
278  GLenum clear_bits = 0u;
279  if (pass_data.clear_color_attachment) {
280  clear_bits |= GL_COLOR_BUFFER_BIT;
281  }
282  if (pass_data.clear_depth_attachment) {
283  clear_bits |= GL_DEPTH_BUFFER_BIT;
284  }
285  if (pass_data.clear_stencil_attachment) {
286  clear_bits |= GL_STENCIL_BUFFER_BIT;
287  }
288 
289  RenderPassGLES::ResetGLState(gl);
290 
291  gl.Clear(clear_bits);
292 
293  // Both the viewport and scissor are specified in framebuffer coordinates.
294  // Impeller's framebuffer coordinate system is top left origin, but OpenGL's
295  // is bottom left origin, so we convert the coordinates here.
296  ISize target_size = pass_data.color_attachment->GetSize();
297 
298  //--------------------------------------------------------------------------
299  /// Setup the viewport.
300  ///
301  const auto& viewport = pass_data.viewport;
302  gl.Viewport(viewport.rect.GetX(), // x
303  target_size.height - viewport.rect.GetY() -
304  viewport.rect.GetHeight(), // y
305  viewport.rect.GetWidth(), // width
306  viewport.rect.GetHeight() // height
307  );
308  if (pass_data.depth_attachment) {
309  if (gl.DepthRangef.IsAvailable()) {
310  gl.DepthRangef(viewport.depth_range.z_near, viewport.depth_range.z_far);
311  } else {
312  gl.DepthRange(viewport.depth_range.z_near, viewport.depth_range.z_far);
313  }
314  }
315 
316  CullMode current_cull_mode = CullMode::kNone;
317  WindingOrder current_winding_order = WindingOrder::kClockwise;
318  gl.FrontFace(GL_CW);
319 
320  for (const auto& command : commands) {
321 #ifdef IMPELLER_DEBUG
322  fml::ScopedCleanupClosure pop_cmd_debug_marker(
323  [&gl]() { gl.PopDebugGroup(); });
324  if (!command.label.empty()) {
325  gl.PushDebugGroup(command.label);
326  } else {
327  pop_cmd_debug_marker.Release();
328  }
329 #endif // IMPELLER_DEBUG
330 
331  const auto& pipeline = PipelineGLES::Cast(*command.pipeline);
332 
333  const auto* color_attachment =
334  pipeline.GetDescriptor().GetLegacyCompatibleColorAttachment();
335  if (!color_attachment) {
337  << "Color attachment is too complicated for a legacy renderer.";
338  return false;
339  }
340 
341  //--------------------------------------------------------------------------
342  /// Configure blending.
343  ///
344  ConfigureBlending(gl, color_attachment);
345 
346  //--------------------------------------------------------------------------
347  /// Setup stencil.
348  ///
349  ConfigureStencil(gl, pipeline.GetDescriptor(), command.stencil_reference);
350 
351  //--------------------------------------------------------------------------
352  /// Configure depth.
353  ///
354  if (auto depth =
355  pipeline.GetDescriptor().GetDepthStencilAttachmentDescriptor();
356  depth.has_value()) {
357  gl.Enable(GL_DEPTH_TEST);
358  gl.DepthFunc(ToCompareFunction(depth->depth_compare));
359  gl.DepthMask(depth->depth_write_enabled ? GL_TRUE : GL_FALSE);
360  } else {
361  gl.Disable(GL_DEPTH_TEST);
362  }
363 
364  //--------------------------------------------------------------------------
365  /// Setup the viewport.
366  ///
367  if (command.viewport.has_value()) {
368  gl.Viewport(viewport.rect.GetX(), // x
369  target_size.height - viewport.rect.GetY() -
370  viewport.rect.GetHeight(), // y
371  viewport.rect.GetWidth(), // width
372  viewport.rect.GetHeight() // height
373  );
374  if (pass_data.depth_attachment) {
375  if (gl.DepthRangef.IsAvailable()) {
376  gl.DepthRangef(viewport.depth_range.z_near,
377  viewport.depth_range.z_far);
378  } else {
379  gl.DepthRange(viewport.depth_range.z_near,
380  viewport.depth_range.z_far);
381  }
382  }
383  }
384 
385  //--------------------------------------------------------------------------
386  /// Setup the scissor rect.
387  ///
388  if (command.scissor.has_value()) {
389  const auto& scissor = command.scissor.value();
390  gl.Enable(GL_SCISSOR_TEST);
391  gl.Scissor(
392  scissor.GetX(), // x
393  target_size.height - scissor.GetY() - scissor.GetHeight(), // y
394  scissor.GetWidth(), // width
395  scissor.GetHeight() // height
396  );
397  }
398 
399  //--------------------------------------------------------------------------
400  /// Setup culling.
401  ///
402  CullMode pipeline_cull_mode = pipeline.GetDescriptor().GetCullMode();
403  if (current_cull_mode != pipeline_cull_mode) {
404  switch (pipeline_cull_mode) {
405  case CullMode::kNone:
406  gl.Disable(GL_CULL_FACE);
407  break;
408  case CullMode::kFrontFace:
409  gl.Enable(GL_CULL_FACE);
410  gl.CullFace(GL_FRONT);
411  break;
412  case CullMode::kBackFace:
413  gl.Enable(GL_CULL_FACE);
414  gl.CullFace(GL_BACK);
415  break;
416  }
417  current_cull_mode = pipeline_cull_mode;
418  }
419 
420  //--------------------------------------------------------------------------
421  /// Setup winding order.
422  ///
423  WindingOrder pipeline_winding_order =
424  pipeline.GetDescriptor().GetWindingOrder();
425  if (current_winding_order != pipeline_winding_order) {
426  switch (pipeline.GetDescriptor().GetWindingOrder()) {
427  case WindingOrder::kClockwise:
428  gl.FrontFace(GL_CW);
429  break;
430  case WindingOrder::kCounterClockwise:
431  gl.FrontFace(GL_CCW);
432  break;
433  }
434  current_winding_order = pipeline_winding_order;
435  }
436 
437  BufferBindingsGLES* vertex_desc_gles = pipeline.GetBufferBindings();
438 
439  //--------------------------------------------------------------------------
440  /// Bind vertex buffers.
441  ///
442  /// Note: There is no need to run `RenderPass::ValidateVertexBuffers` or
443  /// `RenderPass::ValidateIndexBuffer` here, as validation already runs
444  /// when the vertex/index buffers are set on the command.
445  ///
446  for (size_t i = 0; i < command.vertex_buffers.length; i++) {
447  if (!BindVertexBuffer(gl, vertex_desc_gles,
448  vertex_buffers[i + command.vertex_buffers.offset],
449  i)) {
450  return false;
451  }
452  }
453 
454  //--------------------------------------------------------------------------
455  /// Bind the pipeline program.
456  ///
457  if (!pipeline.BindProgram()) {
458  return false;
459  }
460 
461  //--------------------------------------------------------------------------
462  /// Bind uniform data.
463  ///
464  if (!vertex_desc_gles->BindUniformData(
465  gl, //
466  bound_textures, //
467  bound_buffers, //
468  /*texture_range=*/command.bound_textures, //
469  /*buffer_range=*/command.bound_buffers //
470  )) {
471  return false;
472  }
473 
474  //--------------------------------------------------------------------------
475  /// Determine the primitive type.
476  ///
477  // GLES doesn't support setting the fill mode, so override the primitive
478  // with GL_LINE_STRIP to somewhat emulate PolygonMode::kLine. This isn't
479  // correct; full triangle outlines won't be drawn and disconnected
480  // geometry may appear connected. However this can still be useful for
481  // wireframe debug views.
482  GLenum mode =
483  pipeline.GetDescriptor().GetPolygonMode() == PolygonMode::kLine
484  ? GL_LINE_STRIP
485  : ToMode(pipeline.GetDescriptor().GetPrimitiveType());
486 
487  //--------------------------------------------------------------------------
488  /// Finally! Invoke the draw call.
489  ///
490  if (command.index_type == IndexType::kNone) {
491  gl.DrawArrays(mode, command.base_vertex, command.element_count);
492  } else {
493  // Bind the index buffer if necessary.
494  auto index_buffer_view = command.index_buffer;
495  const DeviceBuffer* index_buffer = index_buffer_view.GetBuffer();
496  const auto& index_buffer_gles = DeviceBufferGLES::Cast(*index_buffer);
497  if (!index_buffer_gles.BindAndUploadDataIfNecessary(
498  DeviceBufferGLES::BindingType::kElementArrayBuffer)) {
499  return false;
500  }
501  gl.DrawElements(mode, // mode
502  command.element_count, // count
503  ToIndexType(command.index_type), // type
504  reinterpret_cast<const GLvoid*>(static_cast<GLsizei>(
505  index_buffer_view.GetRange().offset)) // indices
506  );
507  }
508 
509  //--------------------------------------------------------------------------
510  /// Unbind vertex attribs.
511  ///
512  if (!vertex_desc_gles->UnbindVertexAttributes(gl)) {
513  return false;
514  }
515  }
516 
517  if (gl.DiscardFramebufferEXT.IsAvailable()) {
518  std::array<GLenum, 3> attachments;
519  size_t attachment_count = 0;
520 
521  // TODO(130048): discarding stencil or depth on the default fbo causes Angle
522  // to discard the entire render target. Until we know the reason, default to
523  // storing.
524  bool angle_safe = gl.GetCapabilities()->IsANGLE() ? !is_default_fbo : true;
525 
526  if (pass_data.discard_color_attachment) {
527  attachments[attachment_count++] =
528  (is_default_fbo ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0);
529  }
530  if (pass_data.discard_depth_attachment && angle_safe) {
531  attachments[attachment_count++] =
532  (is_default_fbo ? GL_DEPTH_EXT : GL_DEPTH_ATTACHMENT);
533  }
534 
535  if (pass_data.discard_stencil_attachment && angle_safe) {
536  attachments[attachment_count++] =
537  (is_default_fbo ? GL_STENCIL_EXT : GL_STENCIL_ATTACHMENT);
538  }
539  gl.DiscardFramebufferEXT(GL_FRAMEBUFFER, // target
540  attachment_count, // attachments to discard
541  attachments.data() // size
542  );
543  }
544 
545 #ifdef IMPELLER_DEBUG
546  if (is_default_fbo) {
547  tracer->MarkFrameEnd(gl);
548  }
549 #endif // IMPELLER_DEBUG
550 
551  return true;
552 }
553 
554 // |RenderPass|
555 bool RenderPassGLES::OnEncodeCommands(const Context& context) const {
556  if (!IsValid()) {
557  return false;
558  }
559  const auto& render_target = GetRenderTarget();
560  if (!render_target.HasColorAttachment(0u)) {
561  return false;
562  }
563  const ColorAttachment& color0 = render_target.GetColorAttachment(0);
564  const std::optional<DepthAttachment>& depth0 =
565  render_target.GetDepthAttachment();
566  const std::optional<StencilAttachment>& stencil0 =
567  render_target.GetStencilAttachment();
568 
569  auto pass_data = std::make_shared<RenderPassData>();
570  pass_data->label = label_;
571  pass_data->viewport.rect = Rect::MakeSize(GetRenderTargetSize());
572 
573  //----------------------------------------------------------------------------
574  /// Setup color data.
575  ///
576  pass_data->color_attachment = color0.texture;
577  pass_data->clear_color = color0.clear_color;
578  pass_data->clear_color_attachment = CanClearAttachment(color0.load_action);
579  pass_data->discard_color_attachment =
580  CanDiscardAttachmentWhenDone(color0.store_action);
581 
582  // When we are using EXT_multisampled_render_to_texture, it is implicitly
583  // resolved when we bind the texture to the framebuffer. We don't need to
584  // discard the attachment when we are done.
585  if (color0.resolve_texture) {
586  FML_DCHECK(context.GetCapabilities()->SupportsImplicitResolvingMSAA());
587  pass_data->discard_color_attachment = false;
588  }
589 
590  //----------------------------------------------------------------------------
591  /// Setup depth data.
592  ///
593  if (depth0.has_value()) {
594  pass_data->depth_attachment = depth0->texture;
595  pass_data->clear_depth = depth0->clear_depth;
596  pass_data->clear_depth_attachment = CanClearAttachment(depth0->load_action);
597  pass_data->discard_depth_attachment =
598  CanDiscardAttachmentWhenDone(depth0->store_action);
599  }
600 
601  //----------------------------------------------------------------------------
602  /// Setup stencil data.
603  ///
604  if (stencil0.has_value()) {
605  pass_data->stencil_attachment = stencil0->texture;
606  pass_data->clear_stencil = stencil0->clear_stencil;
607  pass_data->clear_stencil_attachment =
608  CanClearAttachment(stencil0->load_action);
609  pass_data->discard_stencil_attachment =
610  CanDiscardAttachmentWhenDone(stencil0->store_action);
611  }
612 
613  return reactor_->AddOperation(
614  [pass_data = std::move(pass_data), render_pass = shared_from_this(),
615  tracer =
616  ContextGLES::Cast(context).GetGPUTracer()](const auto& reactor) {
617  auto result = EncodeCommandsInReactor(
618  /*pass_data=*/*pass_data, //
619  /*reactor=*/reactor, //
620  /*commands=*/render_pass->commands_, //
621  /*vertex_buffers=*/render_pass->vertex_buffers_, //
622  /*bound_textures=*/render_pass->bound_textures_, //
623  /*bound_buffers=*/render_pass->bound_buffers_, //
624  /*tracer=*/tracer //
625  );
626  FML_CHECK(result)
627  << "Must be able to encode GL commands without error.";
628  },
629  /*defer=*/true);
630 }
631 
632 } // 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)
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
const ProcTableGLES & GetProcTable() const
Get the OpenGL proc. table the reactor uses to manage handles.
void SetCachedFBO(GLuint fbo)
GLuint GetCachedFBO() const
Retrieve the cached FBO object, or GL_NONE if there is no object.
bool SetAsFramebufferAttachment(GLenum target, AttachmentType attachment_type) const
std::optional< GLuint > GetFBO() const
bool IsWrapped() const
constexpr bool CanClearAttachment(LoadAction action)
Definition: formats.h:239
float Scalar
Definition: scalar.h:18
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
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)
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:250
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:518
Scalar blue
Definition: color.h:137
Scalar alpha
Definition: color.h:142
Scalar red
Definition: color.h:127
Scalar green
Definition: color.h:132
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
StencilOperation depth_stencil_pass
Definition: formats.h:629
Type height
Definition: size.h:29
#define VALIDATION_LOG
Definition: validation.h:91