rsx: Framebuffer fixes

Primary:
- Fix SET_SURFACE_CLEAR channel mask - it has been wrong for all these
  years! Layout is RGBA not ARGB/BGRA like other registers

Other Fixes:
- vk: Implement subchannel clears using overla pass
- vk: Simplify and clean up state management
- gl: Fix nullptr deref in case of failed subresource copy
- vk/gl: Ignore float buffer clears as hardware seems to do
This commit is contained in:
kd-11 2018-04-12 14:13:13 +03:00 committed by kd-11
parent 9abbbb79ae
commit 63d9cb37ec
8 changed files with 459 additions and 209 deletions

View file

@ -401,6 +401,8 @@ void GLGSRender::end()
//Bind textures and resolve external copy operations //Bind textures and resolve external copy operations
std::chrono::time_point<steady_clock> textures_start = steady_clock::now(); std::chrono::time_point<steady_clock> textures_start = steady_clock::now();
int unused_location; int unused_location;
void *unused = nullptr;
gl::texture_view* tmp_view;
for (int i = 0; i < rsx::limits::fragment_textures_count; ++i) for (int i = 0; i < rsx::limits::fragment_textures_count; ++i)
{ {
@ -417,10 +419,10 @@ void GLGSRender::end()
{ {
sampler_state->image_handle->bind(); sampler_state->image_handle->bind();
} }
else if (sampler_state->external_subresource_desc.external_handle) else if (sampler_state->external_subresource_desc.external_handle &&
(tmp_view = m_gl_texture_cache.create_temporary_subresource(unused, sampler_state->external_subresource_desc)))
{ {
void *unused = nullptr; tmp_view->bind();
m_gl_texture_cache.create_temporary_subresource(unused, sampler_state->external_subresource_desc)->bind();
} }
else else
{ {
@ -967,10 +969,14 @@ void GLGSRender::clear_surface(u32 arg)
case rsx::surface_color_format::x32: case rsx::surface_color_format::x32:
case rsx::surface_color_format::w16z16y16x16: case rsx::surface_color_format::w16z16y16x16:
case rsx::surface_color_format::w32z32y32x32: case rsx::surface_color_format::w32z32y32x32:
{
//Nop
break;
}
case rsx::surface_color_format::g8b8: case rsx::surface_color_format::g8b8:
{ {
//NOP colormask = rsx::get_g8b8_r8g8_colormask(colormask);
break; // Fall through
} }
default: default:
{ {

View file

@ -158,7 +158,7 @@ struct driver_state
{ {
if (!test_property(GL_COLOR_WRITEMASK, mask)) if (!test_property(GL_COLOR_WRITEMASK, mask))
{ {
glColorMask(((mask & 0x20) ? 1 : 0), ((mask & 0x40) ? 1 : 0), ((mask & 0x80) ? 1 : 0), ((mask & 0x10) ? 1 : 0)); glColorMask(((mask & 0x10) ? 1 : 0), ((mask & 0x20) ? 1 : 0), ((mask & 0x40) ? 1 : 0), ((mask & 0x80) ? 1 : 0));
properties[GL_COLOR_WRITEMASK] = mask; properties[GL_COLOR_WRITEMASK] = mask;
} }
} }
@ -166,10 +166,10 @@ struct driver_state
void color_mask(bool r, bool g, bool b, bool a) void color_mask(bool r, bool g, bool b, bool a)
{ {
u32 mask = 0; u32 mask = 0;
if (r) mask |= 0x20; if (r) mask |= 0x10;
if (g) mask |= 0x40; if (g) mask |= 0x20;
if (b) mask |= 0x80; if (b) mask |= 0x40;
if (a) mask |= 0x10; if (a) mask |= 0x80;
color_mask(mask); color_mask(mask);
} }

View file

@ -101,7 +101,7 @@ namespace vk
case rsx::surface_color_format::g8b8: case rsx::surface_color_format::g8b8:
{ {
VkComponentMapping gb_rg = { VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R }; VkComponentMapping gb_rg = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G };
return std::make_pair(VK_FORMAT_R8G8_UNORM, gb_rg); return std::make_pair(VK_FORMAT_R8G8_UNORM, gb_rg);
} }
@ -625,6 +625,9 @@ VKGSRender::VKGSRender() : GSRender()
m_depth_scaler.reset(new vk::depth_scaling_pass()); m_depth_scaler.reset(new vk::depth_scaling_pass());
m_depth_scaler->create(*m_device); m_depth_scaler->create(*m_device);
m_attachment_clear_pass.reset(new vk::attachment_clear_pass());
m_attachment_clear_pass->create(*m_device);
m_prog_buffer.reset(new VKProgramBuffer(m_render_passes.data())); m_prog_buffer.reset(new VKProgramBuffer(m_render_passes.data()));
if (g_cfg.video.disable_vertex_cache) if (g_cfg.video.disable_vertex_cache)
@ -632,7 +635,7 @@ VKGSRender::VKGSRender() : GSRender()
else else
m_vertex_cache.reset(new vk::weak_vertex_cache()); m_vertex_cache.reset(new vk::weak_vertex_cache());
m_shaders_cache.reset(new vk::shader_cache(*m_prog_buffer.get(), "vulkan", "v1.2")); m_shaders_cache.reset(new vk::shader_cache(*m_prog_buffer.get(), "vulkan", "v1.25"));
open_command_buffer(); open_command_buffer();
@ -752,6 +755,10 @@ VKGSRender::~VKGSRender()
m_depth_scaler->destroy(); m_depth_scaler->destroy();
m_depth_scaler.reset(); m_depth_scaler.reset();
//Attachment clear helper
m_attachment_clear_pass->destroy();
m_attachment_clear_pass.reset();
//Pipeline descriptors //Pipeline descriptors
vkDestroyPipelineLayout(*m_device, pipeline_layout, nullptr); vkDestroyPipelineLayout(*m_device, pipeline_layout, nullptr);
vkDestroyDescriptorSetLayout(*m_device, descriptor_layouts, nullptr); vkDestroyDescriptorSetLayout(*m_device, descriptor_layouts, nullptr);
@ -1076,7 +1083,6 @@ void VKGSRender::end()
std::chrono::time_point<steady_clock> textures_start = vertex_end; std::chrono::time_point<steady_clock> textures_start = vertex_end;
auto ds = std::get<1>(m_rtts.m_bound_depth_stencil); auto ds = std::get<1>(m_rtts.m_bound_depth_stencil);
//Check for data casts //Check for data casts
@ -1084,6 +1090,13 @@ void VKGSRender::end()
{ {
if (ds->old_contents->info.format == VK_FORMAT_B8G8R8A8_UNORM) if (ds->old_contents->info.format == VK_FORMAT_B8G8R8A8_UNORM)
{ {
//This routine does not recover stencil data, initialize to 255
VkClearDepthStencilValue clear_depth = { 1.f, 255 };
VkImageSubresourceRange range = { VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, 1 };
change_image_layout(*m_current_command_buffer, ds, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
vkCmdClearDepthStencilImage(*m_current_command_buffer, ds->value, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_depth, 1, &range);
change_image_layout(*m_current_command_buffer, ds, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
auto rp = vk::get_render_pass_location(VK_FORMAT_UNDEFINED, ds->info.format, 0); auto rp = vk::get_render_pass_location(VK_FORMAT_UNDEFINED, ds->info.format, 0);
auto render_pass = m_render_passes[rp]; auto render_pass = m_render_passes[rp];
m_depth_converter->run(*m_current_command_buffer, ds->width(), ds->height(), ds, ds->old_contents->get_view(0xAAE4, rsx::default_remap_vector), render_pass, m_framebuffers_to_clean); m_depth_converter->run(*m_current_command_buffer, ds->width(), ds->height(), ds, ds->old_contents->get_view(0xAAE4, rsx::default_remap_vector), render_pass, m_framebuffers_to_clean);
@ -1678,41 +1691,96 @@ void VKGSRender::clear_surface(u32 mask)
if (mask & 0x2) if (mask & 0x2)
{ {
if (surface_depth_format == rsx::surface_depth_format::z24s8) if (surface_depth_format == rsx::surface_depth_format::z24s8 &&
rsx::method_registers.stencil_mask() != 0)
{ {
u8 clear_stencil = rsx::method_registers.stencil_clear_value(); u8 clear_stencil = rsx::method_registers.stencil_clear_value();
depth_stencil_clear_values.depthStencil.stencil = clear_stencil; depth_stencil_clear_values.depthStencil.stencil = clear_stencil;
depth_stencil_mask |= VK_IMAGE_ASPECT_STENCIL_BIT; depth_stencil_mask |= VK_IMAGE_ASPECT_STENCIL_BIT;
} }
} }
if (mask & 0xF0) if (auto colormask = (mask & 0xF0))
{ {
if (m_draw_buffers_count > 0) if (m_draw_buffers_count > 0)
{ {
u8 clear_a = rsx::method_registers.clear_color_a(); bool use_fast_clear = false;
u8 clear_r = rsx::method_registers.clear_color_r(); bool ignore_clear = false;
u8 clear_g = rsx::method_registers.clear_color_g(); switch (rsx::method_registers.surface_color())
u8 clear_b = rsx::method_registers.clear_color_b();
color_clear_values.color.float32[0] = (float)clear_r / 255;
color_clear_values.color.float32[1] = (float)clear_g / 255;
color_clear_values.color.float32[2] = (float)clear_b / 255;
color_clear_values.color.float32[3] = (float)clear_a / 255;
for (u32 index = 0; index < m_draw_buffers_count; ++index)
{ {
clear_descriptors.push_back({ VK_IMAGE_ASPECT_COLOR_BIT, index, color_clear_values }); case rsx::surface_color_format::x32:
} case rsx::surface_color_format::w16z16y16x16:
case rsx::surface_color_format::w32z32y32x32:
//NOP
ignore_clear = true;
break;
case rsx::surface_color_format::g8b8:
colormask = rsx::get_g8b8_r8g8_colormask(colormask);
use_fast_clear = (colormask == (0x10 | 0x20));
ignore_clear = (colormask == 0);
colormask |= (0x40 | 0x80);
break;
default:
use_fast_clear = (colormask == (0x10 | 0x20 | 0x40 | 0x80));
break;
};
for (auto &rtt : m_rtts.m_bound_render_targets) if (!ignore_clear)
{ {
if (std::get<0>(rtt) != 0) u8 clear_a = rsx::method_registers.clear_color_a();
u8 clear_r = rsx::method_registers.clear_color_r();
u8 clear_g = rsx::method_registers.clear_color_g();
u8 clear_b = rsx::method_registers.clear_color_b();
color_clear_values.color.float32[0] = (float)clear_r / 255;
color_clear_values.color.float32[1] = (float)clear_g / 255;
color_clear_values.color.float32[2] = (float)clear_b / 255;
color_clear_values.color.float32[3] = (float)clear_a / 255;
if (use_fast_clear)
{ {
std::get<1>(rtt)->dirty = false; for (u32 index = 0; index < m_draw_buffers_count; ++index)
std::get<1>(rtt)->old_contents = nullptr; {
clear_descriptors.push_back({ VK_IMAGE_ASPECT_COLOR_BIT, index, color_clear_values });
}
}
else
{
color4f clear_color =
{
color_clear_values.color.float32[0],
color_clear_values.color.float32[1],
color_clear_values.color.float32[2],
color_clear_values.color.float32[3]
};
m_attachment_clear_pass->update_config(colormask, clear_color);
for (u32 index = 0; index < m_draw_buffers_count; ++index)
{
if (auto rtt = std::get<1>(m_rtts.m_bound_render_targets[index]))
{
vk::insert_texture_barrier(*m_current_command_buffer, rtt);
m_attachment_clear_pass->run(*m_current_command_buffer, rtt->width(), rtt->height(),
rtt, rtt->get_view(0xAAE4, rsx::default_remap_vector),
m_draw_fbo->info.renderPass, m_framebuffers_to_clean);
}
else
fmt::throw_exception("Unreachable" HERE);
}
//Fush unconditinally - parameters might not persist
//TODO: Better parameter management for overlay passes
flush_command_queue();
}
for (auto &rtt : m_rtts.m_bound_render_targets)
{
if (std::get<0>(rtt) != 0)
{
std::get<1>(rtt)->dirty = false;
std::get<1>(rtt)->old_contents = nullptr;
}
} }
} }
} }
@ -1966,6 +2034,7 @@ void VKGSRender::process_swap_request(frame_context_t *ctx, bool free_resources)
m_text_writer->reset_descriptors(); m_text_writer->reset_descriptors();
} }
m_attachment_clear_pass->free_resources();
m_depth_converter->free_resources(); m_depth_converter->free_resources();
m_depth_scaler->free_resources(); m_depth_scaler->free_resources();
m_ui_renderer->free_resources(); m_ui_renderer->free_resources();
@ -2154,22 +2223,32 @@ void VKGSRender::load_program(const vk::vertex_upload_info& vertex_info)
vk::pipeline_props properties = {}; vk::pipeline_props properties = {};
// Input assembly
bool emulated_primitive_type; bool emulated_primitive_type;
properties.state.set_primitive_type(vk::get_appropriate_topology(rsx::method_registers.current_draw_clause.primitive, emulated_primitive_type));
properties.ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
properties.ia.topology = vk::get_appropriate_topology(rsx::method_registers.current_draw_clause.primitive, emulated_primitive_type);
const bool restarts_valid = rsx::method_registers.current_draw_clause.command == rsx::draw_command::indexed && !emulated_primitive_type && !rsx::method_registers.current_draw_clause.is_disjoint_primitive; const bool restarts_valid = rsx::method_registers.current_draw_clause.command == rsx::draw_command::indexed && !emulated_primitive_type && !rsx::method_registers.current_draw_clause.is_disjoint_primitive;
if (rsx::method_registers.restart_index_enabled() && !vk::emulate_primitive_restart() && restarts_valid) if (rsx::method_registers.restart_index_enabled() && !vk::emulate_primitive_restart() && restarts_valid)
properties.ia.primitiveRestartEnable = VK_TRUE; properties.state.enable_primitive_restart();
else
properties.ia.primitiveRestartEnable = VK_FALSE;
for (int i = 0; i < 4; ++i) // Rasterizer state
{ properties.state.set_attachment_count(m_draw_buffers_count);
properties.att_state[i].colorWriteMask = 0xf; properties.state.set_depth_mask(rsx::method_registers.depth_write_enabled());
properties.att_state[i].blendEnable = VK_FALSE; properties.state.set_front_face(vk::get_front_face(rsx::method_registers.front_face_mode()));
} properties.state.enable_depth_clamp(rsx::method_registers.depth_clamp_enabled() || !rsx::method_registers.depth_clip_enabled());
properties.state.enable_depth_bias(true);
if (rsx::method_registers.depth_test_enabled())
properties.state.enable_depth_test(vk::get_compare_func(rsx::method_registers.depth_func()));
if (rsx::method_registers.logic_op_enabled())
properties.state.enable_logic_op(vk::get_logic_op(rsx::method_registers.logic_operation()));
if (rsx::method_registers.depth_bounds_test_enabled())
properties.state.enable_depth_bounds_test();
if (rsx::method_registers.cull_face_enabled())
properties.state.enable_cull_face(vk::get_cull_face(rsx::method_registers.cull_face_mode()));
bool color_mask_b = rsx::method_registers.color_mask_b(); bool color_mask_b = rsx::method_registers.color_mask_b();
bool color_mask_g = rsx::method_registers.color_mask_g(); bool color_mask_g = rsx::method_registers.color_mask_g();
@ -2177,21 +2256,9 @@ void VKGSRender::load_program(const vk::vertex_upload_info& vertex_info)
bool color_mask_a = rsx::method_registers.color_mask_a(); bool color_mask_a = rsx::method_registers.color_mask_a();
if (rsx::method_registers.surface_color() == rsx::surface_color_format::g8b8) if (rsx::method_registers.surface_color() == rsx::surface_color_format::g8b8)
{
//Map GB components onto RG
rsx::get_g8b8_r8g8_colormask(color_mask_r, color_mask_g, color_mask_b, color_mask_a); rsx::get_g8b8_r8g8_colormask(color_mask_r, color_mask_g, color_mask_b, color_mask_a);
}
VkColorComponentFlags mask = 0; properties.state.set_color_mask(color_mask_r, color_mask_g, color_mask_b, color_mask_a);
if (color_mask_a) mask |= VK_COLOR_COMPONENT_A_BIT;
if (color_mask_b) mask |= VK_COLOR_COMPONENT_B_BIT;
if (color_mask_g) mask |= VK_COLOR_COMPONENT_G_BIT;
if (color_mask_r) mask |= VK_COLOR_COMPONENT_R_BIT;
for (u8 idx = 0; idx < m_draw_buffers_count; ++idx)
{
properties.att_state[idx].colorWriteMask = mask;
}
bool mrt_blend_enabled[] = bool mrt_blend_enabled[] =
{ {
@ -2238,84 +2305,50 @@ void VKGSRender::load_program(const vk::vertex_upload_info& vertex_info)
{ {
if (mrt_blend_enabled[idx]) if (mrt_blend_enabled[idx])
{ {
properties.att_state[idx].blendEnable = VK_TRUE; properties.state.enable_blend(idx, sfactor_rgb, sfactor_a, dfactor_rgb, dfactor_a, equation_rgb, equation_a);
properties.att_state[idx].srcColorBlendFactor = sfactor_rgb;
properties.att_state[idx].dstColorBlendFactor = dfactor_rgb;
properties.att_state[idx].srcAlphaBlendFactor = sfactor_a;
properties.att_state[idx].dstAlphaBlendFactor = dfactor_a;
properties.att_state[idx].colorBlendOp = equation_rgb;
properties.att_state[idx].alphaBlendOp = equation_a;
} }
} }
} }
properties.cs.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
properties.cs.attachmentCount = m_draw_buffers_count;
properties.cs.pAttachments = properties.att_state;
if (rsx::method_registers.logic_op_enabled())
{
properties.cs.logicOpEnable = true;
properties.cs.logicOp = vk::get_logic_op(rsx::method_registers.logic_operation());
}
properties.ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
properties.ds.depthWriteEnable = rsx::method_registers.depth_write_enabled() ? VK_TRUE : VK_FALSE;
if (rsx::method_registers.depth_bounds_test_enabled())
{
properties.ds.depthBoundsTestEnable = VK_TRUE;
}
else
properties.ds.depthBoundsTestEnable = VK_FALSE;
if (rsx::method_registers.stencil_test_enabled()) if (rsx::method_registers.stencil_test_enabled())
{ {
properties.ds.stencilTestEnable = VK_TRUE; if (!rsx::method_registers.two_sided_stencil_test_enabled())
properties.ds.front.failOp = vk::get_stencil_op(rsx::method_registers.stencil_op_fail());
properties.ds.front.passOp = vk::get_stencil_op(rsx::method_registers.stencil_op_zpass());
properties.ds.front.depthFailOp = vk::get_stencil_op(rsx::method_registers.stencil_op_zfail());
properties.ds.front.compareOp = vk::get_compare_func(rsx::method_registers.stencil_func());
if (rsx::method_registers.two_sided_stencil_test_enabled())
{ {
properties.ds.back.failOp = vk::get_stencil_op(rsx::method_registers.back_stencil_op_fail()); properties.state.set_stencil_mask(rsx::method_registers.stencil_mask());
properties.ds.back.passOp = vk::get_stencil_op(rsx::method_registers.back_stencil_op_zpass());
properties.ds.back.depthFailOp = vk::get_stencil_op(rsx::method_registers.back_stencil_op_zfail()); properties.state.enable_stencil_test(
properties.ds.back.compareOp = vk::get_compare_func(rsx::method_registers.back_stencil_func()); vk::get_stencil_op(rsx::method_registers.stencil_op_fail()),
vk::get_stencil_op(rsx::method_registers.stencil_op_zfail()),
vk::get_stencil_op(rsx::method_registers.stencil_op_zpass()),
vk::get_compare_func(rsx::method_registers.stencil_func()),
rsx::method_registers.stencil_func_mask(),
rsx::method_registers.stencil_func_ref());
} }
else else
properties.ds.back = properties.ds.front; {
properties.state.set_stencil_mask_separate(0, rsx::method_registers.stencil_mask());
properties.state.set_stencil_mask_separate(1, rsx::method_registers.back_stencil_mask());
properties.state.enable_stencil_test_separate(0,
vk::get_stencil_op(rsx::method_registers.stencil_op_fail()),
vk::get_stencil_op(rsx::method_registers.stencil_op_zfail()),
vk::get_stencil_op(rsx::method_registers.stencil_op_zpass()),
vk::get_compare_func(rsx::method_registers.stencil_func()),
rsx::method_registers.stencil_func_mask(),
rsx::method_registers.stencil_func_ref());
properties.state.enable_stencil_test_separate(1,
vk::get_stencil_op(rsx::method_registers.back_stencil_op_fail()),
vk::get_stencil_op(rsx::method_registers.back_stencil_op_zfail()),
vk::get_stencil_op(rsx::method_registers.back_stencil_op_zpass()),
vk::get_compare_func(rsx::method_registers.back_stencil_func()),
rsx::method_registers.back_stencil_func_mask(),
rsx::method_registers.back_stencil_func_ref());
}
} }
else
properties.ds.stencilTestEnable = VK_FALSE;
if (rsx::method_registers.depth_test_enabled())
{
properties.ds.depthTestEnable = VK_TRUE;
properties.ds.depthCompareOp = vk::get_compare_func(rsx::method_registers.depth_func());
}
else
properties.ds.depthTestEnable = VK_FALSE;
properties.rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
properties.rs.polygonMode = VK_POLYGON_MODE_FILL;
properties.rs.depthClampEnable = rsx::method_registers.depth_clamp_enabled() || !rsx::method_registers.depth_clip_enabled();
properties.rs.rasterizerDiscardEnable = VK_FALSE;
//Disabled by setting factors to 0 as needed
properties.rs.depthBiasEnable = VK_TRUE;
if (rsx::method_registers.cull_face_enabled())
properties.rs.cullMode = vk::get_cull_face(rsx::method_registers.cull_face_mode());
else
properties.rs.cullMode = VK_CULL_MODE_NONE;
properties.rs.frontFace = vk::get_front_face(rsx::method_registers.front_face_mode());
properties.render_pass = m_render_passes[m_current_renderpass_id]; properties.render_pass = m_render_passes[m_current_renderpass_id];
properties.render_pass_location = (int)m_current_renderpass_id; properties.render_pass_location = (int)m_current_renderpass_id;
properties.num_targets = m_draw_buffers_count; properties.num_targets = m_draw_buffers_count;
vk::enter_uninterruptible(); vk::enter_uninterruptible();

View file

@ -264,6 +264,7 @@ private:
std::unique_ptr<vk::depth_convert_pass> m_depth_converter; std::unique_ptr<vk::depth_convert_pass> m_depth_converter;
std::unique_ptr<vk::depth_scaling_pass> m_depth_scaler; std::unique_ptr<vk::depth_scaling_pass> m_depth_scaler;
std::unique_ptr<vk::ui_overlay_renderer> m_ui_renderer; std::unique_ptr<vk::ui_overlay_renderer> m_ui_renderer;
std::unique_ptr<vk::attachment_clear_pass> m_attachment_clear_pass;
shared_mutex m_sampler_mutex; shared_mutex m_sampler_mutex;
u64 surface_store_tag = 0; u64 surface_store_tag = 0;

View file

@ -2098,6 +2098,164 @@ public:
} }
}; };
class graphics_pipeline_state
{
public:
VkPipelineInputAssemblyStateCreateInfo ia;
VkPipelineDepthStencilStateCreateInfo ds;
VkPipelineColorBlendAttachmentState att_state[4];
VkPipelineColorBlendStateCreateInfo cs;
VkPipelineRasterizationStateCreateInfo rs;
graphics_pipeline_state()
{
ia = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
cs = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
ds = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
rs = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
for (int i = 0; i < 4; ++i)
{
att_state[i] = {};
}
rs.polygonMode = VK_POLYGON_MODE_FILL;
rs.cullMode = VK_CULL_MODE_NONE;
rs.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rs.lineWidth = 1.f;
}
~graphics_pipeline_state()
{}
void set_primitive_type(VkPrimitiveTopology type)
{
ia.topology = type;
}
void enable_primitive_restart(bool enable = true)
{
ia.primitiveRestartEnable = enable? VK_TRUE : VK_FALSE;
}
void set_color_mask(bool r, bool g, bool b, bool a)
{
VkColorComponentFlags mask = 0;
if (a) mask |= VK_COLOR_COMPONENT_A_BIT;
if (b) mask |= VK_COLOR_COMPONENT_B_BIT;
if (g) mask |= VK_COLOR_COMPONENT_G_BIT;
if (r) mask |= VK_COLOR_COMPONENT_R_BIT;
att_state[0].colorWriteMask = mask;
att_state[1].colorWriteMask = mask;
att_state[2].colorWriteMask = mask;
att_state[3].colorWriteMask = mask;
}
void set_depth_mask(bool enable)
{
ds.depthWriteEnable = enable ? VK_TRUE : VK_FALSE;
}
void set_stencil_mask(u32 mask)
{
ds.front.writeMask = mask;
ds.back.writeMask = mask;
}
void set_stencil_mask_separate(int face, u32 mask)
{
if (!face)
ds.front.writeMask = mask;
else
ds.back.writeMask = mask;
}
void enable_depth_test(VkCompareOp op)
{
ds.depthTestEnable = VK_TRUE;
ds.depthCompareOp = op;
}
void enable_depth_clamp(bool enable = true)
{
rs.depthClampEnable = enable ? VK_TRUE : VK_FALSE;
}
void enable_depth_bias(bool enable = true)
{
rs.depthBiasEnable = VK_TRUE;
}
void enable_depth_bounds_test(bool enable = true)
{
ds.depthBoundsTestEnable = enable? VK_TRUE : VK_FALSE;
}
void enable_blend(int mrt_index, VkBlendFactor src_factor_rgb, VkBlendFactor src_factor_a,
VkBlendFactor dst_factor_rgb, VkBlendFactor dst_factor_a,
VkBlendOp equation_rgb, VkBlendOp equation_a)
{
att_state[mrt_index].srcColorBlendFactor = src_factor_rgb;
att_state[mrt_index].srcAlphaBlendFactor = src_factor_a;
att_state[mrt_index].dstColorBlendFactor = dst_factor_rgb;
att_state[mrt_index].dstAlphaBlendFactor = dst_factor_a;
att_state[mrt_index].colorBlendOp = equation_rgb;
att_state[mrt_index].alphaBlendOp = equation_a;
att_state[mrt_index].blendEnable = VK_TRUE;
}
void enable_stencil_test(VkStencilOp fail, VkStencilOp zfail, VkStencilOp pass,
VkCompareOp func, u32 func_mask, u32 ref)
{
ds.front.failOp = fail;
ds.front.passOp = pass;
ds.front.depthFailOp = zfail;
ds.front.compareOp = func;
ds.front.compareMask = func_mask;
ds.front.reference = ref;
ds.back = ds.front;
ds.stencilTestEnable = VK_TRUE;
}
void enable_stencil_test_separate(int face, VkStencilOp fail, VkStencilOp zfail, VkStencilOp pass,
VkCompareOp func, u32 func_mask, u32 ref)
{
auto& face_props = (face ? ds.back : ds.front);
face_props.failOp = fail;
face_props.passOp = pass;
face_props.depthFailOp = zfail;
face_props.compareOp = func;
face_props.compareMask = func_mask;
face_props.reference = ref;
ds.stencilTestEnable = VK_TRUE;
}
void enable_logic_op(VkLogicOp op)
{
cs.logicOpEnable = VK_TRUE;
cs.logicOp = op;
}
void enable_cull_face(VkCullModeFlags cull_mode)
{
rs.cullMode = cull_mode;
}
void set_front_face(VkFrontFace face)
{
rs.frontFace = face;
}
void set_attachment_count(u32 count)
{
cs.attachmentCount = count;
cs.pAttachments = att_state;
}
};
namespace glsl namespace glsl
{ {
enum program_input_type enum program_input_type

View file

@ -30,15 +30,7 @@ namespace vk
std::string vs_src; std::string vs_src;
std::string fs_src; std::string fs_src;
struct graphics_pipeline_state renderpass_config;
{
int color_attachments = 0;
bool write_color = true;
bool write_depth = true;
bool no_depth_test = true;
bool enable_blend = false;
}
renderpass_config;
bool initialized = false; bool initialized = false;
bool compiled = false; bool compiled = false;
@ -46,6 +38,15 @@ namespace vk
u32 num_drawable_elements = 4; u32 num_drawable_elements = 4;
u32 first_vertex = 0; u32 first_vertex = 0;
overlay_pass()
{
//Override-able defaults
renderpass_config.set_primitive_type(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
}
~overlay_pass()
{}
void init_descriptors() void init_descriptors()
{ {
VkDescriptorPoolSize descriptor_pool_sizes[2] = VkDescriptorPoolSize descriptor_pool_sizes[2] =
@ -173,51 +174,16 @@ namespace vk
ms.pSampleMask = NULL; ms.pSampleMask = NULL;
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineInputAssemblyStateCreateInfo ia = {};
ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
VkPipelineRasterizationStateCreateInfo rs = {};
rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rs.lineWidth = 1.f;
rs.polygonMode = VK_POLYGON_MODE_FILL;
VkPipelineColorBlendAttachmentState att = {};
if (renderpass_config.write_color)
{
att.colorWriteMask = 0xf;
if (renderpass_config.enable_blend)
{
att.blendEnable = VK_TRUE;
att.alphaBlendOp = VK_BLEND_OP_ADD;
att.colorBlendOp = VK_BLEND_OP_ADD;
att.dstAlphaBlendFactor = att.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
att.srcAlphaBlendFactor = att.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
}
}
VkPipelineColorBlendStateCreateInfo cs = {};
cs.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
cs.attachmentCount = renderpass_config.color_attachments;
cs.pAttachments = &att;
VkPipelineDepthStencilStateCreateInfo ds = {};
ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
ds.depthWriteEnable = renderpass_config.write_depth? VK_TRUE: VK_FALSE;
ds.depthTestEnable = VK_TRUE;
ds.depthCompareOp = VK_COMPARE_OP_ALWAYS;
VkPipeline pipeline; VkPipeline pipeline;
VkGraphicsPipelineCreateInfo info = {}; VkGraphicsPipelineCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
info.pVertexInputState = &vi; info.pVertexInputState = &vi;
info.pInputAssemblyState = &ia; info.pInputAssemblyState = &renderpass_config.ia;
info.pRasterizationState = &rs; info.pRasterizationState = &renderpass_config.rs;
info.pColorBlendState = &cs; info.pColorBlendState = &renderpass_config.cs;
info.pMultisampleState = &ms; info.pMultisampleState = &ms;
info.pViewportState = &vp; info.pViewportState = &vp;
info.pDepthStencilState = &ds; info.pDepthStencilState = &renderpass_config.ds;
info.stageCount = 2; info.stageCount = 2;
info.pStages = shader_stages; info.pStages = shader_stages;
info.pDynamicState = &dynamic_state_info; info.pDynamicState = &dynamic_state_info;
@ -426,7 +392,8 @@ namespace vk
"}\n" "}\n"
}; };
renderpass_config.write_color = false; renderpass_config.set_depth_mask(true);
renderpass_config.enable_depth_test(VK_COMPARE_OP_ALWAYS);
m_vertex_shader.id = 100002; m_vertex_shader.id = 100002;
m_fragment_shader.id = 100003; m_fragment_shader.id = 100003;
@ -507,10 +474,13 @@ namespace vk
"}\n" "}\n"
}; };
renderpass_config.color_attachments = 1; renderpass_config.set_attachment_count(1);
renderpass_config.write_color = true; renderpass_config.set_color_mask(true, true, true, true);
renderpass_config.write_depth = false; renderpass_config.set_depth_mask(false);
renderpass_config.enable_blend = true; renderpass_config.enable_blend(0,
VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_SRC_ALPHA,
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
VK_BLEND_OP_ADD, VK_BLEND_OP_ADD);
m_vertex_shader.id = 100004; m_vertex_shader.id = 100004;
m_fragment_shader.id = 100005; m_fragment_shader.id = 100005;
@ -749,9 +719,96 @@ namespace vk
"}\n" "}\n"
}; };
renderpass_config.write_color = false; renderpass_config.set_depth_mask(true);
renderpass_config.enable_depth_test(VK_COMPARE_OP_ALWAYS);
m_vertex_shader.id = 100006; m_vertex_shader.id = 100006;
m_fragment_shader.id = 100007; m_fragment_shader.id = 100007;
} }
}; };
struct attachment_clear_pass : public overlay_pass
{
color4f clear_color = { 0.f, 0.f, 0.f, 0.f };
color4f colormask = { 1.f, 1.f, 1.f, 1.f };
attachment_clear_pass()
{
vs_src =
{
"#version 450\n"
"#extension GL_ARB_separate_shader_objects : enable\n"
"layout(std140, set=0, binding=1) uniform static_data{ vec4 regs[8]; };\n"
"layout(location=0) out vec2 tc0;\n"
"layout(location=1) out vec4 color;\n"
"layout(location=2) out vec4 mask;\n"
"\n"
"void main()\n"
"{\n"
" vec2 positions[] = {vec2(-1., -1.), vec2(1., -1.), vec2(-1., 1.), vec2(1., 1.)};\n"
" vec2 coords[] = {vec2(0., 0.), vec2(1., 0.), vec2(0., 1.), vec2(1., 1.)};\n"
" tc0 = coords[gl_VertexIndex % 4];\n"
" color = regs[0];\n"
" mask = regs[1];\n"
" gl_Position = vec4(positions[gl_VertexIndex % 4], 0., 1.);\n"
"}\n"
};
fs_src =
{
"#version 420\n"
"#extension GL_ARB_separate_shader_objects : enable\n"
"layout(set=0, binding=0) uniform sampler2D fs0;\n"
"layout(location=0) in vec2 tc0;\n"
"layout(location=1) in vec4 color;\n"
"layout(location=2) in vec4 mask;\n"
"layout(location=0) out vec4 out_color;\n"
"\n"
"void main()\n"
"{\n"
" vec4 original_color = texture(fs0, tc0);\n"
" out_color = mix(original_color, color, bvec4(mask));\n"
"}\n"
};
renderpass_config.set_depth_mask(false);
renderpass_config.set_color_mask(true, true, true, true);
renderpass_config.set_attachment_count(1);
m_vertex_shader.id = 100006;
m_fragment_shader.id = 100007;
}
void update_uniforms(vk::glsl::program* /*program*/) override
{
auto dst = (f32*)m_ubo->map(0, 128);
dst[0] = clear_color.r;
dst[1] = clear_color.g;
dst[2] = clear_color.b;
dst[3] = clear_color.a;
dst[4] = colormask.r;
dst[5] = colormask.g;
dst[6] = colormask.b;
dst[7] = colormask.a;
m_ubo->unmap();
}
bool update_config(u32 clearmask, color4f color)
{
color4f mask = { 0.f, 0.f, 0.f, 0.f };
if (clearmask & 0x10) mask.r = 1.f;
if (clearmask & 0x20) mask.g = 1.f;
if (clearmask & 0x40) mask.b = 1.f;
if (clearmask & 0x80) mask.a = 1.f;
if (mask != colormask || color != clear_color)
{
colormask = mask;
clear_color = color;
return true;
}
return false;
}
};
} }

