Vulkan: Implement feedback/history.

This commit is contained in:
Hans-Kristian Arntzen 2016-03-25 15:32:04 +01:00
parent e35e0e0f23
commit 80df588cf0

View File

@ -216,6 +216,9 @@ struct CommonResources
unique_ptr<Buffer> vbo_offscreen, vbo_final;
VkSampler samplers[2];
vector<Texture> origin_history;
vector<Texture> framebuffer_feedback;
VkDevice device;
};
@ -406,9 +409,12 @@ struct vulkan_filter_chain
void set_swapchain_info(const vulkan_filter_chain_swapchain_info &info);
bool init_history();
bool init_feedback();
void update_history(DeferredDisposer &disposer, VkCommandBuffer cmd);
vector<unique_ptr<Framebuffer>> original_history;
bool require_clear = false;
void clear_history_and_feedback(VkCommandBuffer cmd);
void update_feedback_info();
};
vulkan_filter_chain::vulkan_filter_chain(
@ -512,6 +518,27 @@ void vulkan_filter_chain::flush()
execute_deferred();
}
void vulkan_filter_chain::update_feedback_info()
{
if (common.framebuffer_feedback.empty())
return;
for (unsigned i = 0; i < passes.size() - 1; i++)
{
auto fb = passes[i]->get_feedback_framebuffer();
if (!fb)
continue;
auto &source = common.framebuffer_feedback[i];
source.texture.image = fb->get_image();
source.texture.view = fb->get_view();
source.texture.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
source.texture.width = fb->get_size().width;
source.texture.height = fb->get_size().height;
source.filter = passes[i]->get_source_filter();
}
}
bool vulkan_filter_chain::init_history()
{
original_history.clear();
@ -532,10 +559,24 @@ bool vulkan_filter_chain::init_history()
required_images--;
original_history.reserve(required_images);
common.origin_history.clear();
common.origin_history.reserve(passes.size());
for (unsigned i = 0; i < required_images; i++)
{
original_history.emplace_back(new Framebuffer(device, memory_properties,
max_input_size, original_format));
Texture source;
auto &fb = *original_history.back();
source.texture.image = fb.get_image();
source.texture.view = fb.get_view();
source.texture.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
source.texture.width = fb.get_size().width;
source.texture.height = fb.get_size().height;
source.filter = passes.front()->get_source_filter();
common.origin_history.push_back(source);
}
// On first frame, we need to clear the textures to a known state, but we need
@ -544,6 +585,39 @@ bool vulkan_filter_chain::init_history()
return true;
}
bool vulkan_filter_chain::init_feedback()
{
common.framebuffer_feedback.clear();
bool use_feedbacks = false;
// Final pass cannot have feedback.
for (unsigned i = 0; i < passes.size() - 1; i++)
{
bool use_feedback = false;
for (auto &pass : passes)
{
auto &r = pass->get_reflection();
auto &feedbacks = r.semantic_textures[SLANG_TEXTURE_SEMANTIC_PASS_FEEDBACK];
if (i < feedbacks.size() && feedbacks[i].texture)
{
use_feedback = true;
use_feedbacks = true;
break;
}
}
if (use_feedback && !passes[i]->init_feedback())
return false;
}
if (!use_feedbacks)
return true;
common.framebuffer_feedback.resize(passes.size() - 1);
return true;
}
bool vulkan_filter_chain::init()
{
Size2D source = max_input_size;
@ -560,26 +634,36 @@ bool vulkan_filter_chain::init()
if (!init_history())
return false;
if (!init_feedback())
return false;
return true;
}
void vulkan_filter_chain::clear_history_and_feedback(VkCommandBuffer cmd)
{
for (auto &texture : original_history)
texture->clear(cmd);
for (auto &pass : passes)
{
auto *fb = pass->get_feedback_framebuffer();
if (fb)
fb->clear(cmd);
}
}
void vulkan_filter_chain::build_offscreen_passes(VkCommandBuffer cmd,
const VkViewport &vp)
{
// First frame, make sure our history and feedback textures are in a clean state.
if (require_clear)
{
for (auto &texture : original_history)
texture->clear(cmd);
for (auto &pass : passes)
{
auto *fb = pass->get_feedback_framebuffer();
if (fb)
fb->clear(cmd);
}
clear_history_and_feedback(cmd);
require_clear = false;
}
update_feedback_info();
unsigned i;
DeferredDisposer disposer(deferred_calls[current_sync_index]);
const Texture original = {
@ -604,12 +688,13 @@ void vulkan_filter_chain::build_offscreen_passes(VkCommandBuffer cmd,
void vulkan_filter_chain::update_history(DeferredDisposer &disposer, VkCommandBuffer cmd)
{
VkImageLayout src_layout = input_texture.layout;
// Transition input texture to something appropriate.
if (input_texture.layout != VK_IMAGE_LAYOUT_GENERAL)
{
image_layout_transition(cmd,
input_texture.image,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
input_texture.layout,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
0,
VK_ACCESS_TRANSFER_READ_BIT,
@ -637,7 +722,7 @@ void vulkan_filter_chain::update_history(DeferredDisposer &disposer, VkCommandBu
image_layout_transition(cmd,
input_texture.image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
input_texture.layout,
0,
VK_ACCESS_SHADER_READ_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
@ -652,6 +737,13 @@ void vulkan_filter_chain::update_history(DeferredDisposer &disposer, VkCommandBu
void vulkan_filter_chain::build_viewport_pass(
VkCommandBuffer cmd, const VkViewport &vp, const float *mvp)
{
// First frame, make sure our history and feedback textures are in a clean state.
if (require_clear)
{
clear_history_and_feedback(cmd);
require_clear = false;
}
Texture source;
DeferredDisposer disposer(deferred_calls[current_sync_index]);
const Texture original = {