diff --git a/impeller/BUILD.gn b/impeller/BUILD.gn index 0f8b679abea20..4dafc27b4fc3a 100644 --- a/impeller/BUILD.gn +++ b/impeller/BUILD.gn @@ -10,10 +10,6 @@ config("impeller_public_config") { defines = [] - if (impeller_debug) { - defines += [ "IMPELLER_DEBUG=1" ] - } - if (impeller_supports_rendering) { defines += [ "IMPELLER_SUPPORTS_RENDERING=1" ] } diff --git a/impeller/renderer/backend/gles/BUILD.gn b/impeller/renderer/backend/gles/BUILD.gn index a28309f5fa828..2197643d49cba 100644 --- a/impeller/renderer/backend/gles/BUILD.gn +++ b/impeller/renderer/backend/gles/BUILD.gn @@ -76,6 +76,10 @@ impeller_component("gles") { "reactor_gles.h", "render_pass_gles.cc", "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/buffer_bindings_gles.cc b/impeller/renderer/backend/gles/buffer_bindings_gles.cc index 3f10bc9b5d4ea..9e2f6a659dd10 100644 --- a/impeller/renderer/backend/gles/buffer_bindings_gles.cc +++ b/impeller/renderer/backend/gles/buffer_bindings_gles.cc @@ -126,6 +126,8 @@ bool BufferBindingsGLES::ReadUniformsBindingsV3(const ProcTableGLES& gl, gl.GetActiveUniformBlockName(program, i, name_length, &length, name.data()); GLuint block_index = gl.GetUniformBlockIndex(program, name.data()); + gl.UniformBlockBinding(program_handle_, block_index, i); + ubo_locations_[std::string{name.data(), static_cast(length)}] = std::make_pair(block_index, i); } @@ -219,8 +221,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++) { @@ -336,7 +338,6 @@ bool BufferBindingsGLES::BindUniformBufferV3( return BindUniformBufferV2(gl, buffer, metadata, device_buffer_gles); } const auto& [block_index, binding_point] = it->second; - gl.UniformBlockBinding(program_handle_, block_index, binding_point); if (!device_buffer_gles.BindAndUploadDataIfNecessary( DeviceBufferGLES::BindingType::kUniformBuffer)) { @@ -444,7 +445,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..ec474020e6a4c 100644 --- a/impeller/renderer/backend/gles/device_buffer_gles.cc +++ b/impeller/renderer/backend/gles/device_buffer_gles.cc @@ -31,6 +31,9 @@ uint8_t* DeviceBufferGLES::OnGetContents() const { if (!reactor_) { return nullptr; } + if (initialized_) { + return reinterpret_cast(data_); + } return backing_store_->GetBuffer(); } @@ -47,8 +50,8 @@ bool DeviceBufferGLES::OnCopyHostBuffer(const uint8_t* source, return false; } - std::memmove(backing_store_->GetBuffer() + offset, - source + source_range.offset, source_range.length); + std::memmove(OnGetContents() + offset, source + source_range.offset, + source_range.length); Flush(Range{offset, source_range.length}); return true; @@ -63,6 +66,9 @@ std::optional DeviceBufferGLES::GetHandle() const { } void DeviceBufferGLES::Flush(std::optional range) const { + if (initialized_) { + return; + } if (!range.has_value()) { dirty_range_ = Range{ 0, static_cast(backing_store_->GetLength().GetByteSize())}; @@ -111,15 +117,24 @@ bool DeviceBufferGLES::BindAndUploadDataIfNecessary(BindingType type) const { gl.BindBuffer(target_type, buffer.value()); if (!initialized_) { - gl.BufferData(target_type, backing_store_->GetLength().GetByteSize(), - nullptr, GL_DYNAMIC_DRAW); + gl.BufferStorageEXT( + target_type, backing_store_->GetLength().GetByteSize(), nullptr, + GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT); + data_ = gl.MapBufferRange(target_type, 0, + backing_store_->GetLength().GetByteSize(), + GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); initialized_ = true; } 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()) { + ::memcpy(reinterpret_cast(data_) + range.offset, + backing_store_->GetBuffer() + range.offset, range.length); + } else { + gl.BufferSubData(target_type, range.offset, range.length, + backing_store_->GetBuffer() + range.offset); + } dirty_range_ = std::nullopt; } @@ -145,6 +160,9 @@ bool DeviceBufferGLES::SetLabel(std::string_view label, Range range) { } const uint8_t* DeviceBufferGLES::GetBufferData() const { + if (initialized_) { + return reinterpret_cast(data_); + } return backing_store_->GetBuffer(); } @@ -152,7 +170,7 @@ void DeviceBufferGLES::UpdateBufferData( const std::function& update_buffer_data) { if (update_buffer_data) { - update_buffer_data(backing_store_->GetBuffer(), + update_buffer_data(OnGetContents(), backing_store_->GetLength().GetByteSize()); Flush(Range{ 0, static_cast(backing_store_->GetLength().GetByteSize())}); diff --git a/impeller/renderer/backend/gles/device_buffer_gles.h b/impeller/renderer/backend/gles/device_buffer_gles.h index f080d4e3e0ffe..9c16647d85cfc 100644 --- a/impeller/renderer/backend/gles/device_buffer_gles.h +++ b/impeller/renderer/backend/gles/device_buffer_gles.h @@ -51,6 +51,7 @@ class DeviceBufferGLES final mutable std::shared_ptr backing_store_; mutable std::optional dirty_range_ = std::nullopt; mutable bool initialized_ = false; + mutable void* data_ = nullptr; // |DeviceBuffer| uint8_t* OnGetContents() const override; diff --git a/impeller/renderer/backend/gles/proc_table_gles.h b/impeller/renderer/backend/gles/proc_table_gles.h index ccc499af9dcca..3546046d69a50 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); \ @@ -257,6 +259,7 @@ void(glDepthRange)(GLdouble n, GLdouble f); PROC(PopDebugGroupKHR); \ PROC(ObjectLabelKHR); \ PROC(RenderbufferStorageMultisampleEXT); \ + PROC(BufferStorageEXT); \ PROC(GenQueriesEXT); \ PROC(DeleteQueriesEXT); \ PROC(GetQueryObjectui64vEXT); \ 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..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); @@ -463,8 +332,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..a8367a4ccbc7a --- /dev/null +++ b/impeller/renderer/backend/gles/render_pass_gles3.cc @@ -0,0 +1,610 @@ +// 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 { + +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(PipelineRef pipeline) { + pipeline_ = pipeline; +} + +// |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 PipelineGLES& pipeline = PipelineGLES::Cast(*pipeline_); + 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..4855b6ed52bb6 --- /dev/null +++ b/impeller/renderer/backend/gles/render_pass_gles3.h @@ -0,0 +1,143 @@ +// 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/render_pass_utils.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; + + 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; + PipelineRef pipeline_; + + // 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(PipelineRef 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_ 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..869571c5c01d8 --- /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; +} + +} // namespace impeller \ 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_