View file

@ -3,45 +3,41 @@
#include "VKFragmentProgram.h" #include "VKFragmentProgram.h"
#include "../Common/ProgramStateCache.h" #include "../Common/ProgramStateCache.h"
#include "Utilities/hash.h" #include "Utilities/hash.h"
#include "VKHelpers.h"
namespace vk namespace vk
{ {
struct pipeline_props struct pipeline_props
{ {
VkPipelineInputAssemblyStateCreateInfo ia; graphics_pipeline_state state;
VkPipelineDepthStencilStateCreateInfo ds;
VkPipelineColorBlendAttachmentState att_state[4];
VkPipelineColorBlendStateCreateInfo cs;
VkPipelineRasterizationStateCreateInfo rs;
VkRenderPass render_pass; VkRenderPass render_pass;
int num_targets; int num_targets;
int render_pass_location; int render_pass_location;
bool operator==(const pipeline_props& other) const bool operator==(const pipeline_props& other) const
{ {
if (memcmp(&att_state[0], &other.att_state[0], sizeof(VkPipelineColorBlendAttachmentState))) if (memcmp(&state.att_state[0], &other.state.att_state[0], sizeof(VkPipelineColorBlendAttachmentState)))
return false; return false;
if (render_pass_location != other.render_pass_location) if (render_pass_location != other.render_pass_location)
return false; return false;
if (memcmp(&rs, &other.rs, sizeof(VkPipelineRasterizationStateCreateInfo))) if (memcmp(&state.rs, &other.state.rs, sizeof(VkPipelineRasterizationStateCreateInfo)))
return false; return false;
//Cannot memcmp cs due to pAttachments being a pointer to memory //Cannot memcmp cs due to pAttachments being a pointer to memory
if (cs.attachmentCount != other.cs.attachmentCount || if (state.cs.attachmentCount != other.state.cs.attachmentCount ||
cs.flags != other.cs.flags || state.cs.flags != other.state.cs.flags ||
cs.logicOp != other.cs.logicOp || state.cs.logicOp != other.state.cs.logicOp ||
cs.logicOpEnable != other.cs.logicOpEnable || state.cs.logicOpEnable != other.state.cs.logicOpEnable ||
cs.sType != other.cs.sType || state.cs.sType != other.state.cs.sType ||
memcmp(cs.blendConstants, other.cs.blendConstants, 4 * sizeof(f32))) memcmp(state.cs.blendConstants, other.state.cs.blendConstants, 4 * sizeof(f32)))
return false; return false;
if (memcmp(&ia, &other.ia, sizeof(VkPipelineInputAssemblyStateCreateInfo))) if (memcmp(&state.ia, &other.state.ia, sizeof(VkPipelineInputAssemblyStateCreateInfo)))
return false; return false;
if (memcmp(&ds, &other.ds, sizeof(VkPipelineDepthStencilStateCreateInfo))) if (memcmp(&state.ds, &other.state.ds, sizeof(VkPipelineDepthStencilStateCreateInfo)))
return false; return false;
if (num_targets != other.num_targets) if (num_targets != other.num_targets)
@ -58,16 +54,16 @@ namespace rpcs3
size_t hash_struct<vk::pipeline_props>(const vk::pipeline_props &pipelineProperties) size_t hash_struct<vk::pipeline_props>(const vk::pipeline_props &pipelineProperties)
{ {
size_t seed = hash_base<int>(pipelineProperties.num_targets); size_t seed = hash_base<int>(pipelineProperties.num_targets);
seed ^= hash_struct(pipelineProperties.ia); seed ^= hash_struct(pipelineProperties.state.ia);
seed ^= hash_struct(pipelineProperties.ds); seed ^= hash_struct(pipelineProperties.state.ds);
seed ^= hash_struct(pipelineProperties.rs); seed ^= hash_struct(pipelineProperties.state.rs);
//Do not compare pointers to memory! //Do not compare pointers to memory!
auto tmp = pipelineProperties.cs; auto tmp = pipelineProperties.state.cs;
tmp.pAttachments = nullptr; tmp.pAttachments = nullptr;
seed ^= hash_struct(tmp); seed ^= hash_struct(tmp);
seed ^= hash_struct(pipelineProperties.att_state[0]); seed ^= hash_struct(pipelineProperties.state.att_state[0]);
return hash_base<size_t>(seed); return hash_base<size_t>(seed);
} }
} }
@ -99,17 +95,16 @@ struct VKTraits
void validate_pipeline_properties(const VKVertexProgram&, const VKFragmentProgram &fp, vk::pipeline_props& properties) void validate_pipeline_properties(const VKVertexProgram&, const VKFragmentProgram &fp, vk::pipeline_props& properties)
{ {
//Explicitly disable writing to undefined registers //Explicitly disable writing to undefined registers
properties.att_state[0].colorWriteMask &= fp.output_color_masks[0]; properties.state.att_state[0].colorWriteMask &= fp.output_color_masks[0];
properties.att_state[1].colorWriteMask &= fp.output_color_masks[1]; properties.state.att_state[1].colorWriteMask &= fp.output_color_masks[1];
properties.att_state[2].colorWriteMask &= fp.output_color_masks[2]; properties.state.att_state[2].colorWriteMask &= fp.output_color_masks[2];
properties.att_state[3].colorWriteMask &= fp.output_color_masks[3]; properties.state.att_state[3].colorWriteMask &= fp.output_color_masks[3];
} }
static static
pipeline_storage_type build_pipeline(const vertex_program_type &vertexProgramData, const fragment_program_type &fragmentProgramData, pipeline_storage_type build_pipeline(const vertex_program_type &vertexProgramData, const fragment_program_type &fragmentProgramData,
const vk::pipeline_props &pipelineProperties, VkDevice dev, VkPipelineLayout common_pipeline_layout) const vk::pipeline_props &pipelineProperties, VkDevice dev, VkPipelineLayout common_pipeline_layout)
{ {
VkPipelineShaderStageCreateInfo shader_stages[2] = {}; VkPipelineShaderStageCreateInfo shader_stages[2] = {};
shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
@ -151,12 +146,12 @@ struct VKTraits
VkGraphicsPipelineCreateInfo info = {}; VkGraphicsPipelineCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
info.pVertexInputState = &vi; info.pVertexInputState = &vi;
info.pInputAssemblyState = &pipelineProperties.ia; info.pInputAssemblyState = &pipelineProperties.state.ia;
info.pRasterizationState = &pipelineProperties.rs; info.pRasterizationState = &pipelineProperties.state.rs;
info.pColorBlendState = &pipelineProperties.cs; info.pColorBlendState = &pipelineProperties.state.cs;
info.pMultisampleState = &ms; info.pMultisampleState = &ms;
info.pViewportState = &vp; info.pViewportState = &vp;
info.pDepthStencilState = &pipelineProperties.ds; info.pDepthStencilState = &pipelineProperties.state.ds;
info.stageCount = 2; info.stageCount = 2;
info.pStages = shader_stages; info.pStages = shader_stages;
info.pDynamicState = &dynamic_state_info; info.pDynamicState = &dynamic_state_info;
@ -208,7 +203,7 @@ public:
{ {
//Extract pointers from pipeline props //Extract pointers from pipeline props
props.render_pass = m_render_pass_data[props.render_pass_location]; props.render_pass = m_render_pass_data[props.render_pass_location];
props.cs.pAttachments = props.att_state; props.state.cs.pAttachments = props.state.att_state;
vp.skip_vertex_input_check = true; vp.skip_vertex_input_check = true;
getGraphicPipelineState(vp, fp, props, std::forward<Args>(args)...); getGraphicPipelineState(vp, fp, props, std::forward<Args>(args)...);
} }

View file

@ -456,8 +456,8 @@ namespace rsx
static inline u32 get_g8b8_r8g8_colormask(u32 mask) static inline u32 get_g8b8_r8g8_colormask(u32 mask)
{ {
u32 result = 0; u32 result = 0;
if (mask & 0x40) result |= 0x40; if (mask & 0x20) result |= 0x20;
if (mask & 0x80) result |= 0x20; if (mask & 0x40) result |= 0x10;
return result; return result;
} }