blob: 9876a5810e036ab14cda7862daf36a2573b29633 [file] [log] [blame]
// Copyright 2016 The Fuchsia 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 "src/ui/lib/escher/renderer/renderer.h"
#include "src/ui/lib/escher/escher.h"
#include "src/ui/lib/escher/impl/command_buffer_pool.h"
#include "src/ui/lib/escher/impl/image_cache.h"
#include "src/ui/lib/escher/impl/vulkan_utils.h"
#include "src/ui/lib/escher/profiling/timestamp_profiler.h"
#include "src/ui/lib/escher/scene/stage.h"
#include "src/ui/lib/escher/util/stopwatch.h"
#include "src/ui/lib/escher/util/trace_macros.h"
#include "src/ui/lib/escher/vk/framebuffer.h"
#include "src/ui/lib/escher/vk/image.h"
#include "src/ui/lib/escher/vk/texture.h"
namespace escher {
Renderer::Renderer(EscherWeakPtr weak_escher)
: context_(weak_escher->vulkan_context()), escher_(std::move(weak_escher)) {
escher()->IncrementRendererCount();
}
Renderer::~Renderer() { escher()->DecrementRendererCount(); }
Renderer::FrameData::FrameData(const FramePtr& frame_in,
std::shared_ptr<BatchGpuUploader> gpu_uploader_in,
const ImagePtr& output_image_in,
std::pair<TexturePtr, TexturePtr> depth_and_msaa_textures)
: frame(frame_in),
output_image(output_image_in),
depth_texture(std::move(depth_and_msaa_textures.first)),
msaa_texture(std::move(depth_and_msaa_textures.second)),
gpu_uploader(gpu_uploader_in) {}
Renderer::FrameData::~FrameData() = default;
std::pair<TexturePtr, TexturePtr> Renderer::ObtainDepthAndMsaaTextures(
const FramePtr& frame, const ImageInfo& info, uint32_t msaa_sample_count,
vk::Format depth_stencil_format) {
FXL_DCHECK(!depth_buffers_.empty());
// Support for other sample_counts should fairly easy to add, if necessary.
FXL_DCHECK(info.sample_count == 1);
auto index = frame->frame_number() % depth_buffers_.size();
TexturePtr& depth_texture = depth_buffers_[index];
TexturePtr& msaa_texture = msaa_buffers_[index];
const bool realloc_textures =
!depth_texture ||
(depth_texture->image()->use_protected_memory() != frame->use_protected_memory()) ||
info.width != depth_texture->width() || info.height != depth_texture->height() ||
msaa_sample_count != depth_texture->image()->info().sample_count;
if (realloc_textures) {
// Need to generate a new depth buffer.
{
TRACE_DURATION("gfx", "PaperRenderer::ObtainDepthAndMsaaTextures (new depth)");
depth_texture = escher()->NewAttachmentTexture(
depth_stencil_format, info.width, info.height, msaa_sample_count, vk::Filter::eLinear,
vk::ImageUsageFlags(), /*is_transient_attachment=*/false,
/*is_input_attachment=*/false, /*use_unnormalized_coordinates=*/false,
frame->use_protected_memory() ? vk::MemoryPropertyFlagBits::eProtected
: vk::MemoryPropertyFlags());
}
// If the sample count is 1, there is no need for a MSAA buffer.
if (msaa_sample_count == 1) {
msaa_texture = nullptr;
} else {
TRACE_DURATION("gfx", "Renderer::ObtainDepthAndMsaaTextures (new msaa)");
// TODO(SCN-634): use lazy memory allocation and transient attachments
// when available.
msaa_texture = escher()->NewAttachmentTexture(
info.format, info.width, info.height, msaa_sample_count, vk::Filter::eLinear,
vk::ImageUsageFlags(), /*is_transient_attachment=*/false,
/*is_input_attachment=*/false, /*use_unnormalized_coordinates=*/false,
frame->use_protected_memory() ? vk::MemoryPropertyFlagBits::eProtected
: vk::MemoryPropertyFlags()
// TODO(ES-73): , vk::ImageUsageFlagBits::eTransientAttachment
);
frame->cmds()->ImageBarrier(msaa_texture->image(), vk::ImageLayout::eUndefined,
vk::ImageLayout::eColorAttachmentOptimal,
vk::PipelineStageFlagBits::eAllGraphics, vk::AccessFlags(),
vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::AccessFlagBits::eColorAttachmentWrite);
}
}
return {depth_texture, msaa_texture};
}
void Renderer::InitRenderPassInfo(RenderPassInfo* rp, ImageViewAllocator* allocator,
const FrameData& frame_data, vk::Rect2D render_area) {
const ImagePtr& output_image = frame_data.output_image;
const TexturePtr& depth_texture = frame_data.depth_texture;
const TexturePtr& msaa_texture = frame_data.msaa_texture;
rp->render_area = render_area;
static constexpr uint32_t kRenderTargetAttachmentIndex = 0;
static constexpr uint32_t kResolveTargetAttachmentIndex = 1;
{
rp->color_attachments[kRenderTargetAttachmentIndex] = allocator->ObtainImageView(output_image);
rp->num_color_attachments = 1;
// Clear and store color attachment 0, the sole color attachment.
rp->clear_attachments = 1u << kRenderTargetAttachmentIndex;
rp->store_attachments = 1u << kRenderTargetAttachmentIndex;
// NOTE: we don't need to keep |depth_texture| alive explicitly because it
// will be kept alive by the render-pass.
rp->depth_stencil_attachment = depth_texture;
// Standard flags for a depth-testing render-pass that needs to first clear
// the depth image.
rp->op_flags = RenderPassInfo::kClearDepthStencilOp | RenderPassInfo::kOptimalColorLayoutOp |
RenderPassInfo::kOptimalDepthStencilLayoutOp;
rp->clear_color[0].setFloat32({0.f, 0.f, 0.f, 0.f});
// If MSAA is enabled, we need to explicitly specify the sub-pass in order
// to specify the resolve attachment. Otherwise we allow a default subclass
// to be created.
if (msaa_texture) {
FXL_DCHECK(rp->num_color_attachments == 1 && rp->clear_attachments == 1u);
// Move the output image to attachment #1, so that attachment #0 is always
// the attachment that we render into.
rp->color_attachments[kResolveTargetAttachmentIndex] =
std::move(rp->color_attachments[kRenderTargetAttachmentIndex]);
rp->color_attachments[kRenderTargetAttachmentIndex] = msaa_texture;
rp->num_color_attachments = 2;
// Now that the output image is attachment #1, that's the one we need to
// store.
rp->store_attachments = 1u << kResolveTargetAttachmentIndex;
rp->subpasses.push_back(RenderPassInfo::Subpass{
.color_attachments = {kRenderTargetAttachmentIndex},
.input_attachments = {},
.resolve_attachments = {kResolveTargetAttachmentIndex},
.num_color_attachments = 1,
.num_input_attachments = 0,
.num_resolve_attachments = 1,
});
}
}
FXL_DCHECK(rp->Validate());
}
} // namespace escher