mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 18:53:28 +01: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
@ -116,7 +116,7 @@ namespace gl
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
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);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
|
@ -1417,6 +1417,16 @@ namespace rsx
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -644,6 +644,9 @@ VKGSRender::VKGSRender() : GSRender()
|
||||
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()));
|
||||
|
||||
if (g_cfg.video.disable_vertex_cache)
|
||||
@ -754,6 +757,10 @@ VKGSRender::~VKGSRender()
|
||||
//Overlay text handler
|
||||
m_text_writer.reset();
|
||||
|
||||
//RGBA->depth cast helper
|
||||
m_depth_converter->destroy();
|
||||
m_depth_converter.reset();
|
||||
|
||||
//Pipeline descriptors
|
||||
vkDestroyPipelineLayout(*m_device, pipeline_layout, 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();
|
||||
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)
|
||||
{
|
||||
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();
|
||||
|
||||
begin_render_pass();
|
||||
@ -1383,20 +1410,17 @@ void VKGSRender::end()
|
||||
buffers_to_clear.reserve(4);
|
||||
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;
|
||||
depth_clear_value.depthStencil.depth = 1.f;
|
||||
depth_clear_value.depthStencil.stencil = 255;
|
||||
//Clear this surface before drawing on it
|
||||
VkClearValue depth_clear_value;
|
||||
depth_clear_value.depthStencil.depth = 1.f;
|
||||
depth_clear_value.depthStencil.stencil = 255;
|
||||
|
||||
VkClearAttachment clear_desc = { ds->attachment_aspect_flag, 0, depth_clear_value };
|
||||
buffers_to_clear.push_back(clear_desc);
|
||||
VkClearAttachment clear_desc = { ds->attachment_aspect_flag, 0, depth_clear_value };
|
||||
buffers_to_clear.push_back(clear_desc);
|
||||
|
||||
ds->dirty = false;
|
||||
}
|
||||
ds->dirty = false;
|
||||
}
|
||||
|
||||
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_depth_converter->free_resources();
|
||||
|
||||
ctx->buffer_views_to_clean.clear();
|
||||
ctx->samplers_to_clean.clear();
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "VKRenderTargets.h"
|
||||
#include "VKFormats.h"
|
||||
#include "VKTextOut.h"
|
||||
#include "VKOverlays.h"
|
||||
#include "restore_new.h"
|
||||
#include "define_new_memleakdetect.h"
|
||||
#include "VKProgramBuffer.h"
|
||||
@ -134,6 +135,7 @@ private:
|
||||
std::unique_ptr<vk::buffer_view> null_buffer_view;
|
||||
|
||||
std::unique_ptr<vk::text_writer> m_text_writer;
|
||||
std::unique_ptr<vk::depth_convert_pass> m_depth_converter;
|
||||
|
||||
std::mutex m_sampler_mutex;
|
||||
u64 surface_store_tag = 0;
|
||||
|
@ -2,11 +2,348 @@
|
||||
#include "VKHelpers.h"
|
||||
#include "VKVertexProgram.h"
|
||||
#include "VKFragmentProgram.h"
|
||||
#include "VKRenderTargets.h"
|
||||
|
||||
namespace vk
|
||||
{
|
||||
//TODO: Refactor text print class to inherit from this base class
|
||||
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.id = 100000;
|
||||
m_vertex_shader.Compile();
|
||||
|
||||
m_fragment_shader.shader = fs;
|
||||
m_fragment_shader.id = 100001;
|
||||
m_fragment_shader.Compile();
|
||||
|
||||
VkPipelineShaderStageCreateInfo shader_stages[2] = {};
|
||||
|
Loading…
Reference in New Issue
Block a user