mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-05 06:21:26 +12:00
vulkan: Implement overlay shader passes
- Implements vk::overlay_pass and vk::depth_convert_pass - Also added a sanity check in RSX core for depth replace shaders
This commit is contained in:
parent
680ca1d12a
commit
ccc0383f75
6 changed files with 462 additions and 85 deletions
|
@ -116,7 +116,7 @@ namespace gl
|
||||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||||
glDepthMask(depth_target ? GL_TRUE : GL_FALSE);
|
glDepthMask(depth_target ? GL_TRUE : GL_FALSE);
|
||||||
|
|
||||||
// AMD driver bug, disabling depth test doesnt work when doing depth replace (gl_FragDepth writes still go through the depth test)
|
// Disabling depth test will also disable depth writes which is not desired
|
||||||
glDepthFunc(GL_ALWAYS);
|
glDepthFunc(GL_ALWAYS);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
|
|
@ -1417,6 +1417,16 @@ namespace rsx
|
||||||
}
|
}
|
||||||
|
|
||||||
result.set_texture_dimension(texture_dimensions);
|
result.set_texture_dimension(texture_dimensions);
|
||||||
|
|
||||||
|
//Sanity checks
|
||||||
|
if (result.ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT)
|
||||||
|
{
|
||||||
|
//Check that the depth stage is not disabled
|
||||||
|
if (!rsx::method_registers.depth_test_enabled())
|
||||||
|
{
|
||||||
|
LOG_ERROR(RSX, "FS exports depth component but depth test is disabled (INVALID_OPERATION)");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread::get_current_fragment_program_legacy(std::function<std::tuple<bool, u16>(u32, fragment_texture&, bool)> get_surface_info)
|
void thread::get_current_fragment_program_legacy(std::function<std::tuple<bool, u16>(u32, fragment_texture&, bool)> get_surface_info)
|
||||||
|
|
|
@ -644,6 +644,9 @@ VKGSRender::VKGSRender() : GSRender()
|
||||||
m_text_writer->init(*m_device, m_memory_type_mapping, m_render_passes[idx]);
|
m_text_writer->init(*m_device, m_memory_type_mapping, m_render_passes[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_depth_converter.reset(new vk::depth_convert_pass());
|
||||||
|
m_depth_converter->create(*m_device);
|
||||||
|
|
||||||
m_prog_buffer.reset(new VKProgramBuffer(m_render_passes.data()));
|
m_prog_buffer.reset(new VKProgramBuffer(m_render_passes.data()));
|
||||||
|
|
||||||
if (g_cfg.video.disable_vertex_cache)
|
if (g_cfg.video.disable_vertex_cache)
|
||||||
|
@ -754,6 +757,10 @@ VKGSRender::~VKGSRender()
|
||||||
//Overlay text handler
|
//Overlay text handler
|
||||||
m_text_writer.reset();
|
m_text_writer.reset();
|
||||||
|
|
||||||
|
//RGBA->depth cast helper
|
||||||
|
m_depth_converter->destroy();
|
||||||
|
m_depth_converter.reset();
|
||||||
|
|
||||||
//Pipeline descriptors
|
//Pipeline descriptors
|
||||||
vkDestroyPipelineLayout(*m_device, pipeline_layout, nullptr);
|
vkDestroyPipelineLayout(*m_device, pipeline_layout, nullptr);
|
||||||
vkDestroyDescriptorSetLayout(*m_device, descriptor_layouts, nullptr);
|
vkDestroyDescriptorSetLayout(*m_device, descriptor_layouts, nullptr);
|
||||||
|
@ -1246,6 +1253,96 @@ void VKGSRender::end()
|
||||||
std::chrono::time_point<steady_clock> program_stop = steady_clock::now();
|
std::chrono::time_point<steady_clock> program_stop = steady_clock::now();
|
||||||
m_setup_time += std::chrono::duration_cast<std::chrono::microseconds>(program_stop - program_start).count();
|
m_setup_time += std::chrono::duration_cast<std::chrono::microseconds>(program_stop - program_start).count();
|
||||||
|
|
||||||
|
textures_start = program_stop;
|
||||||
|
|
||||||
|
for (int i = 0; i < rsx::limits::fragment_textures_count; ++i)
|
||||||
|
{
|
||||||
|
if (m_program->has_uniform("tex" + std::to_string(i)))
|
||||||
|
{
|
||||||
|
if (!rsx::method_registers.fragment_textures[i].enabled())
|
||||||
|
{
|
||||||
|
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "tex" + std::to_string(i), m_current_frame->descriptor_set);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sampler_state = static_cast<vk::texture_cache::sampled_image_descriptor*>(fs_sampler_state[i].get());
|
||||||
|
auto image_ptr = sampler_state->image_handle;
|
||||||
|
|
||||||
|
if (!image_ptr && sampler_state->external_subresource_desc.external_handle)
|
||||||
|
{
|
||||||
|
//Requires update, copy subresource
|
||||||
|
image_ptr = m_texture_cache.create_temporary_subresource(*m_current_command_buffer, sampler_state->external_subresource_desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!image_ptr)
|
||||||
|
{
|
||||||
|
LOG_ERROR(RSX, "Texture upload failed to texture index %d. Binding null sampler.", i);
|
||||||
|
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "tex" + std::to_string(i), m_current_frame->descriptor_set);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_program->bind_uniform({ fs_sampler_handles[i]->value, image_ptr->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "tex" + std::to_string(i), m_current_frame->descriptor_set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < rsx::limits::vertex_textures_count; ++i)
|
||||||
|
{
|
||||||
|
if (m_program->has_uniform("vtex" + std::to_string(i)))
|
||||||
|
{
|
||||||
|
if (!rsx::method_registers.vertex_textures[i].enabled())
|
||||||
|
{
|
||||||
|
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "vtex" + std::to_string(i), m_current_frame->descriptor_set);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sampler_state = static_cast<vk::texture_cache::sampled_image_descriptor*>(vs_sampler_state[i].get());
|
||||||
|
auto image_ptr = sampler_state->image_handle;
|
||||||
|
|
||||||
|
if (!image_ptr && sampler_state->external_subresource_desc.external_handle)
|
||||||
|
{
|
||||||
|
image_ptr = m_texture_cache.create_temporary_subresource(*m_current_command_buffer, sampler_state->external_subresource_desc);
|
||||||
|
m_vertex_textures_dirty[i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!image_ptr)
|
||||||
|
{
|
||||||
|
LOG_ERROR(RSX, "Texture upload failed to vtexture index %d. Binding null sampler.", i);
|
||||||
|
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "vtex" + std::to_string(i), m_current_frame->descriptor_set);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_program->bind_uniform({ vs_sampler_handles[i]->value, image_ptr->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "vtex" + std::to_string(i), m_current_frame->descriptor_set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textures_end = steady_clock::now();
|
||||||
|
m_textures_upload_time += std::chrono::duration_cast<std::chrono::microseconds>(textures_end - textures_start).count();
|
||||||
|
|
||||||
|
//While vertex upload is an interruptible process, if we made it this far, there's no need to sync anything that occurs past this point
|
||||||
|
//Only textures are synchronized tightly with the GPU and they have been read back above
|
||||||
|
vk::enter_uninterruptible();
|
||||||
|
|
||||||
|
auto ds = std::get<1>(m_rtts.m_bound_depth_stencil);
|
||||||
|
|
||||||
|
//Check for data casts
|
||||||
|
if (ds && ds->old_contents)
|
||||||
|
{
|
||||||
|
if (ds->old_contents->info.format == VK_FORMAT_B8G8R8A8_UNORM)
|
||||||
|
{
|
||||||
|
auto rp = vk::get_render_pass_location(VK_FORMAT_UNDEFINED, ds->info.format, 0);
|
||||||
|
auto render_pass = m_render_passes[rp];
|
||||||
|
m_depth_converter->run(*m_current_command_buffer, ds->width(), ds->height(), ds, ds->old_contents->get_view(), render_pass, m_framebuffers_to_clean);
|
||||||
|
|
||||||
|
ds->old_contents = nullptr;
|
||||||
|
ds->dirty = false;
|
||||||
|
}
|
||||||
|
else if (!g_cfg.video.strict_rendering_mode)
|
||||||
|
{
|
||||||
|
//Clear this to avoid dereferencing stale ptr
|
||||||
|
ds->old_contents = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (g_cfg.video.strict_rendering_mode)
|
if (g_cfg.video.strict_rendering_mode)
|
||||||
{
|
{
|
||||||
auto copy_rtt_contents = [&](vk::render_target* surface)
|
auto copy_rtt_contents = [&](vk::render_target* surface)
|
||||||
|
@ -1295,82 +1392,12 @@ void VKGSRender::end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil))
|
if (ds && ds->old_contents)
|
||||||
{
|
{
|
||||||
if (ds->old_contents != nullptr)
|
copy_rtt_contents(ds);
|
||||||
copy_rtt_contents(ds);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textures_start = steady_clock::now();
|
|
||||||
|
|
||||||
for (int i = 0; i < rsx::limits::fragment_textures_count; ++i)
|
|
||||||
{
|
|
||||||
if (m_program->has_uniform("tex" + std::to_string(i)))
|
|
||||||
{
|
|
||||||
if (!rsx::method_registers.fragment_textures[i].enabled())
|
|
||||||
{
|
|
||||||
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "tex" + std::to_string(i), m_current_frame->descriptor_set);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sampler_state = static_cast<vk::texture_cache::sampled_image_descriptor*>(fs_sampler_state[i].get());
|
|
||||||
auto image_ptr = sampler_state->image_handle;
|
|
||||||
|
|
||||||
if (!image_ptr && sampler_state->external_subresource_desc.external_handle)
|
|
||||||
{
|
|
||||||
//Requires update, copy subresource
|
|
||||||
image_ptr = m_texture_cache.create_temporary_subresource(*m_current_command_buffer, sampler_state->external_subresource_desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!image_ptr)
|
|
||||||
{
|
|
||||||
LOG_ERROR(RSX, "Texture upload failed to texture index %d. Binding null sampler.", i);
|
|
||||||
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "tex" + std::to_string(i), m_current_frame->descriptor_set);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_program->bind_uniform({ fs_sampler_handles[i]->value, image_ptr->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "tex" + std::to_string(i), m_current_frame->descriptor_set);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < rsx::limits::vertex_textures_count; ++i)
|
|
||||||
{
|
|
||||||
if (m_program->has_uniform("vtex" + std::to_string(i)))
|
|
||||||
{
|
|
||||||
if (!rsx::method_registers.vertex_textures[i].enabled())
|
|
||||||
{
|
|
||||||
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "vtex" + std::to_string(i), m_current_frame->descriptor_set);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sampler_state = static_cast<vk::texture_cache::sampled_image_descriptor*>(vs_sampler_state[i].get());
|
|
||||||
auto image_ptr = sampler_state->image_handle;
|
|
||||||
|
|
||||||
if (!image_ptr && sampler_state->external_subresource_desc.external_handle)
|
|
||||||
{
|
|
||||||
image_ptr = m_texture_cache.create_temporary_subresource(*m_current_command_buffer, sampler_state->external_subresource_desc);
|
|
||||||
m_vertex_textures_dirty[i] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!image_ptr)
|
|
||||||
{
|
|
||||||
LOG_ERROR(RSX, "Texture upload failed to vtexture index %d. Binding null sampler.", i);
|
|
||||||
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "vtex" + std::to_string(i), m_current_frame->descriptor_set);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_program->bind_uniform({ vs_sampler_handles[i]->value, image_ptr->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "vtex" + std::to_string(i), m_current_frame->descriptor_set);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
textures_end = steady_clock::now();
|
|
||||||
m_textures_upload_time += std::chrono::duration_cast<std::chrono::microseconds>(textures_end - textures_start).count();
|
|
||||||
|
|
||||||
//While vertex upload is an interruptible process, if we made it this far, there's no need to sync anything that occurs past this point
|
|
||||||
//Only textures are synchronized tightly with the GPU and they have been read back above
|
|
||||||
vk::enter_uninterruptible();
|
|
||||||
|
|
||||||
update_draw_state();
|
update_draw_state();
|
||||||
|
|
||||||
begin_render_pass();
|
begin_render_pass();
|
||||||
|
@ -1383,20 +1410,17 @@ void VKGSRender::end()
|
||||||
buffers_to_clear.reserve(4);
|
buffers_to_clear.reserve(4);
|
||||||
const auto targets = rsx::utility::get_rtt_indexes(rsx::method_registers.surface_color_target());
|
const auto targets = rsx::utility::get_rtt_indexes(rsx::method_registers.surface_color_target());
|
||||||
|
|
||||||
if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil))
|
if (ds && ds->dirty)
|
||||||
{
|
{
|
||||||
if (ds->dirty)
|
//Clear this surface before drawing on it
|
||||||
{
|
VkClearValue depth_clear_value;
|
||||||
//Clear this surface before drawing on it
|
depth_clear_value.depthStencil.depth = 1.f;
|
||||||
VkClearValue depth_clear_value;
|
depth_clear_value.depthStencil.stencil = 255;
|
||||||
depth_clear_value.depthStencil.depth = 1.f;
|
|
||||||
depth_clear_value.depthStencil.stencil = 255;
|
|
||||||
|
|
||||||
VkClearAttachment clear_desc = { ds->attachment_aspect_flag, 0, depth_clear_value };
|
VkClearAttachment clear_desc = { ds->attachment_aspect_flag, 0, depth_clear_value };
|
||||||
buffers_to_clear.push_back(clear_desc);
|
buffers_to_clear.push_back(clear_desc);
|
||||||
|
|
||||||
ds->dirty = false;
|
ds->dirty = false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int index = 0; index < targets.size(); ++index)
|
for (int index = 0; index < targets.size(); ++index)
|
||||||
|
@ -1939,6 +1963,8 @@ void VKGSRender::process_swap_request(frame_context_t *ctx, bool free_resources)
|
||||||
m_text_writer->reset_descriptors();
|
m_text_writer->reset_descriptors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_depth_converter->free_resources();
|
||||||
|
|
||||||
ctx->buffer_views_to_clean.clear();
|
ctx->buffer_views_to_clean.clear();
|
||||||
ctx->samplers_to_clean.clear();
|
ctx->samplers_to_clean.clear();
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "VKRenderTargets.h"
|
#include "VKRenderTargets.h"
|
||||||
#include "VKFormats.h"
|
#include "VKFormats.h"
|
||||||
#include "VKTextOut.h"
|
#include "VKTextOut.h"
|
||||||
|
#include "VKOverlays.h"
|
||||||
#include "restore_new.h"
|
#include "restore_new.h"
|
||||||
#include "define_new_memleakdetect.h"
|
#include "define_new_memleakdetect.h"
|
||||||
#include "VKProgramBuffer.h"
|
#include "VKProgramBuffer.h"
|
||||||
|
@ -134,6 +135,7 @@ private:
|
||||||
std::unique_ptr<vk::buffer_view> null_buffer_view;
|
std::unique_ptr<vk::buffer_view> null_buffer_view;
|
||||||
|
|
||||||
std::unique_ptr<vk::text_writer> m_text_writer;
|
std::unique_ptr<vk::text_writer> m_text_writer;
|
||||||
|
std::unique_ptr<vk::depth_convert_pass> m_depth_converter;
|
||||||
|
|
||||||
std::mutex m_sampler_mutex;
|
std::mutex m_sampler_mutex;
|
||||||
u64 surface_store_tag = 0;
|
u64 surface_store_tag = 0;
|
||||||
|
|
|
@ -2,11 +2,348 @@
|
||||||
#include "VKHelpers.h"
|
#include "VKHelpers.h"
|
||||||
#include "VKVertexProgram.h"
|
#include "VKVertexProgram.h"
|
||||||
#include "VKFragmentProgram.h"
|
#include "VKFragmentProgram.h"
|
||||||
|
#include "VKRenderTargets.h"
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
|
//TODO: Refactor text print class to inherit from this base class
|
||||||
struct overlay_pass
|
struct overlay_pass
|
||||||
{
|
{
|
||||||
//TODO
|
VKVertexProgram m_vertex_shader;
|
||||||
|
VKFragmentProgram m_fragment_shader;
|
||||||
|
|
||||||
|
vk::descriptor_pool m_descriptor_pool;
|
||||||
|
VkDescriptorSet m_descriptor_set = nullptr;
|
||||||
|
VkDescriptorSetLayout m_descriptor_layout = nullptr;
|
||||||
|
VkPipelineLayout m_pipeline_layout = nullptr;
|
||||||
|
u32 m_used_descriptors = 0;
|
||||||
|
|
||||||
|
std::unordered_map<VkRenderPass, std::unique_ptr<vk::glsl::program>> m_program_cache;
|
||||||
|
std::unique_ptr<vk::sampler> m_sampler;
|
||||||
|
std::unique_ptr<vk::framebuffer> m_draw_fbo;
|
||||||
|
vk::render_device* m_device = nullptr;
|
||||||
|
|
||||||
|
std::string vs_src;
|
||||||
|
std::string fs_src;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int color_attachments = 0;
|
||||||
|
bool write_color = true;
|
||||||
|
bool write_depth = true;
|
||||||
|
bool no_depth_test = true;
|
||||||
|
}
|
||||||
|
renderpass_config;
|
||||||
|
|
||||||
|
bool initialized = false;
|
||||||
|
bool compiled = false;
|
||||||
|
|
||||||
|
void init_descriptors()
|
||||||
|
{
|
||||||
|
VkDescriptorPoolSize descriptor_pools[1] =
|
||||||
|
{
|
||||||
|
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 120 },
|
||||||
|
};
|
||||||
|
|
||||||
|
//Reserve descriptor pools
|
||||||
|
m_descriptor_pool.create(*m_device, descriptor_pools, 1);
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutBinding bindings[1] = {};
|
||||||
|
|
||||||
|
bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
bindings[0].descriptorCount = 1;
|
||||||
|
bindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
bindings[0].binding = 0;
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutCreateInfo infos = {};
|
||||||
|
infos.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
|
infos.pBindings = bindings;
|
||||||
|
infos.bindingCount = 1;
|
||||||
|
|
||||||
|
CHECK_RESULT(vkCreateDescriptorSetLayout(*m_device, &infos, nullptr, &m_descriptor_layout));
|
||||||
|
|
||||||
|
VkPipelineLayoutCreateInfo layout_info = {};
|
||||||
|
layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
layout_info.setLayoutCount = 1;
|
||||||
|
layout_info.pSetLayouts = &m_descriptor_layout;
|
||||||
|
|
||||||
|
CHECK_RESULT(vkCreatePipelineLayout(*m_device, &layout_info, nullptr, &m_pipeline_layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::glsl::program* build_pipeline(VkRenderPass render_pass)
|
||||||
|
{
|
||||||
|
if (!compiled)
|
||||||
|
{
|
||||||
|
m_vertex_shader.shader = vs_src;
|
||||||
|
m_vertex_shader.Compile();
|
||||||
|
|
||||||
|
m_fragment_shader.shader = fs_src;
|
||||||
|
m_fragment_shader.Compile();
|
||||||
|
|
||||||
|
compiled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo shader_stages[2] = {};
|
||||||
|
shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
shader_stages[0].module = m_vertex_shader.handle;
|
||||||
|
shader_stages[0].pName = "main";
|
||||||
|
|
||||||
|
shader_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
shader_stages[1].module = m_fragment_shader.handle;
|
||||||
|
shader_stages[1].pName = "main";
|
||||||
|
|
||||||
|
VkDynamicState dynamic_state_descriptors[VK_DYNAMIC_STATE_RANGE_SIZE] = {};
|
||||||
|
VkPipelineDynamicStateCreateInfo dynamic_state_info = {};
|
||||||
|
dynamic_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||||
|
dynamic_state_descriptors[dynamic_state_info.dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT;
|
||||||
|
dynamic_state_descriptors[dynamic_state_info.dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR;
|
||||||
|
dynamic_state_info.pDynamicStates = dynamic_state_descriptors;
|
||||||
|
|
||||||
|
VkPipelineVertexInputStateCreateInfo vi = {};
|
||||||
|
vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
|
|
||||||
|
VkPipelineViewportStateCreateInfo vp = {};
|
||||||
|
vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||||
|
vp.scissorCount = 1;
|
||||||
|
vp.viewportCount = 1;
|
||||||
|
|
||||||
|
VkPipelineMultisampleStateCreateInfo ms = {};
|
||||||
|
ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||||
|
ms.pSampleMask = NULL;
|
||||||
|
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo ia = {};
|
||||||
|
ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||||
|
ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
|
||||||
|
|
||||||
|
VkPipelineRasterizationStateCreateInfo rs = {};
|
||||||
|
rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||||
|
rs.lineWidth = 1.f;
|
||||||
|
rs.polygonMode = VK_POLYGON_MODE_FILL;
|
||||||
|
|
||||||
|
VkPipelineColorBlendAttachmentState att = {};
|
||||||
|
if (renderpass_config.write_color)
|
||||||
|
att.colorWriteMask = 0xf;
|
||||||
|
|
||||||
|
VkPipelineColorBlendStateCreateInfo cs = {};
|
||||||
|
cs.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||||
|
cs.attachmentCount = renderpass_config.color_attachments;
|
||||||
|
cs.pAttachments = &att;
|
||||||
|
|
||||||
|
VkPipelineDepthStencilStateCreateInfo ds = {};
|
||||||
|
ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||||
|
ds.depthWriteEnable = renderpass_config.write_depth? VK_TRUE: VK_FALSE;
|
||||||
|
ds.depthTestEnable = VK_TRUE;
|
||||||
|
ds.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
|
|
||||||
|
VkPipeline pipeline;
|
||||||
|
VkGraphicsPipelineCreateInfo info = {};
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||||
|
info.pVertexInputState = &vi;
|
||||||
|
info.pInputAssemblyState = &ia;
|
||||||
|
info.pRasterizationState = &rs;
|
||||||
|
info.pColorBlendState = &cs;
|
||||||
|
info.pMultisampleState = &ms;
|
||||||
|
info.pViewportState = &vp;
|
||||||
|
info.pDepthStencilState = &ds;
|
||||||
|
info.stageCount = 2;
|
||||||
|
info.pStages = shader_stages;
|
||||||
|
info.pDynamicState = &dynamic_state_info;
|
||||||
|
info.layout = m_pipeline_layout;
|
||||||
|
info.basePipelineIndex = -1;
|
||||||
|
info.basePipelineHandle = VK_NULL_HANDLE;
|
||||||
|
info.renderPass = render_pass;
|
||||||
|
|
||||||
|
CHECK_RESULT(vkCreateGraphicsPipelines(*m_device, nullptr, 1, &info, NULL, &pipeline));
|
||||||
|
|
||||||
|
const std::vector<vk::glsl::program_input> unused;
|
||||||
|
std::vector<vk::glsl::program_input> fs_inputs;
|
||||||
|
fs_inputs.push_back({ ::glsl::program_domain::glsl_fragment_program, vk::glsl::program_input_type::input_type_texture, {}, {}, 0, "fs0"});
|
||||||
|
auto program = std::make_unique<vk::glsl::program>(*m_device, pipeline, unused, fs_inputs);
|
||||||
|
auto result = program.get();
|
||||||
|
m_program_cache[render_pass] = std::move(program);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_program(vk::command_buffer cmd, VkRenderPass pass, vk::image_view *src)
|
||||||
|
{
|
||||||
|
vk::glsl::program *program = nullptr;
|
||||||
|
auto found = m_program_cache.find(pass);
|
||||||
|
if (found != m_program_cache.end())
|
||||||
|
program = found->second.get();
|
||||||
|
else
|
||||||
|
program = build_pipeline(pass);
|
||||||
|
|
||||||
|
verify(HERE), m_used_descriptors < 120;
|
||||||
|
|
||||||
|
VkDescriptorSetAllocateInfo alloc_info = {};
|
||||||
|
alloc_info.descriptorPool = m_descriptor_pool;
|
||||||
|
alloc_info.descriptorSetCount = 1;
|
||||||
|
alloc_info.pSetLayouts = &m_descriptor_layout;
|
||||||
|
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
|
|
||||||
|
CHECK_RESULT(vkAllocateDescriptorSets(*m_device, &alloc_info, &m_descriptor_set));
|
||||||
|
m_used_descriptors++;
|
||||||
|
|
||||||
|
if (!m_sampler)
|
||||||
|
{
|
||||||
|
m_sampler = std::make_unique<vk::sampler>(*m_device,
|
||||||
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
|
||||||
|
VK_FALSE, 0.f, 1.f, 0.f, 0.f, VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorImageInfo info = { m_sampler->value, src->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
|
||||||
|
program->bind_uniform(info, "fs0", m_descriptor_set);
|
||||||
|
|
||||||
|
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, program->pipeline);
|
||||||
|
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, 1, &m_descriptor_set, 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void create(vk::render_device &dev)
|
||||||
|
{
|
||||||
|
if (!initialized)
|
||||||
|
{
|
||||||
|
m_device = &dev;
|
||||||
|
init_descriptors();
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy()
|
||||||
|
{
|
||||||
|
if (initialized)
|
||||||
|
{
|
||||||
|
m_program_cache.clear();
|
||||||
|
m_sampler.reset();
|
||||||
|
|
||||||
|
vkDestroyDescriptorSetLayout(*m_device, m_descriptor_layout, nullptr);
|
||||||
|
vkDestroyPipelineLayout(*m_device, m_pipeline_layout, nullptr);
|
||||||
|
m_descriptor_pool.destroy();
|
||||||
|
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_resources()
|
||||||
|
{
|
||||||
|
if (m_used_descriptors == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vkResetDescriptorPool(*m_device, m_descriptor_pool, 0);
|
||||||
|
m_used_descriptors = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::framebuffer* get_framebuffer(vk::image* target, VkRenderPass render_pass, std::list<std::unique_ptr<vk::framebuffer_holder>>& framebuffer_resources)
|
||||||
|
{
|
||||||
|
std::vector<vk::image*> test = {target};
|
||||||
|
for (auto It = framebuffer_resources.begin(); It != framebuffer_resources.end(); It++)
|
||||||
|
{
|
||||||
|
auto fbo = It->get();
|
||||||
|
if (fbo->matches(test, target->width(), target->height()))
|
||||||
|
{
|
||||||
|
fbo->deref_count = 0;
|
||||||
|
return fbo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//No match, create new fbo and add to the list
|
||||||
|
std::vector<std::unique_ptr<vk::image_view>> views;
|
||||||
|
VkComponentMapping mapping = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A};
|
||||||
|
VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||||
|
|
||||||
|
switch (target->info.format)
|
||||||
|
{
|
||||||
|
case VK_FORMAT_D16_UNORM:
|
||||||
|
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||||
|
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
||||||
|
range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; //We are only writing to depth
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto view = std::make_unique<vk::image_view>(*m_device, target->value, VK_IMAGE_VIEW_TYPE_2D, target->info.format, mapping, range);
|
||||||
|
views.push_back(std::move(view));
|
||||||
|
|
||||||
|
auto fbo = std::make_unique<vk::framebuffer_holder>(*m_device, render_pass, target->width(), target->height(), std::move(views));
|
||||||
|
auto result = fbo.get();
|
||||||
|
framebuffer_resources.push_back(std::move(fbo));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(vk::command_buffer &cmd, u16 w, u16 h, vk::image* target, vk::image_view* src, VkRenderPass render_pass, std::list<std::unique_ptr<vk::framebuffer_holder>>& framebuffer_resources)
|
||||||
|
{
|
||||||
|
vk::framebuffer *fbo = get_framebuffer(target, render_pass, framebuffer_resources);
|
||||||
|
|
||||||
|
VkViewport vp{};
|
||||||
|
vp.width = (f32)w;
|
||||||
|
vp.height = (f32)h;
|
||||||
|
vp.minDepth = 0.f;
|
||||||
|
vp.maxDepth = 1.f;
|
||||||
|
vkCmdSetViewport(cmd, 0, 1, &vp);
|
||||||
|
|
||||||
|
VkRect2D vs = { { 0, 0 },{ 0u + w, 0u + h } };
|
||||||
|
vkCmdSetScissor(cmd, 0, 1, &vs);
|
||||||
|
|
||||||
|
load_program(cmd, render_pass, src);
|
||||||
|
|
||||||
|
VkRenderPassBeginInfo rp_begin = {};
|
||||||
|
rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
|
rp_begin.renderPass = render_pass;
|
||||||
|
rp_begin.framebuffer = fbo->value;
|
||||||
|
rp_begin.renderArea.offset.x = 0;
|
||||||
|
rp_begin.renderArea.offset.y = 0;
|
||||||
|
rp_begin.renderArea.extent.width = w;
|
||||||
|
rp_begin.renderArea.extent.height = h;
|
||||||
|
|
||||||
|
vkCmdBeginRenderPass(cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
vkCmdDraw(cmd, 4, 1, 0, 0);
|
||||||
|
vkCmdEndRenderPass(cmd);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct depth_convert_pass : public overlay_pass
|
||||||
|
{
|
||||||
|
depth_convert_pass()
|
||||||
|
{
|
||||||
|
vs_src =
|
||||||
|
{
|
||||||
|
"#version 450\n"
|
||||||
|
"#extension GL_ARB_separate_shader_objects : enable\n"
|
||||||
|
"layout(location=0) out vec2 tc0;\n"
|
||||||
|
"\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" vec2 positions[] = {vec2(-1., -1.), vec2(1., -1.), vec2(-1., 1.), vec2(1., 1.)};\n"
|
||||||
|
" vec2 coords[] = {vec2(0., 0.), vec2(1., 0.), vec2(0., 1.), vec2(1., 1.)};\n"
|
||||||
|
" gl_Position = vec4(positions[gl_VertexIndex % 4], 0., 1.);\n"
|
||||||
|
" tc0 = coords[gl_VertexIndex % 4];\n"
|
||||||
|
"}\n"
|
||||||
|
};
|
||||||
|
|
||||||
|
fs_src =
|
||||||
|
{
|
||||||
|
"#version 420\n"
|
||||||
|
"#extension GL_ARB_separate_shader_objects : enable\n"
|
||||||
|
"layout(set=0, binding=0) uniform sampler2D fs0;\n"
|
||||||
|
"layout(location=0) in vec2 tc0;\n"
|
||||||
|
"\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" vec4 rgba_in = texture(fs0, tc0);\n"
|
||||||
|
" uint raw_value = uint(rgba_in.b * 255.) | (uint(rgba_in.g * 255.) << 8) | (uint(rgba_in.r * 255.) << 16);\n"
|
||||||
|
" gl_FragDepth = float(raw_value) / 16777215.;\n"
|
||||||
|
" //gl_FragDepth = rgba_in.r * 0.99609 + rgba_in.g * 0.00389 + rgba_in.b * 0.00002;\n"
|
||||||
|
"}\n"
|
||||||
|
};
|
||||||
|
|
||||||
|
renderpass_config.write_color = false;
|
||||||
|
|
||||||
|
m_vertex_shader.id = 100002;
|
||||||
|
m_fragment_shader.id = 100003;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,9 +103,11 @@ namespace vk
|
||||||
};
|
};
|
||||||
|
|
||||||
m_vertex_shader.shader = vs;
|
m_vertex_shader.shader = vs;
|
||||||
|
m_vertex_shader.id = 100000;
|
||||||
m_vertex_shader.Compile();
|
m_vertex_shader.Compile();
|
||||||
|
|
||||||
m_fragment_shader.shader = fs;
|
m_fragment_shader.shader = fs;
|
||||||
|
m_fragment_shader.id = 100001;
|
||||||
m_fragment_shader.Compile();
|
m_fragment_shader.Compile();
|
||||||
|
|
||||||
VkPipelineShaderStageCreateInfo shader_stages[2] = {};
|
VkPipelineShaderStageCreateInfo shader_stages[2] = {};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue