9 #include "flutter/fml/trace_event.h"
10 #include "fml/closure.h"
11 #include "fml/logging.h"
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()) {}
34 RenderPassGLES::~RenderPassGLES() =
default;
37 bool RenderPassGLES::IsValid()
const {
42 void RenderPassGLES::OnSetLabel(std::string_view label) {
56 gl.BlendEquationSeparate(
67 return (mask & check) ? GL_TRUE : GL_FALSE;
71 is_set(color->
write_mask, ColorWriteMaskBits::kRed),
72 is_set(color->
write_mask, ColorWriteMaskBits::kGreen),
73 is_set(color->
write_mask, ColorWriteMaskBits::kBlue),
74 is_set(color->
write_mask, ColorWriteMaskBits::kAlpha)
82 uint32_t stencil_reference) {
89 gl.StencilFuncSeparate(face,
94 gl.StencilMaskSeparate(face, stencil.
write_mask);
99 uint32_t stencil_reference) {
101 gl.Disable(GL_STENCIL_TEST);
105 gl.Enable(GL_STENCIL_TEST);
109 if (front.has_value() && back.has_value() && front == back) {
113 if (front.has_value()) {
116 if (back.has_value()) {
129 uint32_t clear_stencil = 0u;
137 bool clear_color_attachment =
true;
138 bool clear_depth_attachment =
true;
139 bool clear_stencil_attachment =
true;
141 bool discard_color_attachment =
true;
142 bool discard_depth_attachment =
true;
143 bool discard_stencil_attachment =
true;
151 size_t buffer_index) {
152 if (!vertex_buffer_view) {
158 if (!vertex_buffer) {
162 const auto& vertex_buffer_gles = DeviceBufferGLES::Cast(*vertex_buffer);
163 if (!vertex_buffer_gles.BindAndUploadDataIfNecessary(
164 DeviceBufferGLES::BindingType::kArrayBuffer)) {
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);
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");
204 #ifdef IMPELLER_DEBUG
205 tracer->MarkFrameStart(gl);
207 fml::ScopedCleanupClosure pop_pass_debug_marker(
208 [&gl]() { gl.PopDebugGroup(); });
209 if (!pass_data.
label.empty()) {
212 pop_pass_debug_marker.Release();
217 const bool is_wrapped_fbo = color_gles.
IsWrapped();
219 std::optional<GLuint> fbo = 0;
220 if (is_wrapped_fbo) {
221 if (color_gles.
GetFBO().has_value()) {
223 gl.BindFramebuffer(GL_FRAMEBUFFER, *color_gles.
GetFBO());
229 if (!fbo.has_value()) {
232 gl.BindFramebuffer(GL_FRAMEBUFFER, fbo.value());
238 if (!fbo.has_value()) {
241 gl.BindFramebuffer(GL_FRAMEBUFFER, fbo.value());
244 GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) {
249 if (!depth->SetAsFramebufferAttachment(
250 GL_FRAMEBUFFER, TextureGLES::AttachmentType::kDepth)) {
256 if (!stencil->SetAsFramebufferAttachment(
257 GL_FRAMEBUFFER, TextureGLES::AttachmentType::kStencil)) {
262 auto status = gl.CheckFramebufferStatusDebug(GL_FRAMEBUFFER);
263 if (status != GL_FRAMEBUFFER_COMPLETE) {
277 if (gl.DepthRangef.IsAvailable()) {
287 GLenum clear_bits = 0u;
289 clear_bits |= GL_COLOR_BUFFER_BIT;
292 clear_bits |= GL_DEPTH_BUFFER_BIT;
295 clear_bits |= GL_STENCIL_BUFFER_BIT;
298 RenderPassGLES::ResetGLState(gl);
300 gl.Clear(clear_bits);
310 const auto& viewport = pass_data.
viewport;
311 gl.Viewport(viewport.rect.GetX(),
312 target_size.
height - viewport.rect.GetY() -
313 viewport.rect.GetHeight(),
314 viewport.rect.GetWidth(),
315 viewport.rect.GetHeight()
318 if (gl.DepthRangef.IsAvailable()) {
319 gl.DepthRangef(viewport.depth_range.z_near, viewport.depth_range.z_far);
321 gl.DepthRange(viewport.depth_range.z_near, viewport.depth_range.z_far);
325 CullMode current_cull_mode = CullMode::kNone;
326 WindingOrder current_winding_order = WindingOrder::kClockwise;
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);
336 pop_cmd_debug_marker.Release();
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.";
364 pipeline.GetDescriptor().GetDepthStencilAttachmentDescriptor();
366 gl.Enable(GL_DEPTH_TEST);
368 gl.DepthMask(depth->depth_write_enabled ? GL_TRUE : GL_FALSE);
370 gl.Disable(GL_DEPTH_TEST);
376 if (command.viewport.has_value()) {
377 gl.Viewport(viewport.rect.GetX(),
378 target_size.
height - viewport.rect.GetY() -
379 viewport.rect.GetHeight(),
380 viewport.rect.GetWidth(),
381 viewport.rect.GetHeight()
384 if (gl.DepthRangef.IsAvailable()) {
385 gl.DepthRangef(viewport.depth_range.z_near,
386 viewport.depth_range.z_far);
388 gl.DepthRange(viewport.depth_range.z_near,
389 viewport.depth_range.z_far);
397 if (command.scissor.has_value()) {
398 const auto& scissor = command.scissor.value();
399 gl.Enable(GL_SCISSOR_TEST);
402 target_size.
height - scissor.GetY() - scissor.GetHeight(),
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);
417 case CullMode::kFrontFace:
418 gl.Enable(GL_CULL_FACE);
419 gl.CullFace(GL_FRONT);
421 case CullMode::kBackFace:
422 gl.Enable(GL_CULL_FACE);
423 gl.CullFace(GL_BACK);
426 current_cull_mode = pipeline_cull_mode;
433 pipeline.GetDescriptor().GetWindingOrder();
434 if (current_winding_order != pipeline_winding_order) {
435 switch (pipeline.GetDescriptor().GetWindingOrder()) {
436 case WindingOrder::kClockwise:
439 case WindingOrder::kCounterClockwise:
440 gl.FrontFace(GL_CCW);
443 current_winding_order = pipeline_winding_order;
455 for (
size_t i = 0; i < command.vertex_buffers.length; i++) {
457 vertex_buffers[i + command.vertex_buffers.offset],
466 if (!pipeline.BindProgram()) {
477 command.bound_textures,
478 command.bound_buffers
492 pipeline.GetDescriptor().GetPolygonMode() == PolygonMode::kLine
494 :
ToMode(pipeline.GetDescriptor().GetPrimitiveType());
499 if (command.index_type == IndexType::kNone) {
500 gl.DrawArrays(mode, command.base_vertex, command.element_count);
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)) {
510 gl.DrawElements(mode,
511 command.element_count,
513 reinterpret_cast<const GLvoid*
>(
static_cast<GLsizei
>(
514 index_buffer_view.GetRange().offset))
527 !gl.GetCapabilities()->SupportsImplicitResolvingMSAA() &&
533 gl.GenFramebuffers(1u, &resolve_fbo);
534 gl.BindFramebuffer(GL_FRAMEBUFFER, resolve_fbo);
537 .SetAsFramebufferAttachment(
538 GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) {
542 auto status = gl.CheckFramebufferStatusDebug(GL_FRAMEBUFFER);
543 if (status != GL_FRAMEBUFFER_COMPLETE) {
550 gl.BindFramebuffer(GL_READ_FRAMEBUFFER, fbo.value());
551 gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo);
553 RenderPassGLES::ResetGLState(gl);
556 gl.BlitFramebuffer(0,
567 gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, GL_NONE);
568 gl.BindFramebuffer(GL_READ_FRAMEBUFFER, GL_NONE);
569 gl.DeleteFramebuffers(1u, &resolve_fbo);
571 gl.BindFramebuffer(GL_FRAMEBUFFER, fbo.value());
574 GLint framebuffer_id = 0;
575 gl.GetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer_id);
576 const bool is_default_fbo = framebuffer_id == 0;
578 if (gl.DiscardFramebufferEXT.IsAvailable()) {
579 std::array<GLenum, 3> attachments;
580 size_t attachment_count = 0;
585 bool angle_safe = gl.GetCapabilities()->IsANGLE() ? !is_default_fbo :
true;
588 attachments[attachment_count++] =
589 (is_default_fbo ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0);
593 attachments[attachment_count++] =
594 (is_default_fbo ? GL_DEPTH_EXT : GL_DEPTH_ATTACHMENT);
598 attachments[attachment_count++] =
599 (is_default_fbo ? GL_STENCIL_EXT : GL_STENCIL_ATTACHMENT);
601 gl.DiscardFramebufferEXT(GL_FRAMEBUFFER,
607 #ifdef IMPELLER_DEBUG
608 if (is_default_fbo) {
609 tracer->MarkFrameEnd(gl);
617 bool RenderPassGLES::OnEncodeCommands(
const Context& context)
const {
621 const auto& render_target = GetRenderTarget();
622 if (!render_target.HasColorAttachment(0u)) {
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();
631 auto pass_data = std::make_shared<RenderPassData>();
632 pass_data->label = label_;
633 pass_data->viewport.rect = Rect::MakeSize(GetRenderTargetSize());
638 pass_data->color_attachment = color0.texture;
639 pass_data->resolve_attachment = color0.resolve_texture;
640 pass_data->clear_color = color0.clear_color;
642 pass_data->discard_color_attachment =
650 if (color0.resolve_texture) {
651 pass_data->discard_color_attachment =
652 pass_data->discard_color_attachment &&
653 !context.GetCapabilities()->SupportsImplicitResolvingMSAA();
659 if (depth0.has_value()) {
660 pass_data->depth_attachment = depth0->texture;
661 pass_data->clear_depth = depth0->clear_depth;
663 pass_data->discard_depth_attachment =
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 =
675 pass_data->discard_stencil_attachment =
679 return reactor_->AddOperation(
680 [pass_data = std::move(pass_data), render_pass = shared_from_this(),
682 ContextGLES::Cast(context).GetGPUTracer()](
const auto& reactor) {
686 render_pass->commands_,
687 render_pass->vertex_buffers_,
688 render_pass->bound_textures_,
689 render_pass->bound_buffers_,
691 render_pass->context_);
693 <<
"Must be able to encode GL commands without error.";
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...
constexpr bool IsDead() const
Determines if the handle is dead.
std::optional< StencilAttachmentDescriptor > GetBackStencilAttachmentDescriptor() const
std::optional< StencilAttachmentDescriptor > GetFrontStencilAttachmentDescriptor() const
bool HasStencilAttachmentDescriptors() const
void PushDebugGroup(const std::string &string) 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.
void SetCachedFBO(HandleGLES fbo)
bool SetAsFramebufferAttachment(GLenum target, AttachmentType attachment_type) const
std::optional< GLuint > GetFBO() 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)
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)
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)
constexpr GLenum ToBlendOperation(BlendOperation op)
constexpr bool CanDiscardAttachmentWhenDone(StoreAction action)
const DeviceBuffer * GetBuffer() const
Describe the color attachment that will be used with this pipeline.
BlendOperation color_blend_op
BlendFactor dst_color_blend_factor
ColorWriteMask write_mask
BlendFactor src_alpha_blend_factor
BlendOperation alpha_blend_op
BlendFactor src_color_blend_factor
BlendFactor dst_alpha_blend_factor
Encapsulates data that will be needed in the reactor for the encoding of commands for this render pas...
bool clear_color_attachment
std::shared_ptr< Texture > depth_attachment
bool discard_color_attachment
bool clear_stencil_attachment
std::shared_ptr< Texture > color_attachment
bool discard_depth_attachment
std::shared_ptr< Texture > stencil_attachment
bool discard_stencil_attachment
std::shared_ptr< Texture > resolve_attachment
bool clear_depth_attachment
StencilOperation stencil_failure
CompareFunction stencil_compare
StencilOperation depth_failure
StencilOperation depth_stencil_pass