mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-02 13:01:27 +12:00
vk: Rewrite program binding management to use "separate shader objects" concept.
This commit is contained in:
parent
4d493bbb80
commit
356b2f5910
21 changed files with 743 additions and 413 deletions
|
@ -35,4 +35,34 @@ namespace vk
|
||||||
|
|
||||||
fmt::throw_exception("Unknown register name: %s", varying_register_name);
|
fmt::throw_exception("Unknown register name: %s", varying_register_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int get_texture_index(std::string_view name)
|
||||||
|
{
|
||||||
|
if (name.length() < 2)
|
||||||
|
{
|
||||||
|
fmt::throw_exception("Invalid texture name: '%s'", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IS_DIGIT(x) (x >= '0' && x <= '9')
|
||||||
|
|
||||||
|
constexpr int max_index_length = 2;
|
||||||
|
std::string index;
|
||||||
|
|
||||||
|
for (int char_idx = name.length() - max_index_length; char_idx < name.length(); ++char_idx)
|
||||||
|
{
|
||||||
|
if (IS_DIGIT(name[char_idx]))
|
||||||
|
{
|
||||||
|
index += name[char_idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef IS_DIGIT
|
||||||
|
|
||||||
|
if (index.empty())
|
||||||
|
{
|
||||||
|
fmt::throw_exception("Invalid texture name: '%s'", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::atoi(index.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,4 +6,6 @@ namespace vk
|
||||||
using namespace ::glsl;
|
using namespace ::glsl;
|
||||||
|
|
||||||
int get_varying_register_location(std::string_view varying_register_name);
|
int get_varying_register_location(std::string_view varying_register_name);
|
||||||
|
|
||||||
|
int get_texture_index(std::string_view name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ namespace vk
|
||||||
::glsl::glsl_compute_program,
|
::glsl::glsl_compute_program,
|
||||||
"ssbo" + std::to_string(i),
|
"ssbo" + std::to_string(i),
|
||||||
glsl::program_input_type::input_type_storage_buffer,
|
glsl::program_input_type::input_type_storage_buffer,
|
||||||
|
0,
|
||||||
i
|
i
|
||||||
);
|
);
|
||||||
result.push_back(input);
|
result.push_back(input);
|
||||||
|
@ -31,6 +32,7 @@ namespace vk
|
||||||
"push_constants",
|
"push_constants",
|
||||||
glsl::program_input_type::input_type_push_constant,
|
glsl::program_input_type::input_type_push_constant,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
glsl::push_constant_ref{ .offset = 0, .size = push_constants_size }
|
glsl::push_constant_ref{ .offset = 0, .size = push_constants_size }
|
||||||
);
|
);
|
||||||
result.push_back(input);
|
result.push_back(input);
|
||||||
|
@ -243,7 +245,7 @@ namespace vk
|
||||||
|
|
||||||
void cs_shuffle_base::bind_resources()
|
void cs_shuffle_base::bind_resources()
|
||||||
{
|
{
|
||||||
m_program->bind_buffer({ m_data->value, m_data_offset, m_data_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
m_program->bind_uniform({ m_data->value, m_data_offset, m_data_length }, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cs_shuffle_base::set_parameters(const vk::command_buffer& cmd, const u32* params, u8 count)
|
void cs_shuffle_base::set_parameters(const vk::command_buffer& cmd, const u32* params, u8 count)
|
||||||
|
@ -289,7 +291,7 @@ namespace vk
|
||||||
|
|
||||||
void cs_interleave_task::bind_resources()
|
void cs_interleave_task::bind_resources()
|
||||||
{
|
{
|
||||||
m_program->bind_buffer({ m_data->value, m_data_offset, m_ssbo_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
m_program->bind_uniform({ m_data->value, m_data_offset, m_ssbo_length }, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cs_interleave_task::run(const vk::command_buffer& cmd, const vk::buffer* data, u32 data_offset, u32 data_length, u32 zeta_offset, u32 stencil_offset)
|
void cs_interleave_task::run(const vk::command_buffer& cmd, const vk::buffer* data, u32 data_offset, u32 data_length, u32 zeta_offset, u32 stencil_offset)
|
||||||
|
@ -349,8 +351,8 @@ namespace vk
|
||||||
|
|
||||||
void cs_aggregator::bind_resources()
|
void cs_aggregator::bind_resources()
|
||||||
{
|
{
|
||||||
m_program->bind_buffer({ src->value, 0, block_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
m_program->bind_uniform({ src->value, 0, block_length }, 0, 0);
|
||||||
m_program->bind_buffer({ dst->value, 0, 4 }, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
m_program->bind_uniform({ dst->value, 0, 4 }, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cs_aggregator::run(const vk::command_buffer& cmd, const vk::buffer* dst, const vk::buffer* src, u32 num_words)
|
void cs_aggregator::run(const vk::command_buffer& cmd, const vk::buffer* dst, const vk::buffer* src, u32 num_words)
|
||||||
|
|
|
@ -344,7 +344,7 @@ namespace vk
|
||||||
|
|
||||||
void bind_resources() override
|
void bind_resources() override
|
||||||
{
|
{
|
||||||
m_program->bind_buffer({ m_data->value, m_data_offset, m_ssbo_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
m_program->bind_uniform({ m_data->value, m_data_offset, m_ssbo_length }, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(const vk::command_buffer& cmd, const vk::buffer* data, u32 src_offset, u32 src_length, u32 dst_offset)
|
void run(const vk::command_buffer& cmd, const vk::buffer* data, u32 src_offset, u32 src_length, u32 dst_offset)
|
||||||
|
@ -445,8 +445,8 @@ namespace vk
|
||||||
|
|
||||||
void bind_resources() override
|
void bind_resources() override
|
||||||
{
|
{
|
||||||
m_program->bind_buffer({ src_buffer->value, in_offset, block_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
m_program->bind_uniform({ src_buffer->value, in_offset, block_length }, 0, 0);
|
||||||
m_program->bind_buffer({ dst_buffer->value, out_offset, block_length }, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
m_program->bind_uniform({ dst_buffer->value, out_offset, block_length }, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_parameters(const vk::command_buffer& cmd)
|
void set_parameters(const vk::command_buffer& cmd)
|
||||||
|
@ -573,9 +573,9 @@ namespace vk
|
||||||
|
|
||||||
void bind_resources() override
|
void bind_resources() override
|
||||||
{
|
{
|
||||||
const auto op = static_cast<int>(Op);
|
const auto op = static_cast<u32>(Op);
|
||||||
m_program->bind_buffer({ src_buffer->value, in_offset, in_block_length }, 0 ^ op, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
m_program->bind_uniform({ src_buffer->value, in_offset, in_block_length }, 0u, 0u ^ op);
|
||||||
m_program->bind_buffer({ dst_buffer->value, out_offset, out_block_length }, 1 ^ op, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
m_program->bind_uniform({ dst_buffer->value, out_offset, out_block_length }, 0u, 1u ^ op);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_parameters(const vk::command_buffer& cmd)
|
void set_parameters(const vk::command_buffer& cmd)
|
||||||
|
|
|
@ -554,8 +554,8 @@ bool VKGSRender::bind_texture_env()
|
||||||
if (view) [[likely]]
|
if (view) [[likely]]
|
||||||
{
|
{
|
||||||
m_program->bind_uniform({ fs_sampler_handles[i]->value, view->value, view->image()->current_layout },
|
m_program->bind_uniform({ fs_sampler_handles[i]->value, view->value, view->image()->current_layout },
|
||||||
i,
|
vk::glsl::binding_set_index_fragment,
|
||||||
::glsl::program_domain::glsl_fragment_program);
|
m_fragment_prog->binding_table.ftex_location[i]);
|
||||||
|
|
||||||
if (current_fragment_program.texture_state.redirected_textures & (1 << i))
|
if (current_fragment_program.texture_state.redirected_textures & (1 << i))
|
||||||
{
|
{
|
||||||
|
@ -575,24 +575,22 @@ bool VKGSRender::bind_texture_env()
|
||||||
}
|
}
|
||||||
|
|
||||||
m_program->bind_uniform({ m_stencil_mirror_sampler->value, stencil_view->value, stencil_view->image()->current_layout },
|
m_program->bind_uniform({ m_stencil_mirror_sampler->value, stencil_view->value, stencil_view->image()->current_layout },
|
||||||
i,
|
vk::glsl::binding_set_index_fragment,
|
||||||
::glsl::program_domain::glsl_fragment_program,
|
m_fragment_prog->binding_table.ftex_stencil_location[i]);
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const VkImageViewType view_type = vk::get_view_type(current_fragment_program.get_texture_dimension(i));
|
const VkImageViewType view_type = vk::get_view_type(current_fragment_program.get_texture_dimension(i));
|
||||||
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
||||||
i,
|
vk::glsl::binding_set_index_fragment,
|
||||||
::glsl::program_domain::glsl_fragment_program);
|
m_fragment_prog->binding_table.ftex_location[i]);
|
||||||
|
|
||||||
if (current_fragment_program.texture_state.redirected_textures & (1 << i))
|
if (current_fragment_program.texture_state.redirected_textures & (1 << i))
|
||||||
{
|
{
|
||||||
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
||||||
i,
|
vk::glsl::binding_set_index_fragment,
|
||||||
::glsl::program_domain::glsl_fragment_program,
|
m_fragment_prog->binding_table.ftex_stencil_location[i]);
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -606,8 +604,8 @@ bool VKGSRender::bind_texture_env()
|
||||||
{
|
{
|
||||||
const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i));
|
const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i));
|
||||||
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
||||||
i,
|
vk::glsl::binding_set_index_vertex,
|
||||||
::glsl::program_domain::glsl_vertex_program);
|
m_vertex_prog->binding_table.vtex_location[i]);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -629,8 +627,8 @@ bool VKGSRender::bind_texture_env()
|
||||||
const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i));
|
const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i));
|
||||||
|
|
||||||
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
||||||
i,
|
vk::glsl::binding_set_index_vertex,
|
||||||
::glsl::program_domain::glsl_vertex_program);
|
m_vertex_prog->binding_table.vtex_location[i]);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -638,8 +636,8 @@ bool VKGSRender::bind_texture_env()
|
||||||
validate_image_layout_for_read_access(*m_current_command_buffer, image_ptr, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, sampler_state);
|
validate_image_layout_for_read_access(*m_current_command_buffer, image_ptr, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, sampler_state);
|
||||||
|
|
||||||
m_program->bind_uniform({ vs_sampler_handles[i]->value, image_ptr->value, image_ptr->image()->current_layout },
|
m_program->bind_uniform({ vs_sampler_handles[i]->value, image_ptr->value, image_ptr->image()->current_layout },
|
||||||
i,
|
vk::glsl::binding_set_index_vertex,
|
||||||
::glsl::program_domain::glsl_vertex_program);
|
m_vertex_prog->binding_table.vtex_location[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return out_of_memory;
|
return out_of_memory;
|
||||||
|
@ -820,8 +818,6 @@ void VKGSRender::emit_geometry(u32 sub_index)
|
||||||
auto volatile_buffer = m_volatile_attribute_storage ? m_volatile_attribute_storage->value : null_buffer_view->value;
|
auto volatile_buffer = m_volatile_attribute_storage ? m_volatile_attribute_storage->value : null_buffer_view->value;
|
||||||
bool update_descriptors = false;
|
bool update_descriptors = false;
|
||||||
|
|
||||||
const auto& binding_table = m_device->get_pipeline_binding_table();
|
|
||||||
|
|
||||||
if (m_current_draw.subdraw_id == 0)
|
if (m_current_draw.subdraw_id == 0)
|
||||||
{
|
{
|
||||||
update_descriptors = true;
|
update_descriptors = true;
|
||||||
|
@ -878,9 +874,10 @@ void VKGSRender::emit_geometry(u32 sub_index)
|
||||||
ensure(m_vertex_layout_storage);
|
ensure(m_vertex_layout_storage);
|
||||||
if (update_descriptors)
|
if (update_descriptors)
|
||||||
{
|
{
|
||||||
m_program->bind_uniform(persistent_buffer, binding_table.vertex_buffers_first_bind_slot);
|
const auto& binding_table = m_vertex_prog->binding_table;
|
||||||
m_program->bind_uniform(volatile_buffer, binding_table.vertex_buffers_first_bind_slot + 1);
|
m_program->bind_uniform(persistent_buffer, vk::glsl::binding_set_index_vertex, binding_table.vertex_buffers_location);
|
||||||
m_program->bind_uniform(m_vertex_layout_storage->value, binding_table.vertex_buffers_first_bind_slot + 2);
|
m_program->bind_uniform(volatile_buffer, vk::glsl::binding_set_index_vertex, binding_table.vertex_buffers_location + 1);
|
||||||
|
m_program->bind_uniform(m_vertex_layout_storage->value, vk::glsl::binding_set_index_vertex, binding_table.vertex_buffers_location + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool reload_state = (!m_current_draw.subdraw_id++);
|
bool reload_state = (!m_current_draw.subdraw_id++);
|
||||||
|
|
|
@ -26,8 +26,85 @@ std::string VKFragmentDecompilerThread::compareFunction(COMPARE f, const std::st
|
||||||
return glsl::compareFunctionImpl(f, Op0, Op1);
|
return glsl::compareFunctionImpl(f, Op0, Op1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VKFragmentDecompilerThread::prepareBindingTable()
|
||||||
|
{
|
||||||
|
// First check if we have constants and textures as those need extra work
|
||||||
|
bool has_constants = false, has_textures = false;
|
||||||
|
for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||||
|
{
|
||||||
|
if (has_constants && has_textures)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PT.type.starts_with("sampler"))
|
||||||
|
{
|
||||||
|
has_textures = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure(PT.type.starts_with("vec"));
|
||||||
|
has_constants = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned location = 0; // All bindings must be set from this var
|
||||||
|
vk_prog->binding_table.context_buffer_location = location++;
|
||||||
|
if (has_constants)
|
||||||
|
{
|
||||||
|
vk_prog->binding_table.cbuf_location = location++;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk_prog->binding_table.tex_param_location = location++;
|
||||||
|
vk_prog->binding_table.polygon_stipple_params_location = location++;
|
||||||
|
|
||||||
|
if (has_textures) [[ likely ]]
|
||||||
|
{
|
||||||
|
unsigned num_textures = 0;
|
||||||
|
for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||||
|
{
|
||||||
|
if (!PT.type.starts_with("sampler"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const ParamItem& PI : PT.items)
|
||||||
|
{
|
||||||
|
num_textures++;
|
||||||
|
|
||||||
|
const auto texture_id = vk::get_texture_index(PI.name);
|
||||||
|
const auto mask = 1u << texture_id;
|
||||||
|
|
||||||
|
// Allocate real binding
|
||||||
|
vk_prog->binding_table.ftex_location[texture_id] = location++;
|
||||||
|
|
||||||
|
// Tag the stencil mirror if required
|
||||||
|
if (properties.redirected_sampler_mask & mask) [[ unlikely ]]
|
||||||
|
{
|
||||||
|
vk_prog->binding_table.ftex_stencil_location[texture_id] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize stencil offsets
|
||||||
|
if (properties.redirected_sampler_mask != 0) [[ unlikely ]]
|
||||||
|
{
|
||||||
|
for (auto& stencil_location : vk_prog->binding_table.ftex_stencil_location)
|
||||||
|
{
|
||||||
|
if (stencil_location == umax)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
stencil_location = location++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VKFragmentDecompilerThread::insertHeader(std::stringstream & OS)
|
void VKFragmentDecompilerThread::insertHeader(std::stringstream & OS)
|
||||||
{
|
{
|
||||||
|
prepareBindingTable();
|
||||||
|
|
||||||
std::vector<const char*> required_extensions;
|
std::vector<const char*> required_extensions;
|
||||||
|
|
||||||
if (device_props.has_native_half_support)
|
if (device_props.has_native_half_support)
|
||||||
|
@ -97,21 +174,18 @@ void VKFragmentDecompilerThread::insertOutputs(std::stringstream & OS)
|
||||||
|
|
||||||
void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS)
|
void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS)
|
||||||
{
|
{
|
||||||
u32 location = m_binding_table.textures_first_bind_slot;
|
|
||||||
for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM])
|
for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||||
{
|
{
|
||||||
if (PT.type != "sampler1D" &&
|
if (PT.type.starts_with("sampler1D"))
|
||||||
PT.type != "sampler2D" &&
|
{
|
||||||
PT.type != "sampler3D" &&
|
|
||||||
PT.type != "samplerCube")
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (const ParamItem& PI : PT.items)
|
for (const ParamItem& PI : PT.items)
|
||||||
{
|
{
|
||||||
std::string samplerType = PT.type;
|
std::string samplerType = PT.type;
|
||||||
|
|
||||||
ensure(PI.name.length() > 3);
|
const int index = vk::get_texture_index(PI.name);
|
||||||
int index = atoi(&PI.name[3]);
|
|
||||||
const auto mask = (1 << index);
|
const auto mask = (1 << index);
|
||||||
|
|
||||||
if (properties.multisampled_sampler_mask & mask)
|
if (properties.multisampled_sampler_mask & mask)
|
||||||
|
@ -135,39 +209,37 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::glsl::program_input in;
|
const int id = vk::get_texture_index(PI.name);
|
||||||
in.location = location;
|
auto in = vk::glsl::program_input::make(
|
||||||
in.domain = glsl::glsl_fragment_program;
|
glsl::glsl_fragment_program,
|
||||||
in.name = PI.name;
|
PI.name,
|
||||||
in.type = vk::glsl::input_type_texture;
|
vk::glsl::input_type_texture,
|
||||||
|
vk::glsl::binding_set_index_fragment,
|
||||||
|
vk_prog->binding_table.ftex_location[id]
|
||||||
|
);
|
||||||
inputs.push_back(in);
|
inputs.push_back(in);
|
||||||
|
|
||||||
OS << "layout(set=0, binding=" << location++ << ") uniform " << samplerType << " " << PI.name << ";\n";
|
OS << "layout(set=0, binding=" << in.location << ") uniform " << samplerType << " " << PI.name << ";\n";
|
||||||
|
|
||||||
if (properties.redirected_sampler_mask & mask)
|
if (properties.redirected_sampler_mask & mask)
|
||||||
{
|
{
|
||||||
// Insert stencil mirror declaration
|
// Insert stencil mirror declaration
|
||||||
in.name += "_stencil";
|
in.name += "_stencil";
|
||||||
in.location = location;
|
in.location = vk_prog->binding_table.ftex_stencil_location[id];
|
||||||
|
|
||||||
inputs.push_back(in);
|
inputs.push_back(in);
|
||||||
|
|
||||||
OS << "layout(set=0, binding=" << location++ << ") uniform u" << samplerType << " " << in.name << ";\n";
|
OS << "layout(set=0, binding=" << in.location << ") uniform u" << samplerType << " " << in.name << ";\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure(location <= m_binding_table.vertex_textures_first_bind_slot); // "Too many sampler descriptors!"
|
|
||||||
|
|
||||||
std::string constants_block;
|
std::string constants_block;
|
||||||
for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM])
|
for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||||
{
|
{
|
||||||
if (PT.type == "sampler1D" ||
|
if (PT.type.starts_with("sampler1D"))
|
||||||
PT.type == "sampler2D" ||
|
{
|
||||||
PT.type == "sampler3D" ||
|
|
||||||
PT.type == "samplerCube")
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (const ParamItem& PI : PT.items)
|
for (const ParamItem& PI : PT.items)
|
||||||
{
|
{
|
||||||
|
@ -177,13 +249,13 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS)
|
||||||
|
|
||||||
if (!constants_block.empty())
|
if (!constants_block.empty())
|
||||||
{
|
{
|
||||||
OS << "layout(std140, set = 0, binding = 2) uniform FragmentConstantsBuffer\n";
|
OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.cbuf_location << ") uniform FragmentConstantsBuffer\n";
|
||||||
OS << "{\n";
|
OS << "{\n";
|
||||||
OS << constants_block;
|
OS << constants_block;
|
||||||
OS << "};\n\n";
|
OS << "};\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
OS << "layout(std140, set = 0, binding = 3) uniform FragmentStateBuffer\n";
|
OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.context_buffer_location << ") uniform FragmentStateBuffer\n";
|
||||||
OS << "{\n";
|
OS << "{\n";
|
||||||
OS << " float fog_param0;\n";
|
OS << " float fog_param0;\n";
|
||||||
OS << " float fog_param1;\n";
|
OS << " float fog_param1;\n";
|
||||||
|
@ -195,32 +267,39 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS)
|
||||||
OS << " float wpos_bias;\n";
|
OS << " float wpos_bias;\n";
|
||||||
OS << "};\n\n";
|
OS << "};\n\n";
|
||||||
|
|
||||||
OS << "layout(std140, set = 0, binding = 4) uniform TextureParametersBuffer\n";
|
OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.tex_param_location << ") uniform TextureParametersBuffer\n";
|
||||||
OS << "{\n";
|
OS << "{\n";
|
||||||
OS << " sampler_info texture_parameters[16];\n";
|
OS << " sampler_info texture_parameters[16];\n";
|
||||||
OS << "};\n\n";
|
OS << "};\n\n";
|
||||||
|
|
||||||
OS << "layout(std140, set = 0, binding = " << std::to_string(m_binding_table.rasterizer_env_bind_slot) << ") uniform RasterizerHeap\n";
|
OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.polygon_stipple_params_location << ") uniform RasterizerHeap\n";
|
||||||
OS << "{\n";
|
OS << "{\n";
|
||||||
OS << " uvec4 stipple_pattern[8];\n";
|
OS << " uvec4 stipple_pattern[8];\n";
|
||||||
OS << "};\n\n";
|
OS << "};\n\n";
|
||||||
|
|
||||||
vk::glsl::program_input in;
|
vk::glsl::program_input in
|
||||||
in.location = m_binding_table.fragment_constant_buffers_bind_slot;
|
{
|
||||||
in.domain = glsl::glsl_fragment_program;
|
.domain = glsl::glsl_fragment_program,
|
||||||
in.name = "FragmentConstantsBuffer";
|
.type = vk::glsl::input_type_uniform_buffer,
|
||||||
in.type = vk::glsl::input_type_uniform_buffer;
|
.set = vk::glsl::binding_set_index_fragment
|
||||||
inputs.push_back(in);
|
};
|
||||||
|
|
||||||
in.location = m_binding_table.fragment_state_bind_slot;
|
if (!constants_block.empty())
|
||||||
|
{
|
||||||
|
in.location = vk_prog->binding_table.cbuf_location;
|
||||||
|
in.name = "FragmentConstantsBuffer";
|
||||||
|
inputs.push_back(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
in.location = vk_prog->binding_table.context_buffer_location;
|
||||||
in.name = "FragmentStateBuffer";
|
in.name = "FragmentStateBuffer";
|
||||||
inputs.push_back(in);
|
inputs.push_back(in);
|
||||||
|
|
||||||
in.location = m_binding_table.fragment_texture_params_bind_slot;
|
in.location = vk_prog->binding_table.tex_param_location;
|
||||||
in.name = "TextureParametersBuffer";
|
in.name = "TextureParametersBuffer";
|
||||||
inputs.push_back(in);
|
inputs.push_back(in);
|
||||||
|
|
||||||
in.location = m_binding_table.rasterizer_env_bind_slot;
|
in.location = vk_prog->binding_table.polygon_stipple_params_location;
|
||||||
in.name = "RasterizerHeap";
|
in.name = "RasterizerHeap";
|
||||||
inputs.push_back(in);
|
inputs.push_back(in);
|
||||||
}
|
}
|
||||||
|
@ -372,7 +451,6 @@ void VKFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
|
||||||
|
|
||||||
void VKFragmentDecompilerThread::Task()
|
void VKFragmentDecompilerThread::Task()
|
||||||
{
|
{
|
||||||
m_binding_table = vk::g_render_device->get_pipeline_binding_table();
|
|
||||||
m_shader = Decompile();
|
m_shader = Decompile();
|
||||||
vk_prog->SetInputs(inputs);
|
vk_prog->SetInputs(inputs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,8 @@ struct VKFragmentDecompilerThread : public FragmentProgramDecompiler
|
||||||
std::vector<vk::glsl::program_input> inputs;
|
std::vector<vk::glsl::program_input> inputs;
|
||||||
class VKFragmentProgram *vk_prog;
|
class VKFragmentProgram *vk_prog;
|
||||||
glsl::shader_properties m_shader_props{};
|
glsl::shader_properties m_shader_props{};
|
||||||
vk::pipeline_binding_table m_binding_table{};
|
|
||||||
|
void prepareBindingTable();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VKFragmentDecompilerThread(std::string& shader, ParamArray& parr, const RSXFragmentProgram &prog, u32& size, class VKFragmentProgram& dst)
|
VKFragmentDecompilerThread(std::string& shader, ParamArray& parr, const RSXFragmentProgram &prog, u32& size, class VKFragmentProgram& dst)
|
||||||
|
@ -32,6 +33,7 @@ public:
|
||||||
|
|
||||||
void Task();
|
void Task();
|
||||||
const std::vector<vk::glsl::program_input>& get_inputs() { return inputs; }
|
const std::vector<vk::glsl::program_input>& get_inputs() { return inputs; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string getFloatTypeName(usz elementCount) override;
|
std::string getFloatTypeName(usz elementCount) override;
|
||||||
std::string getHalfTypeName(usz elementCount) override;
|
std::string getHalfTypeName(usz elementCount) override;
|
||||||
|
@ -63,8 +65,19 @@ public:
|
||||||
std::vector<usz> FragmentConstantOffsetCache;
|
std::vector<usz> FragmentConstantOffsetCache;
|
||||||
|
|
||||||
std::array<u32, 4> output_color_masks{ {} };
|
std::array<u32, 4> output_color_masks{ {} };
|
||||||
|
|
||||||
std::vector<vk::glsl::program_input> uniforms;
|
std::vector<vk::glsl::program_input> uniforms;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u32 context_buffer_location = umax; // Rasterizer context
|
||||||
|
u32 cbuf_location = umax; // Constants register file
|
||||||
|
u32 tex_param_location = umax; // Texture configuration data
|
||||||
|
u32 polygon_stipple_params_location = umax; // Polygon stipple settings
|
||||||
|
u32 ftex_location[16]; // Texture locations array
|
||||||
|
u32 ftex_stencil_location[16]; // Texture stencil mirror array
|
||||||
|
|
||||||
|
} binding_table;
|
||||||
|
|
||||||
void SetInputs(std::vector<vk::glsl::program_input>& inputs);
|
void SetInputs(std::vector<vk::glsl::program_input>& inputs);
|
||||||
/**
|
/**
|
||||||
* Decompile a fragment shader located in the PS3's Memory. This function operates synchronously.
|
* Decompile a fragment shader located in the PS3's Memory. This function operates synchronously.
|
||||||
|
|
|
@ -2074,34 +2074,35 @@ void VKGSRender::load_program_env()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& binding_table = m_device->get_pipeline_binding_table();
|
const auto& vs_binding_table = m_vertex_prog->binding_table;
|
||||||
|
const auto& fs_binding_table = m_fragment_prog->binding_table;
|
||||||
|
|
||||||
m_program->bind_uniform(m_vertex_env_buffer_info, binding_table.vertex_params_bind_slot);
|
m_program->bind_uniform(m_vertex_env_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.context_buffer_location);
|
||||||
m_program->bind_buffer(m_vertex_constants_buffer_info, binding_table.vertex_constant_buffers_bind_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
m_program->bind_uniform(m_vertex_constants_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.cbuf_location);
|
||||||
m_program->bind_uniform(m_fragment_env_buffer_info, binding_table.fragment_state_bind_slot);
|
m_program->bind_uniform(m_fragment_env_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.context_buffer_location);
|
||||||
m_program->bind_uniform(m_fragment_texture_params_buffer_info, binding_table.fragment_texture_params_bind_slot);
|
m_program->bind_uniform(m_fragment_texture_params_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.tex_param_location);
|
||||||
m_program->bind_uniform(m_raster_env_buffer_info, binding_table.rasterizer_env_bind_slot);
|
m_program->bind_uniform(m_raster_env_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.polygon_stipple_params_location);
|
||||||
|
|
||||||
if (!m_shader_interpreter.is_interpreter(m_program))
|
if (m_shader_interpreter.is_interpreter(m_program))
|
||||||
{
|
{
|
||||||
m_program->bind_uniform(m_fragment_constants_buffer_info, binding_table.fragment_constant_buffers_bind_slot);
|
m_program->bind_uniform(m_vertex_instructions_buffer_info, vk::glsl::binding_set_index_vertex, m_shader_interpreter.get_vertex_instruction_location());
|
||||||
|
m_program->bind_uniform(m_fragment_instructions_buffer_info, vk::glsl::binding_set_index_fragment, m_shader_interpreter.get_fragment_instruction_location());
|
||||||
}
|
}
|
||||||
else
|
else if (fs_binding_table.cbuf_location != umax)
|
||||||
{
|
{
|
||||||
m_program->bind_buffer(m_vertex_instructions_buffer_info, m_shader_interpreter.get_vertex_instruction_location(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
m_program->bind_uniform(m_fragment_constants_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.cbuf_location);
|
||||||
m_program->bind_buffer(m_fragment_instructions_buffer_info, m_shader_interpreter.get_fragment_instruction_location(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vk::emulate_conditional_rendering())
|
if (vk::emulate_conditional_rendering())
|
||||||
{
|
{
|
||||||
auto predicate = m_cond_render_buffer ? m_cond_render_buffer->value : vk::get_scratch_buffer(*m_current_command_buffer, 4)->value;
|
auto predicate = m_cond_render_buffer ? m_cond_render_buffer->value : vk::get_scratch_buffer(*m_current_command_buffer, 4)->value;
|
||||||
m_program->bind_buffer({ predicate, 0, 4 }, binding_table.conditional_render_predicate_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
m_program->bind_uniform({ predicate, 0, 4 }, vk::glsl::binding_set_index_vertex, vs_binding_table.cr_pred_buffer_location);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_vertex_program.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS)
|
if (current_vertex_program.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS)
|
||||||
{
|
{
|
||||||
m_program->bind_buffer(m_instancing_indirection_buffer_info, binding_table.instancing_lookup_table_bind_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
m_program->bind_uniform(m_instancing_indirection_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.instanced_lut_buffer_location);
|
||||||
m_program->bind_buffer(m_instancing_constants_array_buffer_info, binding_table.instancing_constants_buffer_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
m_program->bind_uniform(m_instancing_constants_array_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.instanced_cbuf_location);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear flags
|
// Clear flags
|
||||||
|
|
|
@ -63,21 +63,21 @@ namespace vk
|
||||||
for (u32 n = 0; n < m_num_uniform_buffers; ++n, ++binding)
|
for (u32 n = 0; n < m_num_uniform_buffers; ++n, ++binding)
|
||||||
{
|
{
|
||||||
const std::string name = std::string("static_data") + (n > 0 ? std::to_string(n) : "");
|
const std::string name = std::string("static_data") + (n > 0 ? std::to_string(n) : "");
|
||||||
const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_uniform_buffer, 0);
|
const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_uniform_buffer, 0, 0);
|
||||||
fs_inputs.push_back(input);
|
fs_inputs.push_back(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 n = 0; n < m_num_usable_samplers; ++n, ++binding)
|
for (u32 n = 0; n < m_num_usable_samplers; ++n, ++binding)
|
||||||
{
|
{
|
||||||
const std::string name = "fs" + std::to_string(n);
|
const std::string name = "fs" + std::to_string(n);
|
||||||
const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_texture, binding);
|
const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_texture, 0, binding);
|
||||||
fs_inputs.push_back(input);
|
fs_inputs.push_back(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 n = 0; n < m_num_input_attachments; ++n, ++binding)
|
for (u32 n = 0; n < m_num_input_attachments; ++n, ++binding)
|
||||||
{
|
{
|
||||||
const std::string name = "sp" + std::to_string(n);
|
const std::string name = "sp" + std::to_string(n);
|
||||||
const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_texture, binding);
|
const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_texture, 0, binding);
|
||||||
fs_inputs.push_back(input);
|
fs_inputs.push_back(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,13 +179,14 @@ namespace vk
|
||||||
|
|
||||||
if (m_num_uniform_buffers > 0)
|
if (m_num_uniform_buffers > 0)
|
||||||
{
|
{
|
||||||
program->bind_uniform({ m_ubo.heap->value, m_ubo_offset, std::max(m_ubo_length, 4u) }, 0);
|
program->bind_uniform({ m_ubo.heap->value, m_ubo_offset, std::max(m_ubo_length, 4u) }, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint n = 0; n < src.size(); ++n)
|
for (uint n = 0; n < src.size(); ++n)
|
||||||
{
|
{
|
||||||
VkDescriptorImageInfo info = { m_sampler->value, src[n]->value, src[n]->image()->current_layout };
|
VkDescriptorImageInfo info = { m_sampler->value, src[n]->value, src[n]->image()->current_layout };
|
||||||
program->bind_uniform(info, "fs" + std::to_string(n), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
|
const auto [set, location] = program->get_uniform_location(::glsl::glsl_fragment_program, glsl::input_type_texture, "fs" + std::to_string(n));
|
||||||
|
program->bind_uniform(info, set, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
program->bind(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS);
|
program->bind(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS);
|
||||||
|
@ -488,6 +489,7 @@ namespace vk
|
||||||
"push_constants",
|
"push_constants",
|
||||||
glsl::input_type_push_constant,
|
glsl::input_type_push_constant,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
glsl::push_constant_ref { .size = 68 }
|
glsl::push_constant_ref { .size = 68 }
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -503,6 +505,7 @@ namespace vk
|
||||||
"push_constants",
|
"push_constants",
|
||||||
glsl::input_type_push_constant,
|
glsl::input_type_push_constant,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
glsl::push_constant_ref {.offset = 68, .size = 12 }
|
glsl::push_constant_ref {.offset = 68, .size = 12 }
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -715,6 +718,7 @@ namespace vk
|
||||||
"push_constants",
|
"push_constants",
|
||||||
vk::glsl::input_type_push_constant,
|
vk::glsl::input_type_push_constant,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
glsl::push_constant_ref{ .size = 32 })
|
glsl::push_constant_ref{ .size = 32 })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -864,6 +868,7 @@ namespace vk
|
||||||
"push_constants",
|
"push_constants",
|
||||||
vk::glsl::input_type_push_constant,
|
vk::glsl::input_type_push_constant,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
glsl::push_constant_ref{ .size = 16 }
|
glsl::push_constant_ref{ .size = 16 }
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -54,7 +54,9 @@ namespace vk
|
||||||
const VkComputePipelineCreateInfo& create_info,
|
const VkComputePipelineCreateInfo& create_info,
|
||||||
const std::vector<glsl::program_input>& cs_inputs)
|
const std::vector<glsl::program_input>& cs_inputs)
|
||||||
{
|
{
|
||||||
return std::make_unique<glsl::program>(*m_device, create_info, cs_inputs);
|
auto program = std::make_unique<glsl::program>(*m_device, create_info, cs_inputs);
|
||||||
|
program->link(false);
|
||||||
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<glsl::program> pipe_compiler::int_compile_graphics_pipe(
|
std::unique_ptr<glsl::program> pipe_compiler::int_compile_graphics_pipe(
|
||||||
|
@ -62,7 +64,9 @@ namespace vk
|
||||||
const std::vector<glsl::program_input>& vs_inputs,
|
const std::vector<glsl::program_input>& vs_inputs,
|
||||||
const std::vector<glsl::program_input>& fs_inputs)
|
const std::vector<glsl::program_input>& fs_inputs)
|
||||||
{
|
{
|
||||||
return std::make_unique<glsl::program>(*m_device, create_info, vs_inputs, fs_inputs);
|
auto program = std::make_unique<glsl::program>(*m_device, create_info, vs_inputs, fs_inputs);
|
||||||
|
program->link(true);
|
||||||
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<glsl::program> pipe_compiler::int_compile_graphics_pipe(
|
std::unique_ptr<glsl::program> pipe_compiler::int_compile_graphics_pipe(
|
||||||
|
@ -171,7 +175,7 @@ namespace vk
|
||||||
op_flags flags, callback_t callback,
|
op_flags flags, callback_t callback,
|
||||||
const std::vector<glsl::program_input>& cs_inputs)
|
const std::vector<glsl::program_input>& cs_inputs)
|
||||||
{
|
{
|
||||||
if (flags == COMPILE_INLINE)
|
if (flags & COMPILE_INLINE)
|
||||||
{
|
{
|
||||||
return int_compile_compute_pipe(create_info, cs_inputs);
|
return int_compile_compute_pipe(create_info, cs_inputs);
|
||||||
}
|
}
|
||||||
|
@ -187,7 +191,7 @@ namespace vk
|
||||||
const std::vector<glsl::program_input>& fs_inputs)
|
const std::vector<glsl::program_input>& fs_inputs)
|
||||||
{
|
{
|
||||||
// It is very inefficient to defer this as all pointers need to be saved
|
// It is very inefficient to defer this as all pointers need to be saved
|
||||||
ensure(flags == COMPILE_INLINE);
|
ensure(flags & COMPILE_INLINE);
|
||||||
return int_compile_graphics_pipe(create_info, vs_inputs, fs_inputs);
|
return int_compile_graphics_pipe(create_info, vs_inputs, fs_inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +204,7 @@ namespace vk
|
||||||
const std::vector<glsl::program_input>& fs_inputs)
|
const std::vector<glsl::program_input>& fs_inputs)
|
||||||
{
|
{
|
||||||
VkShaderModule modules[] = { vs, fs };
|
VkShaderModule modules[] = { vs, fs };
|
||||||
if (flags == COMPILE_INLINE)
|
if (flags & COMPILE_INLINE)
|
||||||
{
|
{
|
||||||
return int_compile_graphics_pipe(create_info, modules, vs_inputs, fs_inputs);
|
return int_compile_graphics_pipe(create_info, modules, vs_inputs, fs_inputs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,13 +53,16 @@ namespace vk
|
||||||
class pipe_compiler
|
class pipe_compiler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum op_flags
|
enum op_flag_bits
|
||||||
{
|
{
|
||||||
COMPILE_DEFAULT = 0,
|
COMPILE_DEFAULT = 0,
|
||||||
COMPILE_INLINE = 1,
|
COMPILE_INLINE = 1,
|
||||||
COMPILE_DEFERRED = 2
|
COMPILE_DEFERRED = 2,
|
||||||
|
SEPARATE_SHADER_OBJECTS = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using op_flags = rsx::flags32_t;
|
||||||
|
|
||||||
using callback_t = std::function<void(std::unique_ptr<glsl::program>&)>;
|
using callback_t = std::function<void(std::unique_ptr<glsl::program>&)>;
|
||||||
|
|
||||||
pipe_compiler();
|
pipe_compiler();
|
||||||
|
|
12
rpcs3/Emu/RSX/VK/VKProgramHelper.hpp
Normal file
12
rpcs3/Emu/RSX/VK/VKProgramHelper.hpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "VKProgramPipeline.h"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
namespace glsl
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,30 @@ namespace vk
|
||||||
{
|
{
|
||||||
using namespace ::glsl;
|
using namespace ::glsl;
|
||||||
|
|
||||||
|
bool operator == (const descriptor_slot_t& a, const VkDescriptorImageInfo& b)
|
||||||
|
{
|
||||||
|
const auto ptr = std::get_if<VkDescriptorImageInfo>(&a);
|
||||||
|
return !!ptr &&
|
||||||
|
ptr->imageView == b.imageView &&
|
||||||
|
ptr->sampler == b.sampler &&
|
||||||
|
ptr->imageLayout == b.imageLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator == (const descriptor_slot_t& a, const VkDescriptorBufferInfo& b)
|
||||||
|
{
|
||||||
|
const auto ptr = std::get_if<VkDescriptorBufferInfo>(&a);
|
||||||
|
return !!ptr &&
|
||||||
|
ptr->buffer == b.buffer &&
|
||||||
|
ptr->offset == b.offset &&
|
||||||
|
ptr->range == b.range;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator == (const descriptor_slot_t& a, const VkBufferView& b)
|
||||||
|
{
|
||||||
|
const auto ptr = std::get_if<VkBufferView>(&a);
|
||||||
|
return !!ptr && *ptr == b;
|
||||||
|
}
|
||||||
|
|
||||||
VkDescriptorType to_descriptor_type(program_input_type type)
|
VkDescriptorType to_descriptor_type(program_input_type type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
|
@ -120,42 +144,24 @@ namespace vk
|
||||||
|
|
||||||
void program::init()
|
void program::init()
|
||||||
{
|
{
|
||||||
linked = false;
|
m_linked = false;
|
||||||
|
|
||||||
fs_texture_bindings.fill(~0u);
|
|
||||||
fs_texture_mirror_bindings.fill(~0u);
|
|
||||||
vs_texture_bindings.fill(~0u);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
program::program(VkDevice dev, const VkGraphicsPipelineCreateInfo& create_info, const std::vector<program_input> &vertex_inputs, const std::vector<program_input>& fragment_inputs)
|
program::program(VkDevice dev, const VkGraphicsPipelineCreateInfo& create_info, const std::vector<program_input> &vertex_inputs, const std::vector<program_input>& fragment_inputs)
|
||||||
: m_device(dev)
|
: m_device(dev), m_info(create_info)
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
|
|
||||||
load_uniforms(vertex_inputs);
|
load_uniforms(vertex_inputs);
|
||||||
load_uniforms(fragment_inputs);
|
load_uniforms(fragment_inputs);
|
||||||
|
|
||||||
create_pipeline_layout();
|
|
||||||
ensure(m_pipeline_layout);
|
|
||||||
|
|
||||||
auto _create_info = create_info;
|
|
||||||
_create_info.layout = m_pipeline_layout;
|
|
||||||
CHECK_RESULT(vkCreateGraphicsPipelines(dev, nullptr, 1, &create_info, nullptr, &m_pipeline));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
program::program(VkDevice dev, const VkComputePipelineCreateInfo& create_info, const std::vector<program_input>& compute_inputs)
|
program::program(VkDevice dev, const VkComputePipelineCreateInfo& create_info, const std::vector<program_input>& compute_inputs)
|
||||||
: m_device(dev)
|
: m_device(dev), m_info(create_info)
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
|
|
||||||
load_uniforms(compute_inputs);
|
load_uniforms(compute_inputs);
|
||||||
|
|
||||||
create_pipeline_layout();
|
|
||||||
ensure(m_pipeline_layout);
|
|
||||||
|
|
||||||
auto _create_info = create_info;
|
|
||||||
_create_info.layout = m_pipeline_layout;
|
|
||||||
CHECK_RESULT(vkCreateComputePipelines(dev, nullptr, 1, &create_info, nullptr, &m_pipeline));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
program::~program()
|
program::~program()
|
||||||
|
@ -165,257 +171,352 @@ namespace vk
|
||||||
if (m_pipeline_layout)
|
if (m_pipeline_layout)
|
||||||
{
|
{
|
||||||
vkDestroyPipelineLayout(m_device, m_pipeline_layout, nullptr);
|
vkDestroyPipelineLayout(m_device, m_pipeline_layout, nullptr);
|
||||||
vkDestroyDescriptorSetLayout(m_device, m_descriptor_set_layout, nullptr);
|
|
||||||
vk::get_resource_manager()->dispose(m_descriptor_pool);
|
for (auto& set : m_sets)
|
||||||
|
{
|
||||||
|
set.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
program& program::load_uniforms(const std::vector<program_input>& inputs)
|
program& program::load_uniforms(const std::vector<program_input>& inputs)
|
||||||
{
|
{
|
||||||
ensure(!linked); // "Cannot change uniforms in already linked program!"
|
ensure(!m_linked); // "Cannot change uniforms in already linked program!"
|
||||||
|
|
||||||
for (auto &item : inputs)
|
for (auto &item : inputs)
|
||||||
{
|
{
|
||||||
uniforms[item.type].push_back(item);
|
ensure(item.set < binding_set_index_max_enum); // Ensure we have a valid set id
|
||||||
|
ensure(item.location < 128u || item.type == input_type_push_constant); // Arbitrary limit but useful to catch possibly uninitialized values
|
||||||
|
m_sets[item.set].m_inputs[item.type].push_back(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
program& program::link()
|
program& program::link(bool separate_objects)
|
||||||
{
|
{
|
||||||
// Preprocess texture bindings
|
auto p_graphics_info = std::get_if<VkGraphicsPipelineCreateInfo>(&m_info);
|
||||||
// Link step is only useful for rasterizer programs, compute programs do not need this
|
auto p_compute_info = !p_graphics_info ? std::get_if<VkComputePipelineCreateInfo>(&m_info) : nullptr;
|
||||||
for (const auto &uniform : uniforms[program_input_type::input_type_texture])
|
const bool is_graphics_pipe = p_graphics_info != nullptr;
|
||||||
{
|
|
||||||
if (const auto name_start = uniform.name.find("tex"); name_start != umax)
|
|
||||||
{
|
|
||||||
const auto name_end = uniform.name.find("_stencil");
|
|
||||||
const auto index_start = name_start + 3; // Skip 'tex' part
|
|
||||||
const auto index_length = (name_end != umax) ? name_end - index_start : name_end;
|
|
||||||
const auto index_part = uniform.name.substr(index_start, index_length);
|
|
||||||
const auto index = std::stoi(index_part);
|
|
||||||
|
|
||||||
if (name_start == 0)
|
if (!is_graphics_pipe) [[ likely ]]
|
||||||
|
{
|
||||||
|
// We only support compute and graphics, so disable this for compute
|
||||||
|
separate_objects = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!separate_objects)
|
||||||
|
{
|
||||||
|
// Collapse all sets into set 0 if validation passed
|
||||||
|
auto& sink = m_sets[0];
|
||||||
|
for (auto& set : m_sets)
|
||||||
|
{
|
||||||
|
for (auto& type_arr : set.m_inputs)
|
||||||
{
|
{
|
||||||
// Fragment texture (tex...)
|
if (type_arr.empty())
|
||||||
if (name_end == umax)
|
|
||||||
{
|
{
|
||||||
// Normal texture
|
continue;
|
||||||
fs_texture_bindings[index] = uniform.location;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Stencil mirror
|
|
||||||
fs_texture_mirror_bindings[index] = uniform.location;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto type = type_arr.front().type;
|
||||||
|
auto& dst = sink.m_inputs[type];
|
||||||
|
dst.insert(dst.end(), type_arr.begin(), type_arr.end());
|
||||||
|
|
||||||
|
// Clear
|
||||||
|
type_arr.clear();
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
sink.validate();
|
||||||
|
sink.init(m_device);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto& set : m_sets)
|
||||||
|
{
|
||||||
|
for (auto& type_arr : set.m_inputs)
|
||||||
{
|
{
|
||||||
// Vertex texture (vtex...)
|
if (type_arr.empty())
|
||||||
vs_texture_bindings[index] = uniform.location;
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Real set
|
||||||
|
set.validate();
|
||||||
|
set.init(m_device);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
linked = true;
|
create_pipeline_layout();
|
||||||
|
ensure(m_pipeline_layout);
|
||||||
|
|
||||||
|
if (is_graphics_pipe)
|
||||||
|
{
|
||||||
|
VkGraphicsPipelineCreateInfo create_info = *p_graphics_info;
|
||||||
|
create_info.layout = m_pipeline_layout;
|
||||||
|
CHECK_RESULT(vkCreateGraphicsPipelines(m_device, nullptr, 1, &create_info, nullptr, &m_pipeline));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VkComputePipelineCreateInfo create_info = *p_compute_info;
|
||||||
|
create_info.layout = m_pipeline_layout;
|
||||||
|
CHECK_RESULT(vkCreateComputePipelines(m_device, nullptr, 1, &create_info, nullptr, &m_pipeline));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_linked = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool program::has_uniform(program_input_type type, const std::string& uniform_name)
|
bool program::has_uniform(program_input_type type, const std::string& uniform_name)
|
||||||
{
|
{
|
||||||
const auto& uniform = uniforms[type];
|
for (auto& set : m_sets)
|
||||||
return std::any_of(uniform.cbegin(), uniform.cend(), [&uniform_name](const auto& u)
|
|
||||||
{
|
{
|
||||||
return u.name == uniform_name;
|
const auto& uniform = set.m_inputs[type];
|
||||||
});
|
return std::any_of(uniform.cbegin(), uniform.cend(), [&uniform_name](const auto& u)
|
||||||
}
|
|
||||||
|
|
||||||
u32 program::get_uniform_location(program_input_type type, const std::string& uniform_name)
|
|
||||||
{
|
|
||||||
const auto& uniform = uniforms[type];
|
|
||||||
const auto result = std::find_if(uniform.cbegin(), uniform.cend(), [&uniform_name](const auto& u)
|
|
||||||
{
|
|
||||||
return u.name == uniform_name;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result == uniform.end())
|
|
||||||
{
|
|
||||||
return { umax };
|
|
||||||
}
|
|
||||||
|
|
||||||
return result->location;
|
|
||||||
}
|
|
||||||
|
|
||||||
void program::bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string& uniform_name, VkDescriptorType type)
|
|
||||||
{
|
|
||||||
for (const auto &uniform : uniforms[program_input_type::input_type_texture])
|
|
||||||
{
|
|
||||||
if (uniform.name == uniform_name)
|
|
||||||
{
|
{
|
||||||
if (m_descriptor_slots[uniform.location].matches(image_descriptor))
|
return u.name == uniform_name;
|
||||||
{
|
});
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
next_descriptor_set();
|
std::pair<u32, u32> program::get_uniform_location(::glsl::program_domain domain, program_input_type type, const std::string& uniform_name)
|
||||||
m_descriptor_set.push(image_descriptor, type, uniform.location);
|
{
|
||||||
m_descriptors_dirty[uniform.location] = false;
|
for (unsigned i = 0; i < ::size32(m_sets); ++i)
|
||||||
return;
|
{
|
||||||
|
const auto& type_arr = m_sets[i].m_inputs[type];
|
||||||
|
const auto result = std::find_if(type_arr.cbegin(), type_arr.cend(), [&](const auto& u)
|
||||||
|
{
|
||||||
|
return u.domain == domain && u.name == uniform_name;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result != type_arr.end())
|
||||||
|
{
|
||||||
|
return { i, result->location };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rsx_log.notice("texture not found in program: %s", uniform_name.c_str());
|
return { umax, umax };
|
||||||
}
|
}
|
||||||
|
|
||||||
void program::bind_uniform(const VkDescriptorImageInfo & image_descriptor, int texture_unit, ::glsl::program_domain domain, bool is_stencil_mirror)
|
void program::bind_uniform(const VkDescriptorImageInfo& image_descriptor, u32 set_id, u32 binding_point)
|
||||||
{
|
{
|
||||||
ensure(domain != ::glsl::program_domain::glsl_compute_program);
|
if (m_sets[set_id].m_descriptor_slots[binding_point] == image_descriptor)
|
||||||
|
|
||||||
u32 binding;
|
|
||||||
if (domain == ::glsl::program_domain::glsl_fragment_program)
|
|
||||||
{
|
|
||||||
binding = (is_stencil_mirror) ? fs_texture_mirror_bindings[texture_unit] : fs_texture_bindings[texture_unit];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
binding = vs_texture_bindings[texture_unit];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (binding == ~0u) [[ unlikely ]]
|
|
||||||
{
|
|
||||||
rsx_log.notice("texture not found in program: %stex%u", (domain == ::glsl::program_domain::glsl_vertex_program) ? "v" : "", texture_unit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_descriptor_slots[binding].matches(image_descriptor))
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
next_descriptor_set();
|
m_sets[set_id].notify_descriptor_slot_updated(binding_point, image_descriptor);
|
||||||
m_descriptor_set.push(image_descriptor, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, binding);
|
|
||||||
m_descriptors_dirty[binding] = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void program::bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point)
|
void program::bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 set_id, u32 binding_point)
|
||||||
{
|
{
|
||||||
bind_buffer(buffer_descriptor, binding_point, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
|
if (m_sets[set_id].m_descriptor_slots[binding_point] == buffer_descriptor)
|
||||||
}
|
|
||||||
|
|
||||||
void program::bind_uniform(const VkBufferView &buffer_view, u32 binding_point)
|
|
||||||
{
|
|
||||||
if (m_descriptor_slots[binding_point].matches(buffer_view))
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
next_descriptor_set();
|
m_sets[set_id].notify_descriptor_slot_updated(binding_point, buffer_descriptor);
|
||||||
m_descriptor_set.push(buffer_view, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, binding_point);
|
|
||||||
m_descriptors_dirty[binding_point] = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void program::bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name)
|
void program::bind_uniform(const VkBufferView &buffer_view, u32 set_id, u32 binding_point)
|
||||||
{
|
{
|
||||||
for (const auto &uniform : uniforms[type])
|
if (m_sets[set_id].m_descriptor_slots[binding_point] == buffer_view)
|
||||||
{
|
|
||||||
if (uniform.name == binding_name)
|
|
||||||
{
|
|
||||||
bind_uniform(buffer_view, uniform.location);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rsx_log.notice("vertex buffer not found in program: %s", binding_name.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void program::bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type)
|
|
||||||
{
|
|
||||||
if (m_descriptor_slots[binding_point].matches(buffer_descriptor))
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
next_descriptor_set();
|
m_sets[set_id].notify_descriptor_slot_updated(binding_point, buffer_view);
|
||||||
m_descriptor_set.push(buffer_descriptor, type, binding_point);
|
|
||||||
m_descriptors_dirty[binding_point] = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void program::bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 binding_point)
|
void program::bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 set_id, u32 binding_point)
|
||||||
{
|
{
|
||||||
// FIXME: Unoptimized...
|
auto& set = m_sets[set_id];
|
||||||
bool match = true;
|
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
if (!m_descriptor_slots[binding_point + i].matches(image_descriptors[i]))
|
if (set.m_descriptor_slots[binding_point + i] != image_descriptors[i])
|
||||||
|
{
|
||||||
|
set.notify_descriptor_slot_updated(binding_point + i, image_descriptors[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void program::create_pipeline_layout()
|
||||||
|
{
|
||||||
|
ensure(!m_linked);
|
||||||
|
ensure(m_pipeline_layout == VK_NULL_HANDLE);
|
||||||
|
|
||||||
|
rsx::simple_array<VkPushConstantRange> push_constants{};
|
||||||
|
rsx::simple_array<VkDescriptorSetLayout> set_layouts{};
|
||||||
|
|
||||||
|
for (auto& set : m_sets)
|
||||||
|
{
|
||||||
|
if (!set.m_device)
|
||||||
{
|
{
|
||||||
match = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set.next_descriptor_set(); // Initializes the set layout and allocates first set
|
||||||
|
set_layouts.push_back(set.m_descriptor_set_layout);
|
||||||
|
|
||||||
|
for (const auto& input : set.m_inputs[input_type_push_constant])
|
||||||
|
{
|
||||||
|
const auto& range = input.as_push_constant();
|
||||||
|
push_constants.push_back({
|
||||||
|
.stageFlags = to_shader_stage_flags(input.domain),
|
||||||
|
.offset = range.offset,
|
||||||
|
.size = range.size
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match)
|
VkPipelineLayoutCreateInfo create_info
|
||||||
|
{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||||
|
.flags = 0,
|
||||||
|
.setLayoutCount = set_layouts.size(),
|
||||||
|
.pSetLayouts = set_layouts.data(),
|
||||||
|
.pushConstantRangeCount = push_constants.size(),
|
||||||
|
.pPushConstantRanges = push_constants.data()
|
||||||
|
};
|
||||||
|
CHECK_RESULT(vkCreatePipelineLayout(m_device, &create_info, nullptr, &m_pipeline_layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
program& program::bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point)
|
||||||
|
{
|
||||||
|
VkDescriptorSet bind_sets[binding_set_index_max_enum];
|
||||||
|
unsigned count = 0;
|
||||||
|
|
||||||
|
for (auto& set : m_sets)
|
||||||
|
{
|
||||||
|
if (!set.m_device)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bind_sets[count++] = set.m_descriptor_set.value(); // Current set pointer for binding
|
||||||
|
set.next_descriptor_set(); // Flush queue and update pointers
|
||||||
|
}
|
||||||
|
|
||||||
|
vkCmdBindPipeline(cmd, bind_point, m_pipeline);
|
||||||
|
vkCmdBindDescriptorSets(cmd, bind_point, m_pipeline_layout, 0, count, bind_sets, 0, nullptr);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void descriptor_table_t::destroy()
|
||||||
|
{
|
||||||
|
if (!m_device)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
next_descriptor_set();
|
vkDestroyDescriptorSetLayout(m_device, m_descriptor_set_layout, nullptr);
|
||||||
m_descriptor_set.push(image_descriptors, static_cast<u32>(count), type, binding_point);
|
vk::get_resource_manager()->dispose(m_descriptor_pool);
|
||||||
|
|
||||||
for (int i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
m_descriptors_dirty[binding_point] = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSet program::allocate_descriptor_set()
|
void descriptor_table_t::init(VkDevice dev)
|
||||||
|
{
|
||||||
|
m_device = dev;
|
||||||
|
|
||||||
|
size_t bind_slots_count = 0;
|
||||||
|
for (auto& type_arr : m_inputs)
|
||||||
|
{
|
||||||
|
if (type_arr.empty() || type_arr.front().type == input_type_push_constant)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bind_slots_count += type_arr.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_descriptor_slots.resize(bind_slots_count);
|
||||||
|
std::memset(m_descriptor_slots.data(), 0, sizeof(descriptor_slot_t) * bind_slots_count);
|
||||||
|
|
||||||
|
m_descriptors_dirty.resize(bind_slots_count);
|
||||||
|
std::fill(m_descriptors_dirty.begin(), m_descriptors_dirty.end(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorSet descriptor_table_t::allocate_descriptor_set()
|
||||||
{
|
{
|
||||||
if (!m_descriptor_pool)
|
if (!m_descriptor_pool)
|
||||||
{
|
{
|
||||||
create_descriptor_pool();
|
create_descriptor_pool();
|
||||||
|
create_descriptor_set_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_descriptor_pool->allocate(m_descriptor_set_layout);
|
return m_descriptor_pool->allocate(m_descriptor_set_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void program::next_descriptor_set()
|
void descriptor_table_t::next_descriptor_set()
|
||||||
{
|
{
|
||||||
const auto new_set = allocate_descriptor_set();
|
if (!m_descriptor_set)
|
||||||
const auto old_set = m_descriptor_set.value();
|
|
||||||
|
|
||||||
if (old_set)
|
|
||||||
{
|
{
|
||||||
m_copy_cmds.clear();
|
m_descriptor_set = allocate_descriptor_set();
|
||||||
for (unsigned i = 0; i < m_copy_cmds.size(); ++i)
|
std::fill(m_descriptors_dirty.begin(), m_descriptors_dirty.end(), false);
|
||||||
{
|
return;
|
||||||
if (!m_descriptors_dirty[i])
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reuse already initialized memory. Each command is the same anyway.
|
|
||||||
m_copy_cmds.resize(m_copy_cmds.size() + 1);
|
|
||||||
auto& cmd = m_copy_cmds.back();
|
|
||||||
cmd.srcBinding = cmd.dstBinding = i;
|
|
||||||
cmd.srcSet = old_set;
|
|
||||||
cmd.dstSet = new_set;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_descriptor_set.push(m_copy_cmds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_descriptor_set = allocate_descriptor_set();
|
// Check if we need to actually open a new set
|
||||||
|
if (!m_any_descriptors_dirty)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto old_set = m_descriptor_set.value();
|
||||||
|
auto new_set = allocate_descriptor_set();
|
||||||
|
|
||||||
|
auto push_descriptor_slot = [this](unsigned idx)
|
||||||
|
{
|
||||||
|
const auto& slot = m_descriptor_slots[idx];
|
||||||
|
const VkDescriptorType type = m_descriptor_types[idx];
|
||||||
|
if (auto ptr = std::get_if<VkDescriptorImageInfo>(&slot))
|
||||||
|
{
|
||||||
|
m_descriptor_set.push(*ptr, type, idx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto ptr = std::get_if<VkDescriptorBufferInfo>(&slot))
|
||||||
|
{
|
||||||
|
m_descriptor_set.push(*ptr, type, idx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto ptr = std::get_if<VkBufferView>(&slot))
|
||||||
|
{
|
||||||
|
m_descriptor_set.push(*ptr, type, idx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt::throw_exception("Unexpected descriptor structure at index %u", idx);
|
||||||
|
};
|
||||||
|
|
||||||
|
m_copy_cmds.clear();
|
||||||
|
for (unsigned i = 0; i < m_descriptor_slots.size(); ++i)
|
||||||
|
{
|
||||||
|
if (m_descriptors_dirty[i])
|
||||||
|
{
|
||||||
|
// Push
|
||||||
|
push_descriptor_slot(i);
|
||||||
|
m_descriptors_dirty[i] = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_copy_cmds.push_back({
|
||||||
|
.sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET,
|
||||||
|
.srcSet = old_set,
|
||||||
|
.srcBinding = i,
|
||||||
|
.dstSet = new_set,
|
||||||
|
.dstBinding = i,
|
||||||
|
.descriptorCount = 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
m_descriptor_set.push(m_copy_cmds); // Write previous state
|
||||||
|
m_descriptor_set = new_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
program& program::bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point)
|
void descriptor_table_t::create_descriptor_set_layout()
|
||||||
{
|
|
||||||
VkDescriptorSet set = m_descriptor_set.value();
|
|
||||||
vkCmdBindPipeline(cmd, bind_point, m_pipeline);
|
|
||||||
vkCmdBindDescriptorSets(cmd, bind_point, m_pipeline_layout, 0, 1, &set, 0, nullptr);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void program::create_descriptor_set_layout()
|
|
||||||
{
|
{
|
||||||
ensure(m_descriptor_set_layout == VK_NULL_HANDLE);
|
ensure(m_descriptor_set_layout == VK_NULL_HANDLE);
|
||||||
|
|
||||||
|
@ -425,7 +526,7 @@ namespace vk
|
||||||
m_descriptor_pool_sizes.clear();
|
m_descriptor_pool_sizes.clear();
|
||||||
m_descriptor_pool_sizes.reserve(input_type_max_enum);
|
m_descriptor_pool_sizes.reserve(input_type_max_enum);
|
||||||
|
|
||||||
for (const auto& type_arr : uniforms)
|
for (const auto& type_arr : m_inputs)
|
||||||
{
|
{
|
||||||
if (type_arr.empty() || type_arr.front().type == input_type_push_constant)
|
if (type_arr.empty() || type_arr.front().type == input_type_push_constant)
|
||||||
{
|
{
|
||||||
|
@ -445,6 +546,13 @@ namespace vk
|
||||||
.stageFlags = to_shader_stage_flags(input.domain)
|
.stageFlags = to_shader_stage_flags(input.domain)
|
||||||
};
|
};
|
||||||
bindings.push_back(binding);
|
bindings.push_back(binding);
|
||||||
|
|
||||||
|
if (m_descriptor_types.size() < (input.location + 1))
|
||||||
|
{
|
||||||
|
m_descriptor_types.resize((input.location + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_descriptor_types[input.location] = type;
|
||||||
m_descriptor_pool_sizes.back().descriptorCount++;
|
m_descriptor_pool_sizes.back().descriptorCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -459,38 +567,31 @@ namespace vk
|
||||||
CHECK_RESULT(vkCreateDescriptorSetLayout(m_device, &set_layout_create_info, nullptr, &m_descriptor_set_layout));
|
CHECK_RESULT(vkCreateDescriptorSetLayout(m_device, &set_layout_create_info, nullptr, &m_descriptor_set_layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
void program::create_pipeline_layout()
|
void descriptor_table_t::create_descriptor_pool()
|
||||||
{
|
{
|
||||||
ensure(!linked);
|
|
||||||
ensure(m_pipeline_layout == VK_NULL_HANDLE);
|
|
||||||
|
|
||||||
create_descriptor_set_layout();
|
|
||||||
|
|
||||||
rsx::simple_array<VkPushConstantRange> push_constants{};
|
|
||||||
for (const auto& input : uniforms[input_type_push_constant])
|
|
||||||
{
|
|
||||||
const auto& range = input.as_push_constant();
|
|
||||||
push_constants.push_back({ .offset = range.offset, .size = range.size });
|
|
||||||
}
|
|
||||||
|
|
||||||
VkPipelineLayoutCreateInfo create_info
|
|
||||||
{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
||||||
.flags = 0,
|
|
||||||
.setLayoutCount = 1,
|
|
||||||
.pSetLayouts = &m_descriptor_set_layout,
|
|
||||||
.pushConstantRangeCount = ::size32(push_constants),
|
|
||||||
.pPushConstantRanges = push_constants.data()
|
|
||||||
};
|
|
||||||
CHECK_RESULT(vkCreatePipelineLayout(m_device, &create_info, nullptr, &m_pipeline_layout));
|
|
||||||
}
|
|
||||||
|
|
||||||
void program::create_descriptor_pool()
|
|
||||||
{
|
|
||||||
ensure(linked);
|
|
||||||
|
|
||||||
m_descriptor_pool = std::make_unique<descriptor_pool>();
|
m_descriptor_pool = std::make_unique<descriptor_pool>();
|
||||||
m_descriptor_pool->create(*vk::get_current_renderer(), m_descriptor_pool_sizes);
|
m_descriptor_pool->create(*vk::get_current_renderer(), m_descriptor_pool_sizes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void descriptor_table_t::validate() const
|
||||||
|
{
|
||||||
|
// Check for overlapping locations
|
||||||
|
std::set<u32> taken_locations;
|
||||||
|
|
||||||
|
for (auto& type_arr : m_inputs)
|
||||||
|
{
|
||||||
|
if (type_arr.empty() ||
|
||||||
|
type_arr.front().type == input_type_push_constant)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& input : type_arr)
|
||||||
|
{
|
||||||
|
ensure(taken_locations.find(input.location) == taken_locations.end(), "Overlapping input locations found.");
|
||||||
|
taken_locations.insert(input.location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,8 @@ namespace vk
|
||||||
using bound_data_t = std::variant<bound_buffer, bound_sampler, push_constant_ref>;
|
using bound_data_t = std::variant<bound_buffer, bound_sampler, push_constant_ref>;
|
||||||
bound_data_t bound_data;
|
bound_data_t bound_data;
|
||||||
|
|
||||||
u32 location;
|
u32 set = 0;
|
||||||
|
u32 location = umax;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
inline bound_buffer& as_buffer() { return *std::get_if<bound_buffer>(&bound_data); }
|
inline bound_buffer& as_buffer() { return *std::get_if<bound_buffer>(&bound_data); }
|
||||||
|
@ -69,6 +70,7 @@ namespace vk
|
||||||
::glsl::program_domain domain,
|
::glsl::program_domain domain,
|
||||||
const std::string& name,
|
const std::string& name,
|
||||||
program_input_type type,
|
program_input_type type,
|
||||||
|
u32 set,
|
||||||
u32 location,
|
u32 location,
|
||||||
const bound_data_t& data = bound_buffer{})
|
const bound_data_t& data = bound_buffer{})
|
||||||
{
|
{
|
||||||
|
@ -77,38 +79,13 @@ namespace vk
|
||||||
.domain = domain,
|
.domain = domain,
|
||||||
.type = type,
|
.type = type,
|
||||||
.bound_data = data,
|
.bound_data = data,
|
||||||
|
.set = set,
|
||||||
.location = location,
|
.location = location,
|
||||||
.name = name
|
.name = name
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
union descriptor_slot_t
|
|
||||||
{
|
|
||||||
VkDescriptorImageInfo image_info;
|
|
||||||
VkDescriptorBufferInfo buffer_info;
|
|
||||||
VkBufferView buffer_view;
|
|
||||||
|
|
||||||
bool matches(const VkDescriptorImageInfo& test) const
|
|
||||||
{
|
|
||||||
return test.imageView == image_info.imageView &&
|
|
||||||
test.sampler == image_info.sampler &&
|
|
||||||
test.imageLayout == image_info.imageLayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool matches(const VkDescriptorBufferInfo& test) const
|
|
||||||
{
|
|
||||||
return test.buffer == buffer_info.buffer &&
|
|
||||||
test.offset == buffer_info.offset &&
|
|
||||||
test.range == buffer_info.range;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool matches(VkBufferView test) const
|
|
||||||
{
|
|
||||||
return test == buffer_view;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class shader
|
class shader
|
||||||
{
|
{
|
||||||
::glsl::program_domain type = ::glsl::program_domain::glsl_vertex_program;
|
::glsl::program_domain type = ::glsl::program_domain::glsl_vertex_program;
|
||||||
|
@ -132,37 +109,71 @@ namespace vk
|
||||||
VkShaderModule get_handle() const;
|
VkShaderModule get_handle() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class program
|
using descriptor_slot_t = std::variant<VkDescriptorImageInfo, VkDescriptorBufferInfo, VkBufferView>;
|
||||||
|
|
||||||
|
struct descriptor_table_t
|
||||||
{
|
{
|
||||||
std::array<std::vector<program_input>, input_type_max_enum> uniforms;
|
|
||||||
VkDevice m_device = VK_NULL_HANDLE;
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
std::array<std::vector<program_input>, input_type_max_enum> m_inputs;
|
||||||
VkPipeline m_pipeline = VK_NULL_HANDLE;
|
|
||||||
VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
std::array<u32, 16> fs_texture_bindings;
|
|
||||||
std::array<u32, 16> fs_texture_mirror_bindings;
|
|
||||||
std::array<u32, 4> vs_texture_bindings;
|
|
||||||
bool linked = false;
|
|
||||||
|
|
||||||
std::unique_ptr<vk::descriptor_pool> m_descriptor_pool;
|
std::unique_ptr<vk::descriptor_pool> m_descriptor_pool;
|
||||||
VkDescriptorSetLayout m_descriptor_set_layout = VK_NULL_HANDLE;
|
VkDescriptorSetLayout m_descriptor_set_layout = VK_NULL_HANDLE;
|
||||||
vk::descriptor_set m_descriptor_set{};
|
vk::descriptor_set m_descriptor_set{};
|
||||||
rsx::simple_array<VkDescriptorPoolSize> m_descriptor_pool_sizes;
|
rsx::simple_array<VkDescriptorPoolSize> m_descriptor_pool_sizes;
|
||||||
|
rsx::simple_array<VkDescriptorType> m_descriptor_types;
|
||||||
|
|
||||||
std::vector<descriptor_slot_t> m_descriptor_slots;
|
std::vector<descriptor_slot_t> m_descriptor_slots;
|
||||||
std::vector<bool> m_descriptors_dirty;
|
std::vector<bool> m_descriptors_dirty;
|
||||||
rsx::simple_array<VkCopyDescriptorSet> m_copy_cmds;
|
rsx::simple_array<VkCopyDescriptorSet> m_copy_cmds;
|
||||||
|
bool m_any_descriptors_dirty = false;
|
||||||
|
|
||||||
void init();
|
void init(VkDevice dev);
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
void validate() const;
|
||||||
|
|
||||||
void create_descriptor_set_layout();
|
void create_descriptor_set_layout();
|
||||||
void create_pipeline_layout();
|
|
||||||
void create_descriptor_pool();
|
void create_descriptor_pool();
|
||||||
|
|
||||||
VkDescriptorSet allocate_descriptor_set();
|
VkDescriptorSet allocate_descriptor_set();
|
||||||
void next_descriptor_set();
|
void next_descriptor_set();
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline void notify_descriptor_slot_updated(u32 slot, const T& data)
|
||||||
|
{
|
||||||
|
m_descriptors_dirty[slot] = true;
|
||||||
|
m_descriptor_slots[slot] = data;
|
||||||
|
m_any_descriptors_dirty = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum binding_set_index : u32
|
||||||
|
{
|
||||||
|
// For separate shader objects
|
||||||
|
binding_set_index_vertex = 0,
|
||||||
|
binding_set_index_fragment = 1,
|
||||||
|
|
||||||
|
// Aliases
|
||||||
|
binding_set_index_compute = 0,
|
||||||
|
binding_set_index_unified = 0,
|
||||||
|
|
||||||
|
// Meta
|
||||||
|
binding_set_index_max_enum = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
class program
|
||||||
|
{
|
||||||
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
VkPipeline m_pipeline = VK_NULL_HANDLE;
|
||||||
|
VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
std::variant<VkGraphicsPipelineCreateInfo, VkComputePipelineCreateInfo> m_info;
|
||||||
|
std::array<descriptor_table_t, binding_set_index_max_enum> m_sets;
|
||||||
|
bool m_linked = false;
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void create_pipeline_layout();
|
||||||
|
|
||||||
program& load_uniforms(const std::vector<program_input>& inputs);
|
program& load_uniforms(const std::vector<program_input>& inputs);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -173,20 +184,18 @@ namespace vk
|
||||||
program(program&& other) = delete;
|
program(program&& other) = delete;
|
||||||
~program();
|
~program();
|
||||||
|
|
||||||
program& link();
|
program& link(bool separate_stages);
|
||||||
program& bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point);
|
program& bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point);
|
||||||
|
|
||||||
bool has_uniform(program_input_type type, const std::string &uniform_name);
|
bool has_uniform(program_input_type type, const std::string &uniform_name);
|
||||||
u32 get_uniform_location(program_input_type type, const std::string& uniform_name);
|
std::pair<u32, u32> get_uniform_location(::glsl::program_domain domain, program_input_type type, const std::string& uniform_name);
|
||||||
|
|
||||||
void bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string &uniform_name, VkDescriptorType type);
|
void bind_uniform(const VkDescriptorImageInfo &image_descriptor, u32 set_id, u32 binding_point);
|
||||||
void bind_uniform(const VkDescriptorImageInfo &image_descriptor, int texture_unit, ::glsl::program_domain domain, bool is_stencil_mirror = false);
|
void bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 set_id, u32 binding_point);
|
||||||
void bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point);
|
void bind_uniform(const VkBufferView &buffer_view, u32 set_id, u32 binding_point);
|
||||||
void bind_uniform(const VkBufferView &buffer_view, u32 binding_point);
|
void bind_uniform(const VkBufferView &buffer_view, ::glsl::program_domain domain, program_input_type type, const std::string &binding_name);
|
||||||
void bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name);
|
|
||||||
void bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type);
|
|
||||||
|
|
||||||
void bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 binding_point);
|
void bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 set_id, u32 binding_point);
|
||||||
|
|
||||||
inline VkPipelineLayout layout() const { return m_pipeline_layout; }
|
inline VkPipelineLayout layout() const { return m_pipeline_layout; }
|
||||||
inline VkPipeline value() const { return m_pipeline; }
|
inline VkPipeline value() const { return m_pipeline; }
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace vk
|
||||||
::glsl::program_domain::glsl_compute_program,
|
::glsl::program_domain::glsl_compute_program,
|
||||||
"multisampled",
|
"multisampled",
|
||||||
glsl::input_type_storage_texture,
|
glsl::input_type_storage_texture,
|
||||||
|
0,
|
||||||
0
|
0
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ namespace vk
|
||||||
::glsl::program_domain::glsl_compute_program,
|
::glsl::program_domain::glsl_compute_program,
|
||||||
"resolve",
|
"resolve",
|
||||||
glsl::input_type_storage_texture,
|
glsl::input_type_storage_texture,
|
||||||
|
0,
|
||||||
1
|
1
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
@ -51,8 +53,8 @@ namespace vk
|
||||||
{
|
{
|
||||||
auto msaa_view = multisampled->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_VIEW_MULTISAMPLED));
|
auto msaa_view = multisampled->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_VIEW_MULTISAMPLED));
|
||||||
auto resolved_view = resolve->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_IDENTITY));
|
auto resolved_view = resolve->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_IDENTITY));
|
||||||
m_program->bind_uniform({ VK_NULL_HANDLE, msaa_view->value, multisampled->current_layout }, "multisampled", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
|
m_program->bind_uniform({ VK_NULL_HANDLE, msaa_view->value, multisampled->current_layout }, 0, 0);
|
||||||
m_program->bind_uniform({ VK_NULL_HANDLE, resolved_view->value, resolve->current_layout }, "resolve", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
|
m_program->bind_uniform({ VK_NULL_HANDLE, resolved_view->value, resolve->current_layout }, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(const vk::command_buffer& cmd, vk::viewable_image* msaa_image, vk::viewable_image* resolve_image)
|
void run(const vk::command_buffer& cmd, vk::viewable_image* msaa_image, vk::viewable_image* resolve_image)
|
||||||
|
@ -116,6 +118,7 @@ namespace vk
|
||||||
::glsl::glsl_fragment_program,
|
::glsl::glsl_fragment_program,
|
||||||
"push_constants",
|
"push_constants",
|
||||||
glsl::input_type_push_constant,
|
glsl::input_type_push_constant,
|
||||||
|
0,
|
||||||
umax,
|
umax,
|
||||||
glsl::push_constant_ref{ .size = 16 }
|
glsl::push_constant_ref{ .size = 16 }
|
||||||
));
|
));
|
||||||
|
|
|
@ -471,7 +471,7 @@ namespace vk
|
||||||
void shader_interpreter::update_fragment_textures(const std::array<VkDescriptorImageInfo, 68>& sampled_images)
|
void shader_interpreter::update_fragment_textures(const std::array<VkDescriptorImageInfo, 68>& sampled_images)
|
||||||
{
|
{
|
||||||
// FIXME: Cannot use m_fragment_textures.start now since each interpreter has its own binding layout
|
// FIXME: Cannot use m_fragment_textures.start now since each interpreter has its own binding layout
|
||||||
u32 binding = m_current_interpreter->get_uniform_location(glsl::input_type_texture, "texture1D_array");
|
auto [set, binding] = m_current_interpreter->get_uniform_location(::glsl::glsl_fragment_program, glsl::input_type_texture, "texture1D_array");
|
||||||
if (binding == umax)
|
if (binding == umax)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -480,7 +480,7 @@ namespace vk
|
||||||
const VkDescriptorImageInfo* texture_ptr = sampled_images.data();
|
const VkDescriptorImageInfo* texture_ptr = sampled_images.data();
|
||||||
for (u32 i = 0; i < 4; ++i, ++binding, texture_ptr += 16)
|
for (u32 i = 0; i < 4; ++i, ++binding, texture_ptr += 16)
|
||||||
{
|
{
|
||||||
m_current_interpreter->bind_uniform_array(texture_ptr, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 16, binding);
|
m_current_interpreter->bind_uniform_array(texture_ptr, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 16, set, binding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include "vkutils/device.h"
|
#include "vkutils/device.h"
|
||||||
#include "../Program/GLSLCommon.h"
|
#include "../Program/GLSLCommon.h"
|
||||||
|
|
||||||
|
|
||||||
std::string VKVertexDecompilerThread::getFloatTypeName(usz elementCount)
|
std::string VKVertexDecompilerThread::getFloatTypeName(usz elementCount)
|
||||||
{
|
{
|
||||||
return glsl::getFloatTypeNameImpl(elementCount);
|
return glsl::getFloatTypeNameImpl(elementCount);
|
||||||
|
@ -27,14 +26,57 @@ std::string VKVertexDecompilerThread::compareFunction(COMPARE f, const std::stri
|
||||||
return glsl::compareFunctionImpl(f, Op0, Op1, scalar);
|
return glsl::compareFunctionImpl(f, Op0, Op1, scalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VKVertexDecompilerThread::prepareBindingTable()
|
||||||
|
{
|
||||||
|
u32 location = 0;
|
||||||
|
vk_prog->binding_table.vertex_buffers_location = location;
|
||||||
|
location += 3; // Persistent verts, volatile and layout data
|
||||||
|
|
||||||
|
vk_prog->binding_table.context_buffer_location = location++;
|
||||||
|
if (m_device_props.emulate_conditional_rendering)
|
||||||
|
{
|
||||||
|
vk_prog->binding_table.cr_pred_buffer_location = location++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||||
|
{
|
||||||
|
const bool is_texture_type = PT.type.starts_with("sampler");
|
||||||
|
|
||||||
|
for (const ParamItem& PI : PT.items)
|
||||||
|
{
|
||||||
|
if (is_texture_type)
|
||||||
|
{
|
||||||
|
const int id = vk::get_texture_index(PI.name);
|
||||||
|
vk_prog->binding_table.vtex_location[id] = location++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PI.name.starts_with("vc["))
|
||||||
|
{
|
||||||
|
if (!(m_prog.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS))
|
||||||
|
{
|
||||||
|
vk_prog->binding_table.cbuf_location = location++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk_prog->binding_table.instanced_lut_buffer_location = location++;
|
||||||
|
vk_prog->binding_table.instanced_cbuf_location = location++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VKVertexDecompilerThread::insertHeader(std::stringstream &OS)
|
void VKVertexDecompilerThread::insertHeader(std::stringstream &OS)
|
||||||
{
|
{
|
||||||
|
prepareBindingTable();
|
||||||
|
|
||||||
OS <<
|
OS <<
|
||||||
"#version 450\n\n"
|
"#version 450\n\n"
|
||||||
"#extension GL_ARB_separate_shader_objects : enable\n\n";
|
"#extension GL_ARB_separate_shader_objects : enable\n\n";
|
||||||
|
|
||||||
OS <<
|
OS <<
|
||||||
"layout(std140, set = 0, binding = 0) uniform VertexContextBuffer\n"
|
"layout(std140, set = 0, binding = " << vk_prog->binding_table.context_buffer_location << " ) uniform VertexContextBuffer\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" mat4 scale_offset_mat;\n"
|
" mat4 scale_offset_mat;\n"
|
||||||
" ivec4 user_clip_enabled[2];\n"
|
" ivec4 user_clip_enabled[2];\n"
|
||||||
|
@ -45,13 +87,31 @@ void VKVertexDecompilerThread::insertHeader(std::stringstream &OS)
|
||||||
" float z_far;\n"
|
" float z_far;\n"
|
||||||
"};\n\n";
|
"};\n\n";
|
||||||
|
|
||||||
|
vk::glsl::program_input context_input =
|
||||||
|
{
|
||||||
|
.domain = glsl::glsl_vertex_program,
|
||||||
|
.type = vk::glsl::input_type_uniform_buffer,
|
||||||
|
.location = vk_prog->binding_table.context_buffer_location,
|
||||||
|
.name = "VertexContextBuffer"
|
||||||
|
};
|
||||||
|
inputs.push_back(context_input);
|
||||||
|
|
||||||
if (m_device_props.emulate_conditional_rendering)
|
if (m_device_props.emulate_conditional_rendering)
|
||||||
{
|
{
|
||||||
OS <<
|
OS <<
|
||||||
"layout(std430, set = 0, binding = 8) readonly buffer EXT_Conditional_Rendering\n"
|
"layout(std430, set = 0, binding = " << vk_prog->binding_table.cr_pred_buffer_location << ") readonly buffer EXT_Conditional_Rendering\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" uint conditional_rendering_predicate;\n"
|
" uint conditional_rendering_predicate;\n"
|
||||||
"};\n\n";
|
"};\n\n";
|
||||||
|
|
||||||
|
vk::glsl::program_input predicate_input =
|
||||||
|
{
|
||||||
|
.domain = glsl::glsl_vertex_program,
|
||||||
|
.type = vk::glsl::input_type_storage_buffer,
|
||||||
|
.location = vk_prog->binding_table.cr_pred_buffer_location,
|
||||||
|
.name = "EXT_Conditional_Rendering"
|
||||||
|
};
|
||||||
|
inputs.push_back(predicate_input);
|
||||||
}
|
}
|
||||||
|
|
||||||
OS <<
|
OS <<
|
||||||
|
@ -63,52 +123,50 @@ void VKVertexDecompilerThread::insertHeader(std::stringstream &OS)
|
||||||
" uint layout_ptr_offset;\n"
|
" uint layout_ptr_offset;\n"
|
||||||
" uint xform_constants_offset;\n";
|
" uint xform_constants_offset;\n";
|
||||||
|
|
||||||
|
u32 push_constants_size = 5 * sizeof(u32);
|
||||||
if (m_device_props.emulate_conditional_rendering)
|
if (m_device_props.emulate_conditional_rendering)
|
||||||
{
|
{
|
||||||
|
push_constants_size += sizeof(u32);
|
||||||
OS << " uint conditional_rendering_enabled;\n";
|
OS << " uint conditional_rendering_enabled;\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
OS << "};\n\n";
|
OS << "};\n\n";
|
||||||
|
|
||||||
vk::glsl::program_input in;
|
vk::glsl::program_input push_constants =
|
||||||
in.location = m_binding_table.vertex_params_bind_slot;
|
{
|
||||||
in.domain = glsl::glsl_vertex_program;
|
.domain = glsl::glsl_vertex_program,
|
||||||
in.name = "VertexContextBuffer";
|
.type = vk::glsl::input_type_push_constant,
|
||||||
in.type = vk::glsl::input_type_uniform_buffer;
|
.bound_data = vk::glsl::push_constant_ref{ .offset = 0, .size = push_constants_size }
|
||||||
inputs.push_back(in);
|
};
|
||||||
|
inputs.push_back(push_constants);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKVertexDecompilerThread::insertInputs(std::stringstream& OS, const std::vector<ParamType>& /*inputs*/)
|
void VKVertexDecompilerThread::insertInputs(std::stringstream& OS, const std::vector<ParamType>& /*inputs*/)
|
||||||
{
|
{
|
||||||
OS << "layout(set=0, binding=5) uniform usamplerBuffer persistent_input_stream;\n"; // Data stream with persistent vertex data (cacheable)
|
static const char* input_streams[] =
|
||||||
OS << "layout(set=0, binding=6) uniform usamplerBuffer volatile_input_stream;\n"; // Data stream with per-draw data (registers and immediate draw data)
|
{
|
||||||
OS << "layout(set=0, binding=7) uniform usamplerBuffer vertex_layout_stream;\n"; // Data stream defining vertex data layout
|
"persistent_input_stream", // Data stream with persistent vertex data (cacheable)
|
||||||
|
"volatile_input_stream", // Data stream with per-draw data (registers and immediate draw data)
|
||||||
|
"vertex_layout_stream" // Data stream defining vertex data layout"
|
||||||
|
};
|
||||||
|
|
||||||
vk::glsl::program_input in;
|
int location = vk_prog->binding_table.vertex_buffers_location;
|
||||||
in.location = m_binding_table.vertex_buffers_first_bind_slot;
|
for (const auto& stream : input_streams)
|
||||||
in.domain = glsl::glsl_vertex_program;
|
{
|
||||||
in.name = "persistent_input_stream";
|
OS << "layout(set=0, binding=" << location << ") uniform usamplerBuffer " << stream << ";\n";
|
||||||
in.type = vk::glsl::input_type_texel_buffer;
|
|
||||||
this->inputs.push_back(in);
|
|
||||||
|
|
||||||
in.location = m_binding_table.vertex_buffers_first_bind_slot + 1;
|
vk::glsl::program_input in;
|
||||||
in.domain = glsl::glsl_vertex_program;
|
in.location = location++;
|
||||||
in.name = "volatile_input_stream";
|
in.domain = glsl::glsl_vertex_program;
|
||||||
in.type = vk::glsl::input_type_texel_buffer;
|
in.name = stream;
|
||||||
this->inputs.push_back(in);
|
in.type = vk::glsl::input_type_texel_buffer;
|
||||||
|
this->inputs.push_back(in);
|
||||||
in.location = m_binding_table.vertex_buffers_first_bind_slot + 2;
|
}
|
||||||
in.domain = glsl::glsl_vertex_program;
|
|
||||||
in.name = "vertex_layout_stream";
|
|
||||||
in.type = vk::glsl::input_type_texel_buffer;
|
|
||||||
this->inputs.push_back(in);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std::vector<ParamType> & constants)
|
void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std::vector<ParamType> & constants)
|
||||||
{
|
{
|
||||||
vk::glsl::program_input in;
|
vk::glsl::program_input in;
|
||||||
u32 location = m_binding_table.vertex_textures_first_bind_slot;
|
|
||||||
|
|
||||||
for (const ParamType &PT : constants)
|
for (const ParamType &PT : constants)
|
||||||
{
|
{
|
||||||
for (const ParamItem &PI : PT.items)
|
for (const ParamItem &PI : PT.items)
|
||||||
|
@ -117,12 +175,12 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std
|
||||||
{
|
{
|
||||||
if (!(m_prog.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS))
|
if (!(m_prog.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS))
|
||||||
{
|
{
|
||||||
OS << "layout(std430, set=0, binding=" << static_cast<int>(m_binding_table.vertex_constant_buffers_bind_slot) << ") readonly buffer VertexConstantsBuffer\n";
|
OS << "layout(std430, set=0, binding=" << vk_prog->binding_table.cbuf_location << ") readonly buffer VertexConstantsBuffer\n";
|
||||||
OS << "{\n";
|
OS << "{\n";
|
||||||
OS << " vec4 vc[];\n";
|
OS << " vec4 vc[];\n";
|
||||||
OS << "};\n\n";
|
OS << "};\n\n";
|
||||||
|
|
||||||
in.location = m_binding_table.vertex_constant_buffers_bind_slot;
|
in.location = vk_prog->binding_table.cbuf_location;
|
||||||
in.domain = glsl::glsl_vertex_program;
|
in.domain = glsl::glsl_vertex_program;
|
||||||
in.name = "VertexConstantsBuffer";
|
in.name = "VertexConstantsBuffer";
|
||||||
in.type = vk::glsl::input_type_storage_buffer;
|
in.type = vk::glsl::input_type_storage_buffer;
|
||||||
|
@ -133,26 +191,26 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 1. Bind indirection lookup buffer
|
// 1. Bind indirection lookup buffer
|
||||||
OS << "layout(std430, set=0, binding=" << static_cast<int>(m_binding_table.instancing_lookup_table_bind_slot) << ") readonly buffer InstancingData\n";
|
OS << "layout(std430, set=0, binding=" << vk_prog->binding_table.instanced_lut_buffer_location << ") readonly buffer InstancingData\n";
|
||||||
OS << "{\n";
|
OS << "{\n";
|
||||||
OS << " int constants_addressing_lookup[];\n";
|
OS << " int constants_addressing_lookup[];\n";
|
||||||
OS << "};\n\n";
|
OS << "};\n\n";
|
||||||
|
|
||||||
in.location = m_binding_table.instancing_lookup_table_bind_slot;
|
in.location = vk_prog->binding_table.instanced_lut_buffer_location;
|
||||||
in.domain = glsl::glsl_vertex_program;
|
in.domain = glsl::glsl_vertex_program;
|
||||||
in.name = "InstancingData";
|
in.name = "InstancingData";
|
||||||
in.type = vk::glsl::input_type_storage_buffer;
|
in.type = vk::glsl::input_type_storage_buffer;
|
||||||
inputs.push_back(in);
|
inputs.push_back(in);
|
||||||
|
|
||||||
// 2. Bind actual constants buffer
|
// 2. Bind actual constants buffer
|
||||||
OS << "layout(std430, set=0, binding=" << static_cast<int>(m_binding_table.instancing_constants_buffer_slot) << ") readonly buffer VertexConstantsBuffer\n";
|
OS << "layout(std430, set=0, binding=" << vk_prog->binding_table.instanced_cbuf_location << ") readonly buffer VertexConstantsBuffer\n";
|
||||||
OS << "{\n";
|
OS << "{\n";
|
||||||
OS << " vec4 instanced_constants_array[];\n";
|
OS << " vec4 instanced_constants_array[];\n";
|
||||||
OS << "};\n\n";
|
OS << "};\n\n";
|
||||||
|
|
||||||
OS << "#define CONSTANTS_ARRAY_LENGTH " << (properties.has_indexed_constants ? 468 : ::size32(m_constant_ids)) << "\n\n";
|
OS << "#define CONSTANTS_ARRAY_LENGTH " << (properties.has_indexed_constants ? 468 : ::size32(m_constant_ids)) << "\n\n";
|
||||||
|
|
||||||
in.location = m_binding_table.instancing_constants_buffer_slot;
|
in.location = vk_prog->binding_table.instanced_cbuf_location;
|
||||||
in.domain = glsl::glsl_vertex_program;
|
in.domain = glsl::glsl_vertex_program;
|
||||||
in.name = "VertexConstantsBuffer";
|
in.name = "VertexConstantsBuffer";
|
||||||
in.type = vk::glsl::input_type_storage_buffer;
|
in.type = vk::glsl::input_type_storage_buffer;
|
||||||
|
@ -166,7 +224,8 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std
|
||||||
PT.type == "sampler1D" ||
|
PT.type == "sampler1D" ||
|
||||||
PT.type == "sampler3D")
|
PT.type == "sampler3D")
|
||||||
{
|
{
|
||||||
in.location = location;
|
const int id = vk::get_texture_index(PI.name);
|
||||||
|
in.location = vk_prog->binding_table.vtex_location[id];
|
||||||
in.name = PI.name;
|
in.name = PI.name;
|
||||||
in.type = vk::glsl::input_type_texture;
|
in.type = vk::glsl::input_type_texture;
|
||||||
|
|
||||||
|
@ -190,7 +249,7 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OS << "layout(set = 0, binding=" << location++ << ") uniform " << samplerType << " " << PI.name << ";\n";
|
OS << "layout(set = 0, binding=" << in.location << ") uniform " << samplerType << " " << PI.name << ";\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -371,8 +430,6 @@ void VKVertexDecompilerThread::insertMainEnd(std::stringstream & OS)
|
||||||
void VKVertexDecompilerThread::Task()
|
void VKVertexDecompilerThread::Task()
|
||||||
{
|
{
|
||||||
m_device_props.emulate_conditional_rendering = vk::emulate_conditional_rendering();
|
m_device_props.emulate_conditional_rendering = vk::emulate_conditional_rendering();
|
||||||
m_binding_table = vk::g_render_device->get_pipeline_binding_table();
|
|
||||||
|
|
||||||
m_shader = Decompile();
|
m_shader = Decompile();
|
||||||
vk_prog->SetInputs(inputs);
|
vk_prog->SetInputs(inputs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ struct VKVertexDecompilerThread : public VertexProgramDecompiler
|
||||||
std::string &m_shader;
|
std::string &m_shader;
|
||||||
std::vector<vk::glsl::program_input> inputs;
|
std::vector<vk::glsl::program_input> inputs;
|
||||||
class VKVertexProgram *vk_prog;
|
class VKVertexProgram *vk_prog;
|
||||||
vk::pipeline_binding_table m_binding_table{};
|
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
@ -36,6 +35,8 @@ protected:
|
||||||
void insertMainStart(std::stringstream &OS) override;
|
void insertMainStart(std::stringstream &OS) override;
|
||||||
void insertMainEnd(std::stringstream &OS) override;
|
void insertMainEnd(std::stringstream &OS) override;
|
||||||
|
|
||||||
|
void prepareBindingTable();
|
||||||
|
|
||||||
const RSXVertexProgram &rsx_vertex_program;
|
const RSXVertexProgram &rsx_vertex_program;
|
||||||
public:
|
public:
|
||||||
VKVertexDecompilerThread(const RSXVertexProgram &prog, std::string& shader, ParamArray&, class VKVertexProgram &dst)
|
VKVertexDecompilerThread(const RSXVertexProgram &prog, std::string& shader, ParamArray&, class VKVertexProgram &dst)
|
||||||
|
@ -61,6 +62,19 @@ public:
|
||||||
vk::glsl::shader shader;
|
vk::glsl::shader shader;
|
||||||
std::vector<vk::glsl::program_input> uniforms;
|
std::vector<vk::glsl::program_input> uniforms;
|
||||||
|
|
||||||
|
// Quick attribute indices
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u32 context_buffer_location = umax; // Vertex program context
|
||||||
|
u32 cr_pred_buffer_location = umax; // Conditional rendering predicate
|
||||||
|
u32 vertex_buffers_location = umax; // Vertex input streams (3)
|
||||||
|
u32 cbuf_location = umax; // Vertex program constants register file
|
||||||
|
u32 instanced_lut_buffer_location = umax; // Instancing redirection table
|
||||||
|
u32 instanced_cbuf_location = umax; // Instancing constants register file
|
||||||
|
u32 vtex_location[4]; // Vertex textures (inf)
|
||||||
|
|
||||||
|
} binding_table;
|
||||||
|
|
||||||
void Decompile(const RSXVertexProgram& prog);
|
void Decompile(const RSXVertexProgram& prog);
|
||||||
void Compile();
|
void Compile();
|
||||||
void SetInputs(std::vector<vk::glsl::program_input>& inputs);
|
void SetInputs(std::vector<vk::glsl::program_input>& inputs);
|
||||||
|
|
|
@ -76,6 +76,7 @@ namespace vk
|
||||||
::glsl::program_domain::glsl_compute_program,
|
::glsl::program_domain::glsl_compute_program,
|
||||||
"InputTexture",
|
"InputTexture",
|
||||||
vk::glsl::input_type_texture,
|
vk::glsl::input_type_texture,
|
||||||
|
0,
|
||||||
0
|
0
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@ -83,6 +84,7 @@ namespace vk
|
||||||
::glsl::program_domain::glsl_compute_program,
|
::glsl::program_domain::glsl_compute_program,
|
||||||
"OutputTexture",
|
"OutputTexture",
|
||||||
vk::glsl::input_type_storage_texture,
|
vk::glsl::input_type_storage_texture,
|
||||||
|
0,
|
||||||
1
|
1
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
@ -103,8 +105,8 @@ namespace vk
|
||||||
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);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_program->bind_uniform({ m_sampler->value, m_input_image->value, m_input_image->image()->current_layout }, "InputTexture", VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
|
m_program->bind_uniform({ m_sampler->value, m_input_image->value, m_input_image->image()->current_layout }, 0, 0);
|
||||||
m_program->bind_uniform({ VK_NULL_HANDLE, m_output_image->value, m_output_image->image()->current_layout }, "OutputTexture", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
|
m_program->bind_uniform({ VK_NULL_HANDLE, m_output_image->value, m_output_image->image()->current_layout }, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fsr_pass::run(const vk::command_buffer& cmd, vk::viewable_image* src, vk::viewable_image* dst, const size2u& input_size, const size2u& output_size)
|
void fsr_pass::run(const vk::command_buffer& cmd, vk::viewable_image* src, vk::viewable_image* dst, const size2u& input_size, const size2u& output_size)
|
||||||
|
|
|
@ -333,11 +333,6 @@ namespace vk
|
||||||
return &m_handle;
|
return &m_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSet descriptor_set::value() const
|
|
||||||
{
|
|
||||||
return m_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void descriptor_set::push(const VkBufferView& buffer_view, VkDescriptorType type, u32 binding)
|
void descriptor_set::push(const VkBufferView& buffer_view, VkDescriptorType type, u32 binding)
|
||||||
{
|
{
|
||||||
m_push_type_mask |= (1ull << type);
|
m_push_type_mask |= (1ull << type);
|
||||||
|
|
|
@ -94,8 +94,10 @@ namespace vk
|
||||||
void swap(descriptor_set& other);
|
void swap(descriptor_set& other);
|
||||||
descriptor_set& operator = (VkDescriptorSet set);
|
descriptor_set& operator = (VkDescriptorSet set);
|
||||||
|
|
||||||
|
VkDescriptorSet value() const { return m_handle; }
|
||||||
|
operator bool() const { return m_handle != VK_NULL_HANDLE; }
|
||||||
|
|
||||||
VkDescriptorSet* ptr();
|
VkDescriptorSet* ptr();
|
||||||
VkDescriptorSet value() const;
|
|
||||||
void push(const VkBufferView& buffer_view, VkDescriptorType type, u32 binding);
|
void push(const VkBufferView& buffer_view, VkDescriptorType type, u32 binding);
|
||||||
void push(const VkDescriptorBufferInfo& buffer_info, VkDescriptorType type, u32 binding);
|
void push(const VkDescriptorBufferInfo& buffer_info, VkDescriptorType type, u32 binding);
|
||||||
void push(const VkDescriptorImageInfo& image_info, VkDescriptorType type, u32 binding);
|
void push(const VkDescriptorImageInfo& image_info, VkDescriptorType type, u32 binding);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue