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)
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) {
100 if (!
pipeline.HasStencilAttachmentDescriptors()) {
101 gl.Disable(GL_STENCIL_TEST);
105 gl.Enable(GL_STENCIL_TEST);
106 const auto& front =
pipeline.GetFrontStencilAttachmentDescriptor();
107 const auto& back =
pipeline.GetBackStencilAttachmentDescriptor();
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;
138 uint32_t color_mip_level = 0u;
139 uint32_t color_slice = 0u;
140 uint32_t depth_mip_level = 0u;
141 uint32_t depth_slice = 0u;
142 uint32_t stencil_mip_level = 0u;
143 uint32_t stencil_slice = 0u;
145 bool clear_color_attachment =
true;
146 bool clear_depth_attachment =
true;
147 bool clear_stencil_attachment =
true;
149 bool discard_color_attachment =
true;
150 bool discard_depth_attachment =
true;
151 bool discard_stencil_attachment =
true;
160 size_t instance = 0) {
161 if (!vertex_buffer_view) {
167 if (!vertex_buffer) {
171 const auto& vertex_buffer_gles = DeviceBufferGLES::Cast(*vertex_buffer);
172 if (!vertex_buffer_gles.BindAndUploadDataIfNecessary(
173 DeviceBufferGLES::BindingType::kArrayBuffer)) {
181 gl, buffer_index, vertex_buffer_view.
GetRange().
offset, instance)) {
189 gl.Disable(GL_SCISSOR_TEST);
190 gl.Disable(GL_DEPTH_TEST);
191 gl.Disable(GL_STENCIL_TEST);
192 gl.Disable(GL_CULL_FACE);
193 gl.Disable(GL_BLEND);
194 gl.Disable(GL_DITHER);
195 gl.ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
196 gl.DepthMask(GL_TRUE);
197 gl.StencilMaskSeparate(GL_FRONT, 0xFFFFFFFF);
198 gl.StencilMaskSeparate(GL_BACK, 0xFFFFFFFF);
203 const std::optional<Viewport>& command_viewport,
204 const ISize& target_size,
206 std::optional<Viewport>& current_viewport) {
207 auto new_viewport = command_viewport.value_or(pass_data.
viewport);
209 if (current_viewport.has_value() &&
210 current_viewport.value() == new_viewport) {
215 current_viewport = new_viewport;
219 const auto viewport_y_gl = flip_y ? new_viewport.rect.GetY()
221 new_viewport.rect.GetY() -
222 new_viewport.rect.GetHeight();
223 gl.Viewport(new_viewport.rect.GetX(),
225 new_viewport.rect.GetWidth(), new_viewport.rect.GetHeight());
227 if (gl.DepthRangef.IsAvailable()) {
228 gl.DepthRangef(new_viewport.depth_range.z_near,
229 new_viewport.depth_range.z_far);
231 gl.DepthRange(new_viewport.depth_range.z_near,
232 new_viewport.depth_range.z_far);
240 const std::vector<Command>& commands,
241 const std::vector<BufferView>& vertex_buffers,
242 const std::vector<TextureAndSampler>& bound_textures,
243 const std::vector<BufferResource>& bound_buffers,
244 const std::shared_ptr<GPUTracerGLES>& tracer,
245 const std::shared_ptr<const Context>& impeller_context) {
246 TRACE_EVENT0(
"impeller",
"RenderPassGLES::EncodeCommandsInReactor");
248 const auto& gl =
reactor.GetProcTable();
249 #ifdef IMPELLER_DEBUG
250 tracer->MarkFrameStart(gl);
252 fml::ScopedCleanupClosure pop_pass_debug_marker(
253 [&gl]() { gl.PopDebugGroup(); });
254 if (!pass_data.
label.empty()) {
255 gl.PushDebugGroup(pass_data.
label);
257 pop_pass_debug_marker.Release();
262 const bool is_wrapped_fbo = color_gles.
IsWrapped();
264 std::optional<GLuint> fbo = 0;
265 if (is_wrapped_fbo) {
266 if (color_gles.
GetFBO().has_value()) {
268 gl.BindFramebuffer(GL_FRAMEBUFFER, *color_gles.
GetFBO());
275 bool needs_attachment =
false;
278 reactor.CreateUntrackedHandle(HandleType::kFrameBuffer));
279 needs_attachment =
true;
282 if (!fbo.has_value()) {
285 gl.BindFramebuffer(GL_FRAMEBUFFER, fbo.value());
287 if (needs_attachment ||
291 GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0,
297 if (!depth->SetAsFramebufferAttachment(
298 GL_FRAMEBUFFER, TextureGLES::AttachmentType::kDepth,
305 if (!stencil->SetAsFramebufferAttachment(
306 GL_FRAMEBUFFER, TextureGLES::AttachmentType::kStencil,
312 auto status = gl.CheckFramebufferStatusDebug(GL_FRAMEBUFFER);
313 if (status != GL_FRAMEBUFFER_COMPLETE) {
329 if (gl.DepthRangef.IsAvailable()) {
339 GLenum clear_bits = 0u;
341 clear_bits |= GL_COLOR_BUFFER_BIT;
344 clear_bits |= GL_DEPTH_BUFFER_BIT;
347 clear_bits |= GL_STENCIL_BUFFER_BIT;
350 RenderPassGLES::ResetGLState(gl);
352 gl.Clear(clear_bits);
361 const bool flip_y = !is_wrapped_fbo;
362 const float y_flip_value = flip_y ? -1.0f : 1.0f;
364 std::optional<Viewport> current_viewport;
365 CullMode current_cull_mode = CullMode::kNone;
366 WindingOrder current_winding_order = WindingOrder::kClockwise;
368 gl.FrontFace(flip_y ? GL_CCW : GL_CW);
370 for (
const auto& command : commands) {
371 #ifdef IMPELLER_DEBUG
372 fml::ScopedCleanupClosure pop_cmd_debug_marker(
373 [&gl]() { gl.PopDebugGroup(); });
374 if (!command.label.empty()) {
375 gl.PushDebugGroup(command.label);
377 pop_cmd_debug_marker.Release();
380 const auto&
pipeline = PipelineGLES::Cast(*command.pipeline);
381 impeller_context->GetPipelineLibrary()->LogPipelineUsage(
383 const auto* color_attachment =
384 pipeline.GetDescriptor().GetLegacyCompatibleColorAttachment();
385 if (!color_attachment) {
387 <<
"Color attachment is too complicated for a legacy renderer.";
405 pipeline.GetDescriptor().GetDepthStencilAttachmentDescriptor();
407 gl.Enable(GL_DEPTH_TEST);
409 gl.DepthMask(depth->depth_write_enabled ? GL_TRUE : GL_FALSE);
411 gl.Disable(GL_DEPTH_TEST);
428 if (command.scissor.has_value()) {
429 const auto& scissor = command.scissor.value();
430 gl.Enable(GL_SCISSOR_TEST);
432 const auto scissor_y_gl =
433 flip_y ? scissor.GetY()
434 : target_size.
height - scissor.GetY() - scissor.GetHeight();
435 gl.Scissor(scissor.GetX(),
437 scissor.GetWidth(), scissor.GetHeight());
444 if (current_cull_mode != pipeline_cull_mode) {
445 switch (pipeline_cull_mode) {
446 case CullMode::kNone:
447 gl.Disable(GL_CULL_FACE);
449 case CullMode::kFrontFace:
450 gl.Enable(GL_CULL_FACE);
451 gl.CullFace(GL_FRONT);
453 case CullMode::kBackFace:
454 gl.Enable(GL_CULL_FACE);
455 gl.CullFace(GL_BACK);
458 current_cull_mode = pipeline_cull_mode;
466 pipeline.GetDescriptor().GetWindingOrder();
467 if (current_winding_order != pipeline_winding_order) {
468 switch (
pipeline.GetDescriptor().GetWindingOrder()) {
469 case WindingOrder::kClockwise:
470 gl.FrontFace(flip_y ? GL_CCW : GL_CW);
472 case WindingOrder::kCounterClockwise:
473 gl.FrontFace(flip_y ? GL_CW : GL_CCW);
476 current_winding_order = pipeline_winding_order;
488 for (
size_t i = 0; i < command.vertex_buffers.length; i++) {
490 vertex_buffers[i + command.vertex_buffers.offset],
505 const GLint y_flip_loc =
pipeline.GetYFlipUniformLocation();
506 if (y_flip_loc >= 0) {
507 gl.Uniform1fv(y_flip_loc, 1, &y_flip_value);
517 command.bound_textures,
518 command.bound_buffers
532 pipeline.GetDescriptor().GetPolygonMode() == PolygonMode::kLine
545 const bool instanced = command.instance_count > 1u;
546 const bool hardware_instanced =
548 (gl.DrawArraysInstanced.IsAvailable() ||
549 gl.DrawArraysInstancedEXT.IsAvailable()) &&
550 (gl.DrawElementsInstanced.IsAvailable() ||
551 gl.DrawElementsInstancedEXT.IsAvailable()) &&
552 (gl.VertexAttribDivisor.IsAvailable() ||
553 gl.VertexAttribDivisorEXT.IsAvailable());
554 const bool emulate_instanced = instanced && !hardware_instanced;
555 const GLsizei instance_count =
static_cast<GLsizei
>(command.instance_count);
561 const bool is_indexed = command.index_type != IndexType::kNone &&
562 command.index_type != IndexType::kUnknown;
565 const GLvoid* index_offset =
nullptr;
567 auto index_buffer_view = command.index_buffer;
568 const DeviceBuffer* index_buffer = index_buffer_view.GetBuffer();
569 const auto& index_buffer_gles = DeviceBufferGLES::Cast(*index_buffer);
570 if (!index_buffer_gles.BindAndUploadDataIfNecessary(
571 DeviceBufferGLES::BindingType::kElementArrayBuffer)) {
574 index_offset =
reinterpret_cast<const GLvoid*
>(
575 static_cast<uintptr_t
>(index_buffer_view.GetRange().offset));
580 const auto draw_geometry = [&]() {
582 gl.DrawArrays(mode, command.base_vertex, command.element_count);
584 gl.DrawElements(mode, command.element_count,
589 if (command.instance_count == 0u) {
592 }
else if (emulate_instanced) {
596 for (
size_t instance = 0; instance < command.instance_count; instance++) {
598 for (
size_t i = 0; i < command.vertex_buffers.length; i++) {
600 gl, vertex_desc_gles,
601 vertex_buffers[i + command.vertex_buffers.offset], i,
609 }
else if (hardware_instanced) {
612 const auto& gl_draw_arrays_instanced =
613 gl.DrawArraysInstanced.IsAvailable() ? gl.DrawArraysInstanced
614 : gl.DrawArraysInstancedEXT;
615 gl_draw_arrays_instanced(mode, command.base_vertex,
616 command.element_count, instance_count);
618 const auto& gl_draw_elements_instanced =
619 gl.DrawElementsInstanced.IsAvailable()
620 ? gl.DrawElementsInstanced
621 : gl.DrawElementsInstancedEXT;
622 gl_draw_elements_instanced(mode, command.element_count,
624 index_offset, instance_count);
639 !gl.GetCapabilities()->SupportsImplicitResolvingMSAA() &&
644 std::optional<GLuint> resolve_fbo_opt;
650 if (!resolve_fbo_opt.has_value()) {
652 reactor.CreateUntrackedHandle(HandleType::kFrameBuffer);
654 resolve_fbo_opt =
reactor.GetGLHandle(cached_fbo);
655 gl.BindFramebuffer(GL_FRAMEBUFFER, resolve_fbo_opt.value());
658 GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) {
662 auto status = gl.CheckFramebufferStatusDebug(GL_FRAMEBUFFER);
663 if (status != GL_FRAMEBUFFER_COMPLETE) {
669 gl.BindFramebuffer(GL_FRAMEBUFFER, resolve_fbo_opt.value());
673 gl.BindFramebuffer(GL_READ_FRAMEBUFFER, fbo.value());
674 gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo_opt.value());
676 RenderPassGLES::ResetGLState(gl);
679 gl.BlitFramebuffer(0,
690 gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, GL_NONE);
691 gl.BindFramebuffer(GL_READ_FRAMEBUFFER, GL_NONE);
693 gl.BindFramebuffer(GL_FRAMEBUFFER, fbo.value());
696 GLint framebuffer_id = 0;
697 gl.GetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer_id);
698 const bool is_default_fbo = framebuffer_id == 0;
700 if (gl.InvalidateFramebuffer.IsAvailable()) {
701 std::array<GLenum, 3> attachments;
702 size_t attachment_count = 0;
704 bool angle_safe = gl.GetCapabilities()->IsANGLE() ? !is_default_fbo :
true;
707 attachments[attachment_count++] =
708 (is_default_fbo ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0);
712 attachments[attachment_count++] =
713 (is_default_fbo ? GL_DEPTH_EXT : GL_DEPTH_ATTACHMENT);
717 attachments[attachment_count++] =
718 (is_default_fbo ? GL_STENCIL_EXT : GL_STENCIL_ATTACHMENT);
720 gl.InvalidateFramebuffer(GL_FRAMEBUFFER,
724 }
else if (gl.DiscardFramebufferEXT.IsAvailable()) {
725 std::array<GLenum, 3> attachments;
726 size_t attachment_count = 0;
731 bool angle_safe = gl.GetCapabilities()->IsANGLE() ? !is_default_fbo :
true;
734 attachments[attachment_count++] =
735 (is_default_fbo ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0);
739 attachments[attachment_count++] =
740 (is_default_fbo ? GL_DEPTH_EXT : GL_DEPTH_ATTACHMENT);
744 attachments[attachment_count++] =
745 (is_default_fbo ? GL_STENCIL_EXT : GL_STENCIL_ATTACHMENT);
747 gl.DiscardFramebufferEXT(GL_FRAMEBUFFER,
753 #ifdef IMPELLER_DEBUG
754 if (is_default_fbo) {
755 tracer->MarkFrameEnd(gl);
763 bool RenderPassGLES::OnEncodeCommands(
const Context&
context)
const {
767 const auto& render_target = GetRenderTarget();
768 if (!render_target.HasColorAttachment(0u)) {
771 const ColorAttachment& color0 = render_target.GetColorAttachment(0);
772 const std::optional<DepthAttachment>& depth0 =
773 render_target.GetDepthAttachment();
774 const std::optional<StencilAttachment>& stencil0 =
775 render_target.GetStencilAttachment();
777 auto pass_data = std::make_shared<RenderPassData>();
778 pass_data->label = label_;
779 pass_data->viewport.rect = Rect::MakeSize(GetRenderTargetSize());
784 pass_data->color_attachment = color0.texture;
785 pass_data->resolve_attachment = color0.resolve_texture;
786 pass_data->color_mip_level = color0.mip_level;
787 pass_data->color_slice = color0.slice;
788 pass_data->clear_color = color0.clear_color;
790 pass_data->discard_color_attachment =
798 if (color0.resolve_texture) {
799 pass_data->discard_color_attachment =
800 pass_data->discard_color_attachment &&
801 !
context.GetCapabilities()->SupportsImplicitResolvingMSAA();
807 if (depth0.has_value()) {
808 pass_data->depth_attachment = depth0->texture;
809 pass_data->depth_mip_level = depth0->mip_level;
810 pass_data->depth_slice = depth0->slice;
811 pass_data->clear_depth = depth0->clear_depth;
813 pass_data->discard_depth_attachment =
820 if (stencil0.has_value()) {
821 pass_data->stencil_attachment = stencil0->texture;
822 pass_data->stencil_mip_level = stencil0->mip_level;
823 pass_data->stencil_slice = stencil0->slice;
824 pass_data->clear_stencil = stencil0->clear_stencil;
825 pass_data->clear_stencil_attachment =
827 pass_data->discard_stencil_attachment =
831 return reactor_->AddOperation(
832 [pass_data = std::move(pass_data),
render_pass = shared_from_this(),
845 <<
"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, size_t instance=0)
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.
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
const HandleGLES & GetCachedFBO() const
Retrieve the cached FBO object, or a dead handle if there is no object.
bool CachedFBOMatchesSubresource(uint32_t mip_level, uint32_t slice) const
void SetCachedFBOSubresource(uint32_t mip_level, uint32_t slice)
Records the subresource the cached FBO is currently bound to.
void SetCachedFBO(HandleGLES fbo)
bool SetAsFramebufferAttachment(GLenum target, AttachmentType attachment_type, uint32_t mip_level=0, uint32_t slice=0)
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)
static void EncodeViewport(const ProcTableGLES &gl, const RenderPassData &pass_data, const std::optional< Viewport > &command_viewport, const ISize &target_size, bool flip_y, std::optional< Viewport > ¤t_viewport)
constexpr GLenum ToCompareFunction(CompareFunction func)
std::string DebugToFramebufferError(int status)
constexpr GLenum ToStencilOp(StencilOperation op)
constexpr GLenum ToMode(PrimitiveType primitive_type)
static bool BindVertexBuffer(const ProcTableGLES &gl, BufferBindingsGLES *vertex_desc_gles, const BufferView &vertex_buffer_view, size_t buffer_index, size_t instance=0)
void ConfigureBlending(const ProcTableGLES &gl, const ColorAttachmentDescriptor *color)
void ConfigureStencil(const ProcTableGLES &gl, const PipelineDescriptor &pipeline, uint32_t stencil_reference)
constexpr GLenum ToBlendFactor(BlendFactor factor)
constexpr GLenum ToBlendOperation(BlendOperation op)
constexpr bool CanDiscardAttachmentWhenDone(StoreAction action)
std::shared_ptr< ReactorGLES > reactor
std::shared_ptr< ContextGLES > context
std::shared_ptr< RenderPass > render_pass
std::shared_ptr< PipelineGLES > pipeline
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
uint32_t stencil_mip_level
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