blob: 6f2eb4897553a3ba7a2f68d4794ac1ee65c0f246 [file] [log] [blame]
// Copyright 2017 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 "lib/escher/renderer/shadow_map_renderer.h"
#include "lib/escher/impl/command_buffer.h"
#include "lib/escher/impl/image_cache.h"
#include "lib/escher/impl/model_data.h"
#include "lib/escher/impl/model_display_list.h"
#include "lib/escher/impl/model_renderer.h"
#include "lib/escher/impl/model_shadow_map_pass.h"
#include "lib/escher/impl/vulkan_utils.h"
#include "lib/escher/math/rotations.h"
#include "lib/escher/scene/stage.h"
#include "lib/escher/util/image_utils.h"
#include "lib/escher/vk/framebuffer.h"
#include "lib/escher/vk/image.h"
namespace escher {
ShadowMapRendererPtr ShadowMapRenderer::New(
EscherWeakPtr escher, const impl::ModelDataPtr& model_data,
const impl::ModelRendererPtr& model_renderer) {
auto* resource_recycler = escher->resource_recycler();
constexpr vk::Format kShadowMapFormat = vk::Format::eR16Unorm;
vk::Format depth_format = ESCHER_CHECKED_VK_RESULT(
impl::GetSupportedDepthStencilFormat(escher->vk_physical_device()));
return fxl::MakeRefCounted<ShadowMapRenderer>(
std::move(escher), kShadowMapFormat, depth_format, model_data,
model_renderer,
fxl::MakeRefCounted<impl::ModelShadowMapPass>(
resource_recycler, model_data, kShadowMapFormat, depth_format,
/* sample_count= */ 1));
}
ShadowMapRenderer::ShadowMapRenderer(
EscherWeakPtr weak_escher, vk::Format shadow_map_format,
vk::Format depth_format, const impl::ModelDataPtr& model_data,
const impl::ModelRendererPtr& model_renderer,
const impl::ModelRenderPassPtr& model_render_pass)
: Renderer(std::move(weak_escher)),
shadow_map_format_(shadow_map_format),
depth_format_(depth_format),
model_data_(model_data),
model_renderer_(model_renderer),
shadow_map_pass_(model_render_pass),
clear_values_(
{vk::ClearColorValue(std::array<float, 4>{{0.f, 0.f, 0.f, 1.f}}),
vk::ClearDepthStencilValue(1.f, 0.f)}) {}
ShadowMapRenderer::~ShadowMapRenderer() { escher()->Cleanup(); }
ShadowMapPtr ShadowMapRenderer::GenerateDirectionalShadowMap(
const FramePtr& frame, const Stage& stage, const Model& model,
const glm::vec3& direction, const glm::vec3& light_color) {
auto command_buffer = frame->command_buffer();
auto camera =
Camera::NewForDirectionalShadowMap(stage.viewing_volume(), direction);
Stage shadow_stage;
ComputeShadowStageFromSceneStage(stage, shadow_stage);
auto width = static_cast<uint32_t>(shadow_stage.width());
auto height = static_cast<uint32_t>(shadow_stage.height());
auto color_image = GetTransitionedColorImage(command_buffer, width, height);
auto depth_image = GetTransitionedDepthImage(command_buffer, width, height);
DrawShadowPass(command_buffer, shadow_stage, model, camera, color_image,
depth_image);
frame->AddTimestamp("generated shadow map");
return SubmitPartialFrameAndBuildShadowMap<ShadowMap>(
frame, camera, color_image, light_color);
}
ImagePtr ShadowMapRenderer::GetTransitionedColorImage(
impl::CommandBuffer* command_buffer, uint32_t width, uint32_t height) {
ImageInfo info;
info.format = shadow_map_format_;
info.width = width;
info.height = height;
info.sample_count = 1;
info.usage = vk::ImageUsageFlagBits::eColorAttachment |
vk::ImageUsageFlagBits::eSampled |
vk::ImageUsageFlagBits::eTransferSrc |
vk::ImageUsageFlagBits::eStorage;
auto color_image = escher()->image_cache()->NewImage(info);
command_buffer->TransitionImageLayout(
color_image, vk::ImageLayout::eUndefined,
vk::ImageLayout::eColorAttachmentOptimal);
return color_image;
}
ImagePtr ShadowMapRenderer::GetTransitionedDepthImage(
impl::CommandBuffer* command_buffer, uint32_t width, uint32_t height) {
auto depth_image =
image_utils::NewDepthImage(escher()->image_cache(), depth_format_, width,
height, vk::ImageUsageFlags());
command_buffer->TransitionImageLayout(
depth_image, vk::ImageLayout::eUndefined,
vk::ImageLayout::eDepthStencilAttachmentOptimal);
return depth_image;
}
void ShadowMapRenderer::DrawShadowPass(impl::CommandBuffer* command_buffer,
const Stage& shadow_stage,
const Model& model, const Camera& camera,
ImagePtr& color_image,
ImagePtr& depth_image) {
auto fb = fxl::MakeRefCounted<Framebuffer>(escher(), color_image, depth_image,
shadow_map_pass_->vk());
auto display_list = model_renderer_->CreateDisplayList(
shadow_stage, model, camera, shadow_map_pass_,
impl::ModelDisplayListFlag::kNull, 1.f, TexturePtr(), mat4(1.f),
vec3(0.f), vec3(0.f), command_buffer);
command_buffer->KeepAlive(fb);
command_buffer->KeepAlive(display_list);
command_buffer->BeginRenderPass(
shadow_map_pass_, fb, clear_values_,
camera.viewport().vk_rect_2d(fb->width(), fb->height()));
model_renderer_->Draw(shadow_stage, display_list, command_buffer,
camera.viewport());
command_buffer->EndRenderPass();
}
void ShadowMapRenderer::ComputeShadowStageFromSceneStage(
const Stage& scene_stage, Stage& shadow_stage) {
uint32_t shadow_size = static_cast<uint32_t>(
.75f * std::max(scene_stage.width(), scene_stage.height()));
shadow_stage.set_viewing_volume(escher::ViewingVolume(
shadow_size, shadow_size, scene_stage.viewing_volume().top(),
scene_stage.viewing_volume().bottom()));
shadow_stage.set_key_light(scene_stage.key_light());
shadow_stage.set_fill_light(scene_stage.fill_light());
}
} // namespace escher