| // 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/entity/inline_pass_context.h" |
| |
| #include <utility> |
| |
| #include "impeller/base/validation.h" |
| #include "impeller/renderer/command_buffer.h" |
| #include "impeller/renderer/formats.h" |
| #include "impeller/renderer/texture_descriptor.h" |
| |
| namespace impeller { |
| |
| InlinePassContext::InlinePassContext(std::shared_ptr<Context> context, |
| const RenderTarget& render_target, |
| uint32_t pass_texture_reads) |
| : context_(std::move(context)), |
| render_target_(render_target), |
| total_pass_reads_(pass_texture_reads) {} |
| |
| InlinePassContext::~InlinePassContext() { |
| EndPass(); |
| } |
| |
| bool InlinePassContext::IsValid() const { |
| return !render_target_.GetColorAttachments().empty(); |
| } |
| |
| bool InlinePassContext::IsActive() const { |
| return pass_ != nullptr; |
| } |
| |
| std::shared_ptr<Texture> InlinePassContext::GetTexture() { |
| if (!IsValid()) { |
| return nullptr; |
| } |
| return render_target_.GetRenderTargetTexture(); |
| } |
| |
| bool InlinePassContext::EndPass() { |
| if (!IsActive()) { |
| return true; |
| } |
| |
| if (!pass_->EncodeCommands()) { |
| return false; |
| } |
| |
| if (!command_buffer_->SubmitCommands()) { |
| return false; |
| } |
| |
| pass_ = nullptr; |
| command_buffer_ = nullptr; |
| |
| return true; |
| } |
| |
| const RenderTarget& InlinePassContext::GetRenderTarget() const { |
| return render_target_; |
| } |
| |
| InlinePassContext::RenderPassResult InlinePassContext::GetRenderPass( |
| uint32_t pass_depth) { |
| if (IsActive()) { |
| return {.pass = pass_}; |
| } |
| |
| /// Create a new render pass if one isn't active. This path will run the first |
| /// time this method is called, but it'll also run if the pass has been |
| /// previously ended via `EndPass`. |
| |
| command_buffer_ = context_->CreateCommandBuffer(); |
| if (!command_buffer_) { |
| VALIDATION_LOG << "Could not create command buffer."; |
| return {}; |
| } |
| |
| if (render_target_.GetColorAttachments().empty()) { |
| VALIDATION_LOG << "Color attachment unexpectedly missing from the " |
| "EntityPass render target."; |
| return {}; |
| } |
| auto color0 = render_target_.GetColorAttachments().find(0)->second; |
| |
| command_buffer_->SetLabel( |
| "EntityPass Command Buffer: Depth=" + std::to_string(pass_depth) + |
| " Count=" + std::to_string(pass_count_)); |
| |
| RenderPassResult result; |
| |
| if (pass_count_ > 0 && color0.resolve_texture) { |
| result.backdrop_texture = color0.resolve_texture; |
| } |
| |
| if (color0.resolve_texture) { |
| color0.load_action = |
| pass_count_ > 0 ? LoadAction::kDontCare : LoadAction::kClear; |
| color0.store_action = StoreAction::kMultisampleResolve; |
| } else { |
| color0.load_action = LoadAction::kClear; |
| color0.store_action = StoreAction::kStore; |
| } |
| |
| #ifndef IMPELLER_ENABLE_VULKAN |
| auto stencil = render_target_.GetStencilAttachment(); |
| if (!stencil.has_value()) { |
| VALIDATION_LOG << "Stencil attachment unexpectedly missing from the " |
| "EntityPass render target."; |
| return {}; |
| } |
| |
| // Only clear the stencil if this is the very first pass of the |
| // layer. |
| stencil->load_action = |
| pass_count_ > 0 ? LoadAction::kLoad : LoadAction::kClear; |
| // If we're on the last pass of the layer, there's no need to store the |
| // stencil because nothing needs to read it. |
| stencil->store_action = pass_count_ == total_pass_reads_ |
| ? StoreAction::kDontCare |
| : StoreAction::kStore; |
| render_target_.SetStencilAttachment(stencil.value()); |
| #else |
| // Touch this variable to avoid a compiler warnings. |
| // This will go away once stencil support is added for vulkan. |
| total_pass_reads_ = 1; |
| #endif |
| |
| render_target_.SetColorAttachment(color0, 0); |
| |
| pass_ = command_buffer_->CreateRenderPass(render_target_); |
| if (!pass_) { |
| VALIDATION_LOG << "Could not create render pass."; |
| return {}; |
| } |
| |
| pass_->SetLabel( |
| "EntityPass Render Pass: Depth=" + std::to_string(pass_depth) + |
| " Count=" + std::to_string(pass_count_)); |
| |
| ++pass_count_; |
| |
| result.pass = pass_; |
| return result; |
| } |
| |
| uint32_t InlinePassContext::GetPassCount() const { |
| return pass_count_; |
| } |
| |
| } // namespace impeller |