From 251c975002061c63699ec6ada85887014f9548b6 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Mon, 9 Dec 2024 15:31:16 -0800 Subject: [PATCH 1/3] [Impeller] add GLES renderpass that avoids command encoding. --- impeller/renderer/backend/gles/BUILD.gn | 2 + .../backend/gles/buffer_bindings_gles.cc | 6 +- .../backend/gles/buffer_bindings_gles.h | 15 +- .../gles/buffer_bindings_gles_unittests.cc | 6 +- .../backend/gles/command_buffer_gles.cc | 11 + .../renderer/backend/gles/context_gles.cc | 1 + impeller/renderer/backend/gles/context_gles.h | 10 + .../backend/gles/device_buffer_gles.cc | 14 +- .../renderer/backend/gles/proc_table_gles.h | 2 + impeller/renderer/backend/gles/reactor_gles.h | 4 +- .../renderer/backend/gles/render_pass_gles.cc | 4 +- .../backend/gles/render_pass_gles3.cc | 721 ++++++++++++++++++ .../renderer/backend/gles/render_pass_gles3.h | 170 +++++ 13 files changed, 945 insertions(+), 21 deletions(-) create mode 100644 impeller/renderer/backend/gles/render_pass_gles3.cc create mode 100644 impeller/renderer/backend/gles/render_pass_gles3.h diff --git a/impeller/renderer/backend/gles/BUILD.gn b/impeller/renderer/backend/gles/BUILD.gn index a28309f5fa828..5ffcf6e80fdbc 100644 --- a/impeller/renderer/backend/gles/BUILD.gn +++ b/impeller/renderer/backend/gles/BUILD.gn @@ -76,6 +76,8 @@ impeller_component("gles") { "reactor_gles.h", "render_pass_gles.cc", "render_pass_gles.h", + "render_pass_gles3.cc", + "render_pass_gles3.h", "sampler_gles.cc", "sampler_gles.h", "sampler_library_gles.cc", diff --git a/impeller/renderer/backend/gles/buffer_bindings_gles.cc b/impeller/renderer/backend/gles/buffer_bindings_gles.cc index 3f10bc9b5d4ea..1548e9bf0dad2 100644 --- a/impeller/renderer/backend/gles/buffer_bindings_gles.cc +++ b/impeller/renderer/backend/gles/buffer_bindings_gles.cc @@ -219,8 +219,8 @@ bool BufferBindingsGLES::BindVertexAttributes(const ProcTableGLES& gl, bool BufferBindingsGLES::BindUniformData( const ProcTableGLES& gl, - const std::vector& bound_textures, - const std::vector& bound_buffers, + const TextureAndSampler bound_textures[], + const BufferResource bound_buffers[], Range texture_range, Range buffer_range) { for (auto i = 0u; i < buffer_range.length; i++) { @@ -444,7 +444,7 @@ bool BufferBindingsGLES::BindUniformBufferV2( std::optional BufferBindingsGLES::BindTextures( const ProcTableGLES& gl, - const std::vector& bound_textures, + const TextureAndSampler bound_textures[], Range texture_range, ShaderStage stage, size_t unit_start_index) { diff --git a/impeller/renderer/backend/gles/buffer_bindings_gles.h b/impeller/renderer/backend/gles/buffer_bindings_gles.h index 29f032da76cf9..5f277f054bd18 100644 --- a/impeller/renderer/backend/gles/buffer_bindings_gles.h +++ b/impeller/renderer/backend/gles/buffer_bindings_gles.h @@ -43,8 +43,8 @@ class BufferBindingsGLES { size_t vertex_offset); bool BindUniformData(const ProcTableGLES& gl, - const std::vector& bound_textures, - const std::vector& bound_buffers, + const TextureAndSampler bound_textures[], + const BufferResource bound_buffers[], Range texture_range, Range buffer_range); @@ -95,12 +95,11 @@ class BufferBindingsGLES { const ShaderMetadata* metadata, const DeviceBufferGLES& device_buffer_gles); - std::optional BindTextures( - const ProcTableGLES& gl, - const std::vector& bound_textures, - Range texture_range, - ShaderStage stage, - size_t unit_start_index = 0); + std::optional BindTextures(const ProcTableGLES& gl, + const TextureAndSampler bound_textures[], + Range texture_range, + ShaderStage stage, + size_t unit_start_index = 0); BufferBindingsGLES(const BufferBindingsGLES&) = delete; diff --git a/impeller/renderer/backend/gles/buffer_bindings_gles_unittests.cc b/impeller/renderer/backend/gles/buffer_bindings_gles_unittests.cc index 45a342bfcbd06..36f97bd893f31 100644 --- a/impeller/renderer/backend/gles/buffer_bindings_gles_unittests.cc +++ b/impeller/renderer/backend/gles/buffer_bindings_gles_unittests.cc @@ -42,9 +42,9 @@ TEST(BufferBindingsGLESTest, BindUniformData) { BufferView buffer_view(&device_buffer, Range(0, sizeof(float))); bound_buffers.push_back(BufferResource(&shader_metadata, buffer_view)); - EXPECT_TRUE(bindings.BindUniformData(mock_gl->GetProcTable(), bound_textures, - bound_buffers, Range{0, 0}, - Range{0, 1})); + EXPECT_TRUE( + bindings.BindUniformData(mock_gl->GetProcTable(), bound_textures.data(), + bound_buffers.data(), Range{0, 0}, Range{0, 1})); } } // namespace testing diff --git a/impeller/renderer/backend/gles/command_buffer_gles.cc b/impeller/renderer/backend/gles/command_buffer_gles.cc index 4cd6b279b9e18..18f9e7a3c7a87 100644 --- a/impeller/renderer/backend/gles/command_buffer_gles.cc +++ b/impeller/renderer/backend/gles/command_buffer_gles.cc @@ -7,6 +7,7 @@ #include "impeller/base/config.h" #include "impeller/renderer/backend/gles/blit_pass_gles.h" #include "impeller/renderer/backend/gles/render_pass_gles.h" +#include "impeller/renderer/backend/gles/render_pass_gles3.h" namespace impeller { @@ -58,6 +59,16 @@ std::shared_ptr CommandBufferGLES::OnCreateRenderPass( if (!context) { return nullptr; } + if (reactor_->GetProcTable().GetDescription()->GetGlVersion().IsAtLeast( + Version{3, 0, 0}) && + reactor_->CanReactOnCurrentThread()) { + auto pass = std::shared_ptr( + new RenderPassGLES3(context, target, reactor_)); + if (!pass->IsValid()) { + return nullptr; + } + return pass; + } auto pass = std::shared_ptr( new RenderPassGLES(context, target, reactor_)); if (!pass->IsValid()) { diff --git a/impeller/renderer/backend/gles/context_gles.cc b/impeller/renderer/backend/gles/context_gles.cc index f8cf2841cd013..9e9664747e5b2 100644 --- a/impeller/renderer/backend/gles/context_gles.cc +++ b/impeller/renderer/backend/gles/context_gles.cc @@ -74,6 +74,7 @@ ContextGLES::ContextGLES( gpu_tracer_ = std::make_shared(GetReactor()->GetProcTable(), enable_gpu_tracing); command_queue_ = std::make_shared(); + global_state_ = std::make_shared(); is_valid_ = true; } diff --git a/impeller/renderer/backend/gles/context_gles.h b/impeller/renderer/backend/gles/context_gles.h index 2e7e87a01c9fd..fc5247ed24a77 100644 --- a/impeller/renderer/backend/gles/context_gles.h +++ b/impeller/renderer/backend/gles/context_gles.h @@ -6,6 +6,7 @@ #define FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_CONTEXT_GLES_H_ #include "impeller/base/backend_cast.h" +#include "impeller/core/formats.h" #include "impeller/core/runtime_types.h" #include "impeller/renderer/backend/gles/allocator_gles.h" #include "impeller/renderer/backend/gles/capabilities_gles.h" @@ -20,6 +21,12 @@ namespace impeller { +struct GlobalStateGLES { + GLuint fbo_id = GL_NONE; + std::optional viewport = std::nullopt; + std::optional target_size = std::nullopt; +}; + class ContextGLES final : public Context, public BackendCast, public std::enable_shared_from_this { @@ -44,6 +51,8 @@ class ContextGLES final : public Context, std::shared_ptr GetGPUTracer() const { return gpu_tracer_; } + GlobalStateGLES* GetGlobalState() const { return global_state_.get(); } + private: std::shared_ptr reactor_; std::shared_ptr shader_library_; @@ -51,6 +60,7 @@ class ContextGLES final : public Context, std::shared_ptr sampler_library_; std::shared_ptr resource_allocator_; std::shared_ptr command_queue_; + std::shared_ptr global_state_; std::shared_ptr gpu_tracer_; // Note: This is stored separately from the ProcTableGLES CapabilitiesGLES diff --git a/impeller/renderer/backend/gles/device_buffer_gles.cc b/impeller/renderer/backend/gles/device_buffer_gles.cc index 0a7478d8f7e95..2cb2583d2ebe6 100644 --- a/impeller/renderer/backend/gles/device_buffer_gles.cc +++ b/impeller/renderer/backend/gles/device_buffer_gles.cc @@ -117,9 +117,17 @@ bool DeviceBufferGLES::BindAndUploadDataIfNecessary(BindingType type) const { } if (dirty_range_.has_value()) { - auto range = dirty_range_.value(); - gl.BufferSubData(target_type, range.offset, range.length, - backing_store_->GetBuffer() + range.offset); + Range range = dirty_range_.value(); + if (gl.MapBufferRange.IsAvailable()) { + void* data = + gl.MapBufferRange(target_type, range.offset, range.length, + GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); + ::memcpy(data, backing_store_->GetBuffer() + range.offset, range.length); + gl.UnmapBuffer(target_type); + } else { + gl.BufferSubData(target_type, range.offset, range.length, + backing_store_->GetBuffer() + range.offset); + } dirty_range_ = std::nullopt; } diff --git a/impeller/renderer/backend/gles/proc_table_gles.h b/impeller/renderer/backend/gles/proc_table_gles.h index ccc499af9dcca..e3ebe0204164a 100644 --- a/impeller/renderer/backend/gles/proc_table_gles.h +++ b/impeller/renderer/backend/gles/proc_table_gles.h @@ -241,6 +241,8 @@ void(glDepthRange)(GLdouble n, GLdouble f); #define FOR_EACH_IMPELLER_GLES3_PROC(PROC) \ PROC(FenceSync); \ PROC(DeleteSync); \ + PROC(MapBufferRange); \ + PROC(UnmapBuffer); \ PROC(GetActiveUniformBlockiv); \ PROC(GetActiveUniformBlockName); \ PROC(GetUniformBlockIndex); \ diff --git a/impeller/renderer/backend/gles/reactor_gles.h b/impeller/renderer/backend/gles/reactor_gles.h index a05dd22b8fb42..44ae9f5cde926 100644 --- a/impeller/renderer/backend/gles/reactor_gles.h +++ b/impeller/renderer/backend/gles/reactor_gles.h @@ -138,6 +138,8 @@ class ReactorGLES { /// const ProcTableGLES& GetProcTable() const; + bool CanReactOnCurrentThread() const; + //---------------------------------------------------------------------------- /// @brief Returns the OpenGL handle for a reactor handle if one is /// available. This is typically only safe to call within a @@ -306,8 +308,6 @@ class ReactorGLES { bool HasPendingOperations() const; - bool CanReactOnCurrentThread() const; - bool ConsolidateHandles(); bool FlushOps(); diff --git a/impeller/renderer/backend/gles/render_pass_gles.cc b/impeller/renderer/backend/gles/render_pass_gles.cc index c8900d6e0c1c0..8f3ed207c3cb6 100644 --- a/impeller/renderer/backend/gles/render_pass_gles.cc +++ b/impeller/renderer/backend/gles/render_pass_gles.cc @@ -463,8 +463,8 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) { /// if (!vertex_desc_gles->BindUniformData( gl, // - bound_textures, // - bound_buffers, // + bound_textures.data(), // + bound_buffers.data(), // /*texture_range=*/command.bound_textures, // /*buffer_range=*/command.bound_buffers // )) { diff --git a/impeller/renderer/backend/gles/render_pass_gles3.cc b/impeller/renderer/backend/gles/render_pass_gles3.cc new file mode 100644 index 0000000000000..307796b53db60 --- /dev/null +++ b/impeller/renderer/backend/gles/render_pass_gles3.cc @@ -0,0 +1,721 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/renderer/backend/gles/render_pass_gles3.h" + +#include + +#include "fml/closure.h" +#include "fml/logging.h" +#include "fml/status.h" +#include "impeller/base/validation.h" +#include "impeller/geometry/size.h" +#include "impeller/renderer/backend/gles/buffer_bindings_gles.h" +#include "impeller/renderer/backend/gles/context_gles.h" +#include "impeller/renderer/backend/gles/device_buffer_gles.h" +#include "impeller/renderer/backend/gles/formats_gles.h" +#include "impeller/renderer/backend/gles/pipeline_gles.h" +#include "impeller/renderer/backend/gles/texture_gles.h" +#include "impeller/renderer/command.h" + +namespace impeller { + +namespace { + +void ConfigureBlending(const ProcTableGLES& gl, + const ColorAttachmentDescriptor* color) { + if (color->blending_enabled) { + gl.Enable(GL_BLEND); + gl.BlendFuncSeparate( + ToBlendFactor(color->src_color_blend_factor), // src color + ToBlendFactor(color->dst_color_blend_factor), // dst color + ToBlendFactor(color->src_alpha_blend_factor), // src alpha + ToBlendFactor(color->dst_alpha_blend_factor) // dst alpha + ); + gl.BlendEquationSeparate( + ToBlendOperation(color->color_blend_op), // mode color + ToBlendOperation(color->alpha_blend_op) // mode alpha + ); + } else { + gl.Disable(GL_BLEND); + } + + { + const auto is_set = [](ColorWriteMask mask, + ColorWriteMask check) -> GLboolean { + return (mask & check) ? GL_TRUE : GL_FALSE; + }; + + gl.ColorMask( + is_set(color->write_mask, ColorWriteMaskBits::kRed), // red + is_set(color->write_mask, ColorWriteMaskBits::kGreen), // green + is_set(color->write_mask, ColorWriteMaskBits::kBlue), // blue + is_set(color->write_mask, ColorWriteMaskBits::kAlpha) // alpha + ); + } +} + +void ConfigureStencil(GLenum face, + const ProcTableGLES& gl, + const StencilAttachmentDescriptor& stencil, + uint32_t stencil_reference) { + gl.StencilOpSeparate( + face, // face + ToStencilOp(stencil.stencil_failure), // stencil fail + ToStencilOp(stencil.depth_failure), // depth fail + ToStencilOp(stencil.depth_stencil_pass) // depth stencil pass + ); + gl.StencilFuncSeparate(face, // face + ToCompareFunction(stencil.stencil_compare), // func + stencil_reference, // ref + stencil.read_mask // mask + ); + gl.StencilMaskSeparate(face, stencil.write_mask); +} + +void ConfigureStencil(const ProcTableGLES& gl, + const PipelineDescriptor& pipeline, + uint32_t stencil_reference) { + if (!pipeline.HasStencilAttachmentDescriptors()) { + gl.Disable(GL_STENCIL_TEST); + return; + } + + gl.Enable(GL_STENCIL_TEST); + const auto& front = pipeline.GetFrontStencilAttachmentDescriptor(); + const auto& back = pipeline.GetBackStencilAttachmentDescriptor(); + + if (front.has_value() && back.has_value() && front == back) { + ConfigureStencil(GL_FRONT_AND_BACK, gl, *front, stencil_reference); + return; + } + if (front.has_value()) { + ConfigureStencil(GL_FRONT, gl, *front, stencil_reference); + } + if (back.has_value()) { + ConfigureStencil(GL_BACK, gl, *back, stencil_reference); + } +} + +static bool BindVertexBuffer(const ProcTableGLES& gl, + BufferBindingsGLES* vertex_desc_gles, + const BufferView& vertex_buffer_view, + size_t buffer_index) { + if (!vertex_buffer_view) { + return false; + } + + const DeviceBuffer* vertex_buffer = vertex_buffer_view.GetBuffer(); + + if (!vertex_buffer) { + return false; + } + + const auto& vertex_buffer_gles = DeviceBufferGLES::Cast(*vertex_buffer); + if (!vertex_buffer_gles.BindAndUploadDataIfNecessary( + DeviceBufferGLES::BindingType::kArrayBuffer)) { + return false; + } + + //-------------------------------------------------------------------------- + /// Bind the vertex attributes associated with vertex buffer. + /// + if (!vertex_desc_gles->BindVertexAttributes( + gl, buffer_index, vertex_buffer_view.GetRange().offset)) { + return false; + } + + return true; +} + +} // namespace + +RenderPassGLES3::RenderPassGLES3(std::shared_ptr context, + const RenderTarget& target, + std::shared_ptr reactor) + : RenderPass(std::move(context), target), + reactor_(std::move(reactor)), + is_valid_(reactor_ && reactor_->IsValid()) { + const auto& render_target = GetRenderTarget(); + if (!render_target.HasColorAttachment(0u)) { + return; + } + const auto& gl = reactor_->GetProcTable(); + const ContextGLES& context_gles = ContextGLES::Cast(*GetContext()); + + const auto& color0 = render_target.GetColorAttachment(0); + const auto& depth0 = render_target.GetDepthAttachment(); + const auto& stencil0 = render_target.GetStencilAttachment(); + + render_pass_data_.label = label_; + render_pass_data_.viewport.rect = Rect::MakeSize(GetRenderTargetSize()); + + //---------------------------------------------------------------------------- + /// Setup color data. + /// + render_pass_data_.color_attachment = color0.texture; + render_pass_data_.clear_color = color0.clear_color; + render_pass_data_.clear_color_attachment = + CanClearAttachment(color0.load_action); + render_pass_data_.discard_color_attachment = + CanDiscardAttachmentWhenDone(color0.store_action); + + // When we are using EXT_multisampled_render_to_texture, it is implicitly + // resolved when we bind the texture to the framebuffer. We don't need to + // discard the attachment when we are done. + if (color0.resolve_texture) { + FML_DCHECK(context->GetCapabilities()->SupportsImplicitResolvingMSAA()); + render_pass_data_.discard_color_attachment = false; + } + + //---------------------------------------------------------------------------- + /// Setup depth data. + /// + if (depth0.has_value()) { + render_pass_data_.depth_attachment = depth0->texture; + render_pass_data_.clear_depth = depth0->clear_depth; + render_pass_data_.clear_depth_attachment = + CanClearAttachment(depth0->load_action); + render_pass_data_.discard_depth_attachment = + CanDiscardAttachmentWhenDone(depth0->store_action); + } + + //---------------------------------------------------------------------------- + /// Setup stencil data. + /// + if (stencil0.has_value()) { + render_pass_data_.stencil_attachment = stencil0->texture; + render_pass_data_.clear_stencil = stencil0->clear_stencil; + render_pass_data_.clear_stencil_attachment = + CanClearAttachment(stencil0->load_action); + render_pass_data_.discard_stencil_attachment = + CanDiscardAttachmentWhenDone(stencil0->store_action); + } + + GLuint fbo = GL_NONE; + TextureGLES& color_gles = + TextureGLES::Cast(*render_pass_data_.color_attachment); + const bool is_default_fbo = color_gles.IsWrapped(); + + if (is_default_fbo) { + // NOLINTNEXTLINE(bugprone-unchecked-optional-access) + gl.BindFramebuffer(GL_FRAMEBUFFER, *color_gles.GetFBO()); + } else { + // Create and bind an offscreen FBO. + auto cached_fbo = color_gles.GetCachedFBO(); + if (cached_fbo != GL_NONE) { + fbo = cached_fbo; + gl.BindFramebuffer(GL_FRAMEBUFFER, fbo); + } else { + gl.GenFramebuffers(1u, &fbo); + color_gles.SetCachedFBO(fbo); + gl.BindFramebuffer(GL_FRAMEBUFFER, fbo); + + if (!color_gles.SetAsFramebufferAttachment( + GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) { + return; + } + + if (auto depth = + TextureGLES::Cast(render_pass_data_.depth_attachment.get())) { + if (!depth->SetAsFramebufferAttachment( + GL_FRAMEBUFFER, TextureGLES::AttachmentType::kDepth)) { + return; + } + } + if (auto stencil = + TextureGLES::Cast(render_pass_data_.stencil_attachment.get())) { + if (!stencil->SetAsFramebufferAttachment( + GL_FRAMEBUFFER, TextureGLES::AttachmentType::kStencil)) { + return; + } + } + + auto status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + VALIDATION_LOG << "Could not create a complete frambuffer: " + << DebugToFramebufferError(status); + return; + } + } + } + current_fbo_ = fbo; + + gl.ClearColor(render_pass_data_.clear_color.red, // red + render_pass_data_.clear_color.green, // green + render_pass_data_.clear_color.blue, // blue + render_pass_data_.clear_color.alpha // alpha + ); + if (render_pass_data_.depth_attachment) { + if (gl.DepthRangef.IsAvailable()) { + gl.ClearDepthf(render_pass_data_.clear_depth); + } else { + gl.ClearDepth(render_pass_data_.clear_depth); + } + } + if (render_pass_data_.stencil_attachment) { + gl.ClearStencil(render_pass_data_.clear_stencil); + } + + GLenum clear_bits = 0u; + if (render_pass_data_.clear_color_attachment) { + clear_bits |= GL_COLOR_BUFFER_BIT; + } + if (render_pass_data_.clear_depth_attachment) { + clear_bits |= GL_DEPTH_BUFFER_BIT; + } + if (render_pass_data_.clear_stencil_attachment) { + clear_bits |= GL_STENCIL_BUFFER_BIT; + } + + RenderPassGLES3::ResetGLState(gl); + + gl.Clear(clear_bits); + + // Both the viewport and scissor are specified in framebuffer coordinates. + // Impeller's framebuffer coordinate system is top left origin, but OpenGL's + // is bottom left origin, so we convert the coordinates here. + auto target_size = render_pass_data_.color_attachment->GetSize(); + + //-------------------------------------------------------------------------- + /// Setup the viewport. + /// + const Viewport& viewport = render_pass_data_.viewport; + gl.Viewport(viewport.rect.GetX(), // x + target_size.height - viewport.rect.GetY() - + viewport.rect.GetHeight(), // y + viewport.rect.GetWidth(), // width + viewport.rect.GetHeight() // height + ); + if (render_pass_data_.depth_attachment) { + if (gl.DepthRangef.IsAvailable()) { + gl.DepthRangef(viewport.depth_range.z_near, viewport.depth_range.z_far); + } else { + gl.DepthRange(viewport.depth_range.z_near, viewport.depth_range.z_far); + } + } + + // Cache prior global rendering state. + GlobalStateGLES* global_state = context_gles.GetGlobalState(); + prev_framebuffer_ = global_state->fbo_id; + prev_size_ = global_state->target_size; + prev_viewport_ = global_state->viewport; + + global_state->fbo_id = fbo; + global_state->target_size = target_size; + global_state->viewport = viewport; +} + +// |RenderPass| +RenderPassGLES3::~RenderPassGLES3() = default; + +// |RenderPass| +bool RenderPassGLES3::IsValid() const { + return is_valid_; +} + +// |RenderPass| +void RenderPassGLES3::OnSetLabel(std::string_view label) { + label_ = label; +} + +void RenderPassGLES3::ResetGLState(const ProcTableGLES& gl) { + gl.Disable(GL_SCISSOR_TEST); + gl.Disable(GL_DEPTH_TEST); + gl.Disable(GL_STENCIL_TEST); + gl.Disable(GL_CULL_FACE); + gl.Disable(GL_BLEND); + gl.Disable(GL_DITHER); + gl.ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + gl.DepthMask(GL_TRUE); + gl.StencilMaskSeparate(GL_FRONT, 0xFFFFFFFF); + gl.StencilMaskSeparate(GL_BACK, 0xFFFFFFFF); +} + +// |RenderPass| +void RenderPassGLES3::SetPipeline( + const std::shared_ptr>& pipeline) { + PipelineGLES* pipeline_gles = PipelineGLES::Cast(pipeline.get()); + pipeline_ = pipeline_gles; +} + +// |RenderPass| +void RenderPassGLES3::SetCommandLabel(std::string_view label) {} + +// |RenderPass| +void RenderPassGLES3::SetStencilReference(uint32_t value) { + if (stencil_reference_ == value) { + return; + } + stencil_reference_ = value; +} + +// |RenderPass| +void RenderPassGLES3::SetBaseVertex(uint64_t value) { + base_vertex_ = value; +} + +// |RenderPass| +void RenderPassGLES3::SetViewport(Viewport viewport) { + const auto& gl = reactor_->GetProcTable(); + ISize target_size = render_pass_data_.color_attachment->GetSize(); + gl.Viewport(viewport.rect.GetX(), // x + target_size.height - viewport.rect.GetY() - + viewport.rect.GetHeight(), // y + viewport.rect.GetWidth(), // width + viewport.rect.GetHeight() // height + ); +} + +// |RenderPass| +void RenderPassGLES3::SetScissor(IRect scissor) { + const auto& gl = reactor_->GetProcTable(); + ISize target_size = render_pass_data_.color_attachment->GetSize(); + gl.Enable(GL_SCISSOR_TEST); + gl.Scissor(scissor.GetX(), // x + target_size.height - scissor.GetY() - scissor.GetHeight(), // y + scissor.GetWidth(), // width + scissor.GetHeight() // height + ); +} + +// |RenderPass| +void RenderPassGLES3::SetElementCount(size_t count) { + element_count_ = count; +} + +// |RenderPass| +void RenderPassGLES3::SetInstanceCount(size_t count) { + instance_count_ = count; +} + +// |RenderPass| +bool RenderPassGLES3::SetVertexBuffer(BufferView vertex_buffers[], + size_t vertex_buffer_count) { + vertex_buffer_count_ = vertex_buffer_count; + for (size_t i = 0; i < vertex_buffer_count; i++) { + vertex_buffers_[i] = vertex_buffers[i]; + } + return true; +} + +// |RenderPass| +bool RenderPassGLES3::SetIndexBuffer(BufferView index_buffer, + IndexType index_type) { + index_type_ = index_type; + index_buffer_ = std::move(index_buffer); + return true; +} + +// |RenderPass| +fml::Status RenderPassGLES3::Draw() { + const auto& gl = reactor_->GetProcTable(); + + fml::ScopedCleanupClosure cleanup([&] { + bound_texture_index_ = 0; + bound_buffers_index_ = 0; + base_vertex_ = 0; + element_count_ = 0; + instance_count_ = 0; + index_buffer_ = {}; + index_type_ = IndexType::kNone; + vertex_buffer_count_ = 0; + }); + + if (!pipeline_) { + return fml::Status(fml::StatusCode::kInternal, ""); + } + + const auto* color_attachment = + pipeline_->GetDescriptor().GetLegacyCompatibleColorAttachment(); + if (!color_attachment) { + VALIDATION_LOG + << "Color attachment is too complicated for a legacy renderer."; + return fml::Status(fml::StatusCode::kInternal, ""); + } + + //-------------------------------------------------------------------------- + /// Configure blending. + /// + ConfigureBlending(gl, color_attachment); + + //-------------------------------------------------------------------------- + /// Setup stencil. + /// + ConfigureStencil(gl, pipeline_->GetDescriptor(), stencil_reference_); + + //-------------------------------------------------------------------------- + /// Configure depth. + /// + if (auto depth = + pipeline_->GetDescriptor().GetDepthStencilAttachmentDescriptor(); + depth.has_value()) { + gl.Enable(GL_DEPTH_TEST); + gl.DepthFunc(ToCompareFunction(depth->depth_compare)); + gl.DepthMask(depth->depth_write_enabled ? GL_TRUE : GL_FALSE); + } else { + gl.Disable(GL_DEPTH_TEST); + } + + //-------------------------------------------------------------------------- + /// Setup culling. + /// + switch (pipeline_->GetDescriptor().GetCullMode()) { + case CullMode::kNone: + gl.Disable(GL_CULL_FACE); + break; + case CullMode::kFrontFace: + gl.Enable(GL_CULL_FACE); + gl.CullFace(GL_FRONT); + break; + case CullMode::kBackFace: + gl.Enable(GL_CULL_FACE); + gl.CullFace(GL_BACK); + break; + } + //-------------------------------------------------------------------------- + /// Setup winding order. + /// + switch (pipeline_->GetDescriptor().GetWindingOrder()) { + case WindingOrder::kClockwise: + gl.FrontFace(GL_CW); + break; + case WindingOrder::kCounterClockwise: + gl.FrontFace(GL_CCW); + break; + } + + //-------------------------------------------------------------------------- + /// Bind the pipeline program. + /// + if (!pipeline_->BindProgram()) { + VALIDATION_LOG << "Failed to bind pipeline program"; + } + + BufferBindingsGLES* vertex_desc_gles = pipeline_->GetBufferBindings(); + + //-------------------------------------------------------------------------- + /// Bind uniform data. + /// + if (!vertex_desc_gles->BindUniformData( + gl, // + /*bound_textures=*/bound_textures_.data(), + /*bound_buffers=*/bound_buffers_.data(), + /*texture_range=*/Range{0, bound_texture_index_}, + /*buffer_range=*/Range{0, bound_buffers_index_})) { + return fml::Status(fml::StatusCode::kInternal, ""); + } + + // Bind Vertex Data + for (auto i = 0u; i < vertex_buffer_count_; i++) { + if (!BindVertexBuffer(gl, vertex_desc_gles, vertex_buffers_[i], i)) { + return fml::Status(fml::StatusCode::kInternal, ""); + } + } + + //-------------------------------------------------------------------------- + /// Determine the primitive type. + /// + // GLES doesn't support setting the fill mode, so override the primitive + // with GL_LINE_STRIP to somewhat emulate PolygonMode::kLine. This isn't + // correct; full triangle outlines won't be drawn and disconnected + // geometry may appear connected. However this can still be useful for + // wireframe debug views. + auto mode = pipeline_->GetDescriptor().GetPolygonMode() == PolygonMode::kLine + ? GL_LINE_STRIP + : ToMode(pipeline_->GetDescriptor().GetPrimitiveType()); + + //-------------------------------------------------------------------------- + /// Finally! Invoke the draw call. + /// + if (index_type_ == IndexType::kNone) { + gl.DrawArrays(mode, base_vertex_, element_count_); + } else { + // Bind the index buffer if necessary. + const DeviceBuffer* index_buffer = index_buffer_.GetBuffer(); + const DeviceBufferGLES& index_buffer_gles = + DeviceBufferGLES::Cast(*index_buffer); + if (!index_buffer_gles.BindAndUploadDataIfNecessary( + DeviceBufferGLES::BindingType::kElementArrayBuffer)) { + fml::Status(fml::StatusCode::kInternal, ""); + } + gl.DrawElements(mode, // mode + element_count_, // count + ToIndexType(index_type_), // type + reinterpret_cast(static_cast( + index_buffer_.GetRange().offset)) // indices + ); + } + + //-------------------------------------------------------------------------- + /// Unbind vertex attribs. + /// + if (!vertex_desc_gles->UnbindVertexAttributes(gl)) { + fml::Status(fml::StatusCode::kInternal, ""); + } + + // OK! + return {}; +} + +// |ResourceBinder| +bool RenderPassGLES3::BindResource(ShaderStage stage, + DescriptorType type, + const ShaderUniformSlot& slot, + const ShaderMetadata* metadata, + BufferView view) { + if (bound_buffers_index_ > 16) { + return false; + } + bound_buffers_[bound_buffers_index_++] = + BufferResource(metadata, std::move(view)); + return true; +} + +// |ResourceBinder| +bool RenderPassGLES3::BindResource( + ShaderStage stage, + DescriptorType type, + const SampledImageSlot& slot, + const ShaderMetadata* metadata, + std::shared_ptr texture, + const std::unique_ptr& sampler) { + if (!sampler || !texture || !texture->IsValid() || + bound_texture_index_ > 16) { + return false; + } + + TextureResource resource = TextureResource(metadata, std::move(texture)); + + bound_textures_[bound_texture_index_++] = TextureAndSampler{ + .slot = slot, + .stage = stage, + .texture = std::move(resource), + .sampler = &sampler, + }; + return true; +} + +// |RenderPass| +bool RenderPassGLES3::BindDynamicResource( + ShaderStage stage, + DescriptorType type, + const SampledImageSlot& slot, + std::unique_ptr metadata, + std::shared_ptr texture, + const std::unique_ptr& sampler) { + if (!sampler || !texture || !texture->IsValid() || + bound_texture_index_ > 16) { + return false; + } + + TextureResource resource = + TextureResource::MakeDynamic(std::move(metadata), std::move(texture)); + + bound_textures_[bound_texture_index_++] = TextureAndSampler{ + .slot = slot, + .stage = stage, + .texture = std::move(resource), + .sampler = &sampler, + }; + return true; +} + +// |RenderPass| +bool RenderPassGLES3::BindDynamicResource( + ShaderStage stage, + DescriptorType type, + const ShaderUniformSlot& slot, + std::unique_ptr metadata, + BufferView view) { + if (bound_buffers_index_ > 16) { + return false; + } + bound_buffers_[bound_buffers_index_++] = + BufferResource::MakeDynamic(std::move(metadata), std::move(view)); + return true; +} + +// |RenderPass| +bool RenderPassGLES3::OnEncodeCommands(const Context& context) const { + if (!IsValid()) { + return false; + } + + const auto& gl = reactor_->GetProcTable(); + TextureGLES& color_gles = + TextureGLES::Cast(*render_pass_data_.color_attachment); + const bool is_default_fbo = color_gles.IsWrapped(); + + if (gl.DiscardFramebufferEXT.IsAvailable()) { + std::array attachments; + size_t attachment_count = 0; + + // TODO(130048): discarding stencil or depth on the default fbo causes Angle + // to discard the entire render target. Until we know the reason, default to + // storing. + bool angle_safe = gl.GetCapabilities()->IsANGLE() ? !is_default_fbo : true; + + if (render_pass_data_.discard_color_attachment) { + attachments[attachment_count++] = + (is_default_fbo ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0); + } + if (render_pass_data_.discard_depth_attachment && angle_safe) { + attachments[attachment_count++] = + (is_default_fbo ? GL_DEPTH_EXT : GL_DEPTH_ATTACHMENT); + } + + if (render_pass_data_.discard_stencil_attachment && angle_safe) { + attachments[attachment_count++] = + (is_default_fbo ? GL_STENCIL_EXT : GL_STENCIL_ATTACHMENT); + } + gl.DiscardFramebufferEXT(GL_FRAMEBUFFER, // target + attachment_count, // attachments to discard + attachments.data() // size + ); + } + ResetGLState(gl); + + GlobalStateGLES* global_state = + ContextGLES::Cast(*GetContext()).GetGlobalState(); + if (prev_framebuffer_ != current_fbo_) { + gl.BindFramebuffer(GL_FRAMEBUFFER, prev_framebuffer_); + + if (prev_viewport_.has_value() && prev_size_.has_value()) { + const auto& viewport = prev_viewport_.value(); + const auto& target_size = prev_size_.value(); + gl.Viewport(viewport.rect.GetX(), // x + target_size.height - viewport.rect.GetY() - + viewport.rect.GetHeight(), // y + viewport.rect.GetWidth(), // width + viewport.rect.GetHeight() // height + ); + if (gl.DepthRangef.IsAvailable()) { + gl.DepthRangef(viewport.depth_range.z_near, viewport.depth_range.z_far); + } else { + gl.DepthRange(viewport.depth_range.z_near, viewport.depth_range.z_far); + } + + gl.Enable(GL_SCISSOR_TEST); + gl.Scissor(0, // x + 0, // y + target_size.width, // width + target_size.height // height + ); + } + + global_state->fbo_id = prev_framebuffer_; + global_state->target_size = prev_size_; + global_state->viewport = prev_viewport_; + } + if (current_fbo_ == GL_NONE) { + global_state->fbo_id = GL_NONE; + global_state->target_size = std::nullopt; + global_state->viewport = std::nullopt; + } + + return true; +} + +} // namespace impeller \ No newline at end of file diff --git a/impeller/renderer/backend/gles/render_pass_gles3.h b/impeller/renderer/backend/gles/render_pass_gles3.h new file mode 100644 index 0000000000000..8eb099ef71a7d --- /dev/null +++ b/impeller/renderer/backend/gles/render_pass_gles3.h @@ -0,0 +1,170 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_RENDER_PASS_GLES3_H_ +#define FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_RENDER_PASS_GLES3_H_ + +#include +#include + +#include "flutter/impeller/renderer/backend/gles/reactor_gles.h" +#include "flutter/impeller/renderer/render_pass.h" +#include "impeller/core/buffer_view.h" +#include "impeller/core/formats.h" +#include "impeller/renderer/backend/gles/pipeline_gles.h" +#include "impeller/renderer/command.h" + +namespace impeller { + +class RenderPassGLES3 final + : public RenderPass, + public std::enable_shared_from_this { + public: + // |RenderPass| + ~RenderPassGLES3() override; + + static void ResetGLState(const ProcTableGLES& gl); + + private: + friend class CommandBufferGLES; + + //------------------------------------------------------------------------------ + /// @brief Encapsulates data that will be needed in the reactor for the + /// encoding of commands for this render pass. + /// + struct RenderPassData { + Viewport viewport; + + Color clear_color; + uint32_t clear_stencil = 0u; + Scalar clear_depth = 1.0; + + std::shared_ptr color_attachment; + std::shared_ptr depth_attachment; + std::shared_ptr stencil_attachment; + + bool clear_color_attachment = true; + bool clear_depth_attachment = true; + bool clear_stencil_attachment = true; + + bool discard_color_attachment = true; + bool discard_depth_attachment = true; + bool discard_stencil_attachment = true; + + std::string label; + }; + + std::shared_ptr reactor_; + std::string label_; + RenderPassData render_pass_data_; + uint32_t stencil_reference_ = 0; + bool is_valid_ = false; + + // Per command state. + std::array bound_textures_; + size_t bound_texture_index_ = 0; + std::array bound_buffers_; + size_t bound_buffers_index_ = 0; + std::array vertex_buffers_; + size_t vertex_buffer_count_ = 0; + uint64_t base_vertex_ = 0; + size_t element_count_ = 0; + size_t instance_count_ = 0; + BufferView index_buffer_ = {}; + IndexType index_type_ = IndexType::kNone; + const PipelineGLES* pipeline_ = nullptr; + + // cached state. + GLint current_fbo_ = GL_NONE; + GLint prev_framebuffer_ = GL_NONE; + std::optional prev_size_ = std::nullopt; + std::optional prev_viewport_ = std::nullopt; + + RenderPassGLES3(std::shared_ptr context, + const RenderTarget& target, + std::shared_ptr reactor); + + // |RenderPass| + bool IsValid() const override; + + // |RenderPass| + void OnSetLabel(std::string_view label) override; + + // |RenderPass| + bool OnEncodeCommands(const Context& context) const override; + + // |RenderPass| + void SetPipeline( + const std::shared_ptr>& pipeline) override; + + // |RenderPass| + void SetCommandLabel(std::string_view label) override; + + // |RenderPass| + void SetStencilReference(uint32_t value) override; + + // |RenderPass| + void SetBaseVertex(uint64_t value) override; + + // |RenderPass| + void SetViewport(Viewport viewport) override; + + // |RenderPass| + void SetScissor(IRect scissor) override; + + // |RenderPass| + void SetElementCount(size_t count) override; + + // |RenderPass| + void SetInstanceCount(size_t count) override; + + // |RenderPass| + bool SetVertexBuffer(BufferView vertex_buffers[], + size_t vertex_buffer_count) override; + + // |RenderPass| + bool SetIndexBuffer(BufferView index_buffer, IndexType index_type) override; + + // |RenderPass| + fml::Status Draw() override; + + // |ResourceBinder| + bool BindResource(ShaderStage stage, + DescriptorType type, + const ShaderUniformSlot& slot, + const ShaderMetadata* metadata, + BufferView view) override; + + // |ResourceBinder| + bool BindResource(ShaderStage stage, + DescriptorType type, + const SampledImageSlot& slot, + const ShaderMetadata* metadata, + std::shared_ptr texture, + const std::unique_ptr& sampler) override; + + // |RenderPass| + bool BindDynamicResource( + ShaderStage stage, + DescriptorType type, + const SampledImageSlot& slot, + std::unique_ptr metadata, + std::shared_ptr texture, + const std::unique_ptr& sampler) override; + + // |RenderPass| + bool BindDynamicResource(ShaderStage stage, + DescriptorType type, + const ShaderUniformSlot& slot, + std::unique_ptr metadata, + BufferView view) override; + + RenderPassGLES3(const RenderPassGLES3&) = delete; + + RenderPassGLES3& operator=(const RenderPassGLES3&) = delete; +}; + +} // namespace impeller + +#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_RENDER_PASS_GLES3_H_ From 090177e71b165b937a762c1111d106f6164488ca Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Mon, 9 Dec 2024 15:46:10 -0800 Subject: [PATCH 2/3] Refactored shared logic into utils class. --- impeller/renderer/backend/gles/BUILD.gn | 2 + .../renderer/backend/gles/render_pass_gles.cc | 133 +---------------- .../backend/gles/render_pass_gles3.cc | 135 ++---------------- .../renderer/backend/gles/render_pass_gles3.h | 33 +---- .../backend/gles/render_pass_utils.cc | 111 ++++++++++++++ .../renderer/backend/gles/render_pass_utils.h | 59 ++++++++ 6 files changed, 188 insertions(+), 285 deletions(-) create mode 100644 impeller/renderer/backend/gles/render_pass_utils.cc create mode 100644 impeller/renderer/backend/gles/render_pass_utils.h diff --git a/impeller/renderer/backend/gles/BUILD.gn b/impeller/renderer/backend/gles/BUILD.gn index 5ffcf6e80fdbc..2197643d49cba 100644 --- a/impeller/renderer/backend/gles/BUILD.gn +++ b/impeller/renderer/backend/gles/BUILD.gn @@ -78,6 +78,8 @@ impeller_component("gles") { "render_pass_gles.h", "render_pass_gles3.cc", "render_pass_gles3.h", + "render_pass_utils.cc", + "render_pass_utils.h", "sampler_gles.cc", "sampler_gles.h", "sampler_library_gles.cc", diff --git a/impeller/renderer/backend/gles/render_pass_gles.cc b/impeller/renderer/backend/gles/render_pass_gles.cc index 8f3ed207c3cb6..623c0abb8a4e1 100644 --- a/impeller/renderer/backend/gles/render_pass_gles.cc +++ b/impeller/renderer/backend/gles/render_pass_gles.cc @@ -18,6 +18,7 @@ #include "impeller/renderer/backend/gles/formats_gles.h" #include "impeller/renderer/backend/gles/gpu_tracer_gles.h" #include "impeller/renderer/backend/gles/pipeline_gles.h" +#include "impeller/renderer/backend/gles/render_pass_utils.h" #include "impeller/renderer/backend/gles/texture_gles.h" #include "impeller/renderer/command.h" @@ -43,138 +44,6 @@ void RenderPassGLES::OnSetLabel(std::string_view label) { label_ = label; } -void ConfigureBlending(const ProcTableGLES& gl, - const ColorAttachmentDescriptor* color) { - if (color->blending_enabled) { - gl.Enable(GL_BLEND); - gl.BlendFuncSeparate( - ToBlendFactor(color->src_color_blend_factor), // src color - ToBlendFactor(color->dst_color_blend_factor), // dst color - ToBlendFactor(color->src_alpha_blend_factor), // src alpha - ToBlendFactor(color->dst_alpha_blend_factor) // dst alpha - ); - gl.BlendEquationSeparate( - ToBlendOperation(color->color_blend_op), // mode color - ToBlendOperation(color->alpha_blend_op) // mode alpha - ); - } else { - gl.Disable(GL_BLEND); - } - - { - const auto is_set = [](ColorWriteMask mask, - ColorWriteMask check) -> GLboolean { - return (mask & check) ? GL_TRUE : GL_FALSE; - }; - - gl.ColorMask( - is_set(color->write_mask, ColorWriteMaskBits::kRed), // red - is_set(color->write_mask, ColorWriteMaskBits::kGreen), // green - is_set(color->write_mask, ColorWriteMaskBits::kBlue), // blue - is_set(color->write_mask, ColorWriteMaskBits::kAlpha) // alpha - ); - } -} - -void ConfigureStencil(GLenum face, - const ProcTableGLES& gl, - const StencilAttachmentDescriptor& stencil, - uint32_t stencil_reference) { - gl.StencilOpSeparate( - face, // face - ToStencilOp(stencil.stencil_failure), // stencil fail - ToStencilOp(stencil.depth_failure), // depth fail - ToStencilOp(stencil.depth_stencil_pass) // depth stencil pass - ); - gl.StencilFuncSeparate(face, // face - ToCompareFunction(stencil.stencil_compare), // func - stencil_reference, // ref - stencil.read_mask // mask - ); - gl.StencilMaskSeparate(face, stencil.write_mask); -} - -void ConfigureStencil(const ProcTableGLES& gl, - const PipelineDescriptor& pipeline, - uint32_t stencil_reference) { - if (!pipeline.HasStencilAttachmentDescriptors()) { - gl.Disable(GL_STENCIL_TEST); - return; - } - - gl.Enable(GL_STENCIL_TEST); - const auto& front = pipeline.GetFrontStencilAttachmentDescriptor(); - const auto& back = pipeline.GetBackStencilAttachmentDescriptor(); - - if (front.has_value() && back.has_value() && front == back) { - ConfigureStencil(GL_FRONT_AND_BACK, gl, *front, stencil_reference); - return; - } - if (front.has_value()) { - ConfigureStencil(GL_FRONT, gl, *front, stencil_reference); - } - if (back.has_value()) { - ConfigureStencil(GL_BACK, gl, *back, stencil_reference); - } -} - -//------------------------------------------------------------------------------ -/// @brief Encapsulates data that will be needed in the reactor for the -/// encoding of commands for this render pass. -/// -struct RenderPassData { - Viewport viewport; - - Color clear_color; - uint32_t clear_stencil = 0u; - Scalar clear_depth = 1.0; - - std::shared_ptr color_attachment; - std::shared_ptr depth_attachment; - std::shared_ptr stencil_attachment; - - bool clear_color_attachment = true; - bool clear_depth_attachment = true; - bool clear_stencil_attachment = true; - - bool discard_color_attachment = true; - bool discard_depth_attachment = true; - bool discard_stencil_attachment = true; - - std::string label; -}; - -static bool BindVertexBuffer(const ProcTableGLES& gl, - BufferBindingsGLES* vertex_desc_gles, - const BufferView& vertex_buffer_view, - size_t buffer_index) { - if (!vertex_buffer_view) { - return false; - } - - const DeviceBuffer* vertex_buffer = vertex_buffer_view.GetBuffer(); - - if (!vertex_buffer) { - return false; - } - - const auto& vertex_buffer_gles = DeviceBufferGLES::Cast(*vertex_buffer); - if (!vertex_buffer_gles.BindAndUploadDataIfNecessary( - DeviceBufferGLES::BindingType::kArrayBuffer)) { - return false; - } - - //-------------------------------------------------------------------------- - /// Bind the vertex attributes associated with vertex buffer. - /// - if (!vertex_desc_gles->BindVertexAttributes( - gl, buffer_index, vertex_buffer_view.GetRange().offset)) { - return false; - } - - return true; -} - void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) { gl.Disable(GL_SCISSOR_TEST); gl.Disable(GL_DEPTH_TEST); diff --git a/impeller/renderer/backend/gles/render_pass_gles3.cc b/impeller/renderer/backend/gles/render_pass_gles3.cc index 307796b53db60..a8367a4ccbc7a 100644 --- a/impeller/renderer/backend/gles/render_pass_gles3.cc +++ b/impeller/renderer/backend/gles/render_pass_gles3.cc @@ -21,116 +21,6 @@ namespace impeller { -namespace { - -void ConfigureBlending(const ProcTableGLES& gl, - const ColorAttachmentDescriptor* color) { - if (color->blending_enabled) { - gl.Enable(GL_BLEND); - gl.BlendFuncSeparate( - ToBlendFactor(color->src_color_blend_factor), // src color - ToBlendFactor(color->dst_color_blend_factor), // dst color - ToBlendFactor(color->src_alpha_blend_factor), // src alpha - ToBlendFactor(color->dst_alpha_blend_factor) // dst alpha - ); - gl.BlendEquationSeparate( - ToBlendOperation(color->color_blend_op), // mode color - ToBlendOperation(color->alpha_blend_op) // mode alpha - ); - } else { - gl.Disable(GL_BLEND); - } - - { - const auto is_set = [](ColorWriteMask mask, - ColorWriteMask check) -> GLboolean { - return (mask & check) ? GL_TRUE : GL_FALSE; - }; - - gl.ColorMask( - is_set(color->write_mask, ColorWriteMaskBits::kRed), // red - is_set(color->write_mask, ColorWriteMaskBits::kGreen), // green - is_set(color->write_mask, ColorWriteMaskBits::kBlue), // blue - is_set(color->write_mask, ColorWriteMaskBits::kAlpha) // alpha - ); - } -} - -void ConfigureStencil(GLenum face, - const ProcTableGLES& gl, - const StencilAttachmentDescriptor& stencil, - uint32_t stencil_reference) { - gl.StencilOpSeparate( - face, // face - ToStencilOp(stencil.stencil_failure), // stencil fail - ToStencilOp(stencil.depth_failure), // depth fail - ToStencilOp(stencil.depth_stencil_pass) // depth stencil pass - ); - gl.StencilFuncSeparate(face, // face - ToCompareFunction(stencil.stencil_compare), // func - stencil_reference, // ref - stencil.read_mask // mask - ); - gl.StencilMaskSeparate(face, stencil.write_mask); -} - -void ConfigureStencil(const ProcTableGLES& gl, - const PipelineDescriptor& pipeline, - uint32_t stencil_reference) { - if (!pipeline.HasStencilAttachmentDescriptors()) { - gl.Disable(GL_STENCIL_TEST); - return; - } - - gl.Enable(GL_STENCIL_TEST); - const auto& front = pipeline.GetFrontStencilAttachmentDescriptor(); - const auto& back = pipeline.GetBackStencilAttachmentDescriptor(); - - if (front.has_value() && back.has_value() && front == back) { - ConfigureStencil(GL_FRONT_AND_BACK, gl, *front, stencil_reference); - return; - } - if (front.has_value()) { - ConfigureStencil(GL_FRONT, gl, *front, stencil_reference); - } - if (back.has_value()) { - ConfigureStencil(GL_BACK, gl, *back, stencil_reference); - } -} - -static bool BindVertexBuffer(const ProcTableGLES& gl, - BufferBindingsGLES* vertex_desc_gles, - const BufferView& vertex_buffer_view, - size_t buffer_index) { - if (!vertex_buffer_view) { - return false; - } - - const DeviceBuffer* vertex_buffer = vertex_buffer_view.GetBuffer(); - - if (!vertex_buffer) { - return false; - } - - const auto& vertex_buffer_gles = DeviceBufferGLES::Cast(*vertex_buffer); - if (!vertex_buffer_gles.BindAndUploadDataIfNecessary( - DeviceBufferGLES::BindingType::kArrayBuffer)) { - return false; - } - - //-------------------------------------------------------------------------- - /// Bind the vertex attributes associated with vertex buffer. - /// - if (!vertex_desc_gles->BindVertexAttributes( - gl, buffer_index, vertex_buffer_view.GetRange().offset)) { - return false; - } - - return true; -} - -} // namespace - RenderPassGLES3::RenderPassGLES3(std::shared_ptr context, const RenderTarget& target, std::shared_ptr reactor) @@ -334,10 +224,8 @@ void RenderPassGLES3::ResetGLState(const ProcTableGLES& gl) { } // |RenderPass| -void RenderPassGLES3::SetPipeline( - const std::shared_ptr>& pipeline) { - PipelineGLES* pipeline_gles = PipelineGLES::Cast(pipeline.get()); - pipeline_ = pipeline_gles; +void RenderPassGLES3::SetPipeline(PipelineRef pipeline) { + pipeline_ = pipeline; } // |RenderPass| @@ -427,8 +315,9 @@ fml::Status RenderPassGLES3::Draw() { return fml::Status(fml::StatusCode::kInternal, ""); } + const PipelineGLES& pipeline = PipelineGLES::Cast(*pipeline_); const auto* color_attachment = - pipeline_->GetDescriptor().GetLegacyCompatibleColorAttachment(); + pipeline.GetDescriptor().GetLegacyCompatibleColorAttachment(); if (!color_attachment) { VALIDATION_LOG << "Color attachment is too complicated for a legacy renderer."; @@ -443,13 +332,13 @@ fml::Status RenderPassGLES3::Draw() { //-------------------------------------------------------------------------- /// Setup stencil. /// - ConfigureStencil(gl, pipeline_->GetDescriptor(), stencil_reference_); + ConfigureStencil(gl, pipeline.GetDescriptor(), stencil_reference_); //-------------------------------------------------------------------------- /// Configure depth. /// if (auto depth = - pipeline_->GetDescriptor().GetDepthStencilAttachmentDescriptor(); + pipeline.GetDescriptor().GetDepthStencilAttachmentDescriptor(); depth.has_value()) { gl.Enable(GL_DEPTH_TEST); gl.DepthFunc(ToCompareFunction(depth->depth_compare)); @@ -461,7 +350,7 @@ fml::Status RenderPassGLES3::Draw() { //-------------------------------------------------------------------------- /// Setup culling. /// - switch (pipeline_->GetDescriptor().GetCullMode()) { + switch (pipeline.GetDescriptor().GetCullMode()) { case CullMode::kNone: gl.Disable(GL_CULL_FACE); break; @@ -477,7 +366,7 @@ fml::Status RenderPassGLES3::Draw() { //-------------------------------------------------------------------------- /// Setup winding order. /// - switch (pipeline_->GetDescriptor().GetWindingOrder()) { + switch (pipeline.GetDescriptor().GetWindingOrder()) { case WindingOrder::kClockwise: gl.FrontFace(GL_CW); break; @@ -489,11 +378,11 @@ fml::Status RenderPassGLES3::Draw() { //-------------------------------------------------------------------------- /// Bind the pipeline program. /// - if (!pipeline_->BindProgram()) { + if (!pipeline.BindProgram()) { VALIDATION_LOG << "Failed to bind pipeline program"; } - BufferBindingsGLES* vertex_desc_gles = pipeline_->GetBufferBindings(); + BufferBindingsGLES* vertex_desc_gles = pipeline.GetBufferBindings(); //-------------------------------------------------------------------------- /// Bind uniform data. @@ -522,9 +411,9 @@ fml::Status RenderPassGLES3::Draw() { // correct; full triangle outlines won't be drawn and disconnected // geometry may appear connected. However this can still be useful for // wireframe debug views. - auto mode = pipeline_->GetDescriptor().GetPolygonMode() == PolygonMode::kLine + auto mode = pipeline.GetDescriptor().GetPolygonMode() == PolygonMode::kLine ? GL_LINE_STRIP - : ToMode(pipeline_->GetDescriptor().GetPrimitiveType()); + : ToMode(pipeline.GetDescriptor().GetPrimitiveType()); //-------------------------------------------------------------------------- /// Finally! Invoke the draw call. diff --git a/impeller/renderer/backend/gles/render_pass_gles3.h b/impeller/renderer/backend/gles/render_pass_gles3.h index 8eb099ef71a7d..4855b6ed52bb6 100644 --- a/impeller/renderer/backend/gles/render_pass_gles3.h +++ b/impeller/renderer/backend/gles/render_pass_gles3.h @@ -12,7 +12,7 @@ #include "flutter/impeller/renderer/render_pass.h" #include "impeller/core/buffer_view.h" #include "impeller/core/formats.h" -#include "impeller/renderer/backend/gles/pipeline_gles.h" +#include "impeller/renderer/backend/gles/render_pass_utils.h" #include "impeller/renderer/command.h" namespace impeller { @@ -29,32 +29,6 @@ class RenderPassGLES3 final private: friend class CommandBufferGLES; - //------------------------------------------------------------------------------ - /// @brief Encapsulates data that will be needed in the reactor for the - /// encoding of commands for this render pass. - /// - struct RenderPassData { - Viewport viewport; - - Color clear_color; - uint32_t clear_stencil = 0u; - Scalar clear_depth = 1.0; - - std::shared_ptr color_attachment; - std::shared_ptr depth_attachment; - std::shared_ptr stencil_attachment; - - bool clear_color_attachment = true; - bool clear_depth_attachment = true; - bool clear_stencil_attachment = true; - - bool discard_color_attachment = true; - bool discard_depth_attachment = true; - bool discard_stencil_attachment = true; - - std::string label; - }; - std::shared_ptr reactor_; std::string label_; RenderPassData render_pass_data_; @@ -73,7 +47,7 @@ class RenderPassGLES3 final size_t instance_count_ = 0; BufferView index_buffer_ = {}; IndexType index_type_ = IndexType::kNone; - const PipelineGLES* pipeline_ = nullptr; + PipelineRef pipeline_; // cached state. GLint current_fbo_ = GL_NONE; @@ -95,8 +69,7 @@ class RenderPassGLES3 final bool OnEncodeCommands(const Context& context) const override; // |RenderPass| - void SetPipeline( - const std::shared_ptr>& pipeline) override; + void SetPipeline(PipelineRef pipeline) override; // |RenderPass| void SetCommandLabel(std::string_view label) override; diff --git a/impeller/renderer/backend/gles/render_pass_utils.cc b/impeller/renderer/backend/gles/render_pass_utils.cc new file mode 100644 index 0000000000000..7f4fefdbfabae --- /dev/null +++ b/impeller/renderer/backend/gles/render_pass_utils.cc @@ -0,0 +1,111 @@ +#include "impeller/renderer/backend/gles/render_pass_utils.h" +#include "impeller/renderer/backend/gles/formats_gles.h" + +namespace impeller { + +void ConfigureBlending(const ProcTableGLES& gl, + const ColorAttachmentDescriptor* color) { + if (color->blending_enabled) { + gl.Enable(GL_BLEND); + gl.BlendFuncSeparate( + ToBlendFactor(color->src_color_blend_factor), // src color + ToBlendFactor(color->dst_color_blend_factor), // dst color + ToBlendFactor(color->src_alpha_blend_factor), // src alpha + ToBlendFactor(color->dst_alpha_blend_factor) // dst alpha + ); + gl.BlendEquationSeparate( + ToBlendOperation(color->color_blend_op), // mode color + ToBlendOperation(color->alpha_blend_op) // mode alpha + ); + } else { + gl.Disable(GL_BLEND); + } + + { + const auto is_set = [](ColorWriteMask mask, + ColorWriteMask check) -> GLboolean { + return (mask & check) ? GL_TRUE : GL_FALSE; + }; + + gl.ColorMask( + is_set(color->write_mask, ColorWriteMaskBits::kRed), // red + is_set(color->write_mask, ColorWriteMaskBits::kGreen), // green + is_set(color->write_mask, ColorWriteMaskBits::kBlue), // blue + is_set(color->write_mask, ColorWriteMaskBits::kAlpha) // alpha + ); + } +} +void ConfigureStencil(GLenum face, + const ProcTableGLES& gl, + const StencilAttachmentDescriptor& stencil, + uint32_t stencil_reference) { + gl.StencilOpSeparate( + face, // face + ToStencilOp(stencil.stencil_failure), // stencil fail + ToStencilOp(stencil.depth_failure), // depth fail + ToStencilOp(stencil.depth_stencil_pass) // depth stencil pass + ); + gl.StencilFuncSeparate(face, // face + ToCompareFunction(stencil.stencil_compare), // func + stencil_reference, // ref + stencil.read_mask // mask + ); + gl.StencilMaskSeparate(face, stencil.write_mask); +} + +void ConfigureStencil(const ProcTableGLES& gl, + const PipelineDescriptor& pipeline, + uint32_t stencil_reference) { + if (!pipeline.HasStencilAttachmentDescriptors()) { + gl.Disable(GL_STENCIL_TEST); + return; + } + + gl.Enable(GL_STENCIL_TEST); + const auto& front = pipeline.GetFrontStencilAttachmentDescriptor(); + const auto& back = pipeline.GetBackStencilAttachmentDescriptor(); + + if (front.has_value() && back.has_value() && front == back) { + ConfigureStencil(GL_FRONT_AND_BACK, gl, *front, stencil_reference); + return; + } + if (front.has_value()) { + ConfigureStencil(GL_FRONT, gl, *front, stencil_reference); + } + if (back.has_value()) { + ConfigureStencil(GL_BACK, gl, *back, stencil_reference); + } +} + +bool BindVertexBuffer(const ProcTableGLES& gl, + BufferBindingsGLES* vertex_desc_gles, + const BufferView& vertex_buffer_view, + size_t buffer_index) { + if (!vertex_buffer_view) { + return false; + } + + const DeviceBuffer* vertex_buffer = vertex_buffer_view.GetBuffer(); + + if (!vertex_buffer) { + return false; + } + + const auto& vertex_buffer_gles = DeviceBufferGLES::Cast(*vertex_buffer); + if (!vertex_buffer_gles.BindAndUploadDataIfNecessary( + DeviceBufferGLES::BindingType::kArrayBuffer)) { + return false; + } + + //-------------------------------------------------------------------------- + /// Bind the vertex attributes associated with vertex buffer. + /// + if (!vertex_desc_gles->BindVertexAttributes( + gl, buffer_index, vertex_buffer_view.GetRange().offset)) { + return false; + } + + return true; +} + +} \ No newline at end of file diff --git a/impeller/renderer/backend/gles/render_pass_utils.h b/impeller/renderer/backend/gles/render_pass_utils.h new file mode 100644 index 0000000000000..798e7113f0363 --- /dev/null +++ b/impeller/renderer/backend/gles/render_pass_utils.h @@ -0,0 +1,59 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_RENDER_PASS_UTILS_H_ +#define FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_RENDER_PASS_UTILS_H_ + +#include "impeller/renderer/backend/gles/buffer_bindings_gles.h" +#include "impeller/renderer/backend/gles/proc_table_gles.h" +#include "impeller/renderer/pipeline_descriptor.h" + +namespace impeller { + +//------------------------------------------------------------------------------ +/// @brief Encapsulates data that will be needed in the reactor for the +/// encoding of commands for this render pass. +/// +struct RenderPassData { + Viewport viewport; + + Color clear_color; + uint32_t clear_stencil = 0u; + Scalar clear_depth = 1.0; + + std::shared_ptr color_attachment; + std::shared_ptr depth_attachment; + std::shared_ptr stencil_attachment; + + bool clear_color_attachment = true; + bool clear_depth_attachment = true; + bool clear_stencil_attachment = true; + + bool discard_color_attachment = true; + bool discard_depth_attachment = true; + bool discard_stencil_attachment = true; + + std::string label; +}; + +void ConfigureBlending(const ProcTableGLES& gl, + const ColorAttachmentDescriptor* color); + +void ConfigureStencil(GLenum face, + const ProcTableGLES& gl, + const StencilAttachmentDescriptor& stencil, + uint32_t stencil_reference); + +void ConfigureStencil(const ProcTableGLES& gl, + const PipelineDescriptor& pipeline, + uint32_t stencil_reference); + +bool BindVertexBuffer(const ProcTableGLES& gl, + BufferBindingsGLES* vertex_desc_gles, + const BufferView& vertex_buffer_view, + size_t buffer_index); + +} // namespace impeller + +#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_RENDER_PASS_UTILS_H_ From 3e18bcaf81ace9fb15b52d7990627f826e1c1ae4 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Mon, 9 Dec 2024 15:47:11 -0800 Subject: [PATCH 3/3] ++ --- impeller/renderer/backend/gles/render_pass_utils.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/impeller/renderer/backend/gles/render_pass_utils.cc b/impeller/renderer/backend/gles/render_pass_utils.cc index 7f4fefdbfabae..869571c5c01d8 100644 --- a/impeller/renderer/backend/gles/render_pass_utils.cc +++ b/impeller/renderer/backend/gles/render_pass_utils.cc @@ -78,9 +78,9 @@ void ConfigureStencil(const ProcTableGLES& gl, } bool BindVertexBuffer(const ProcTableGLES& gl, - BufferBindingsGLES* vertex_desc_gles, - const BufferView& vertex_buffer_view, - size_t buffer_index) { + BufferBindingsGLES* vertex_desc_gles, + const BufferView& vertex_buffer_view, + size_t buffer_index) { if (!vertex_buffer_view) { return false; } @@ -108,4 +108,4 @@ bool BindVertexBuffer(const ProcTableGLES& gl, return true; } -} \ No newline at end of file +} // namespace impeller \ No newline at end of file