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
std::chrono::time_point<steady_clock> textures_start = steady_clock::now();
int unused_location;
void *unused = nullptr;
gl::texture_view* tmp_view;
for (int i = 0; i < rsx::limits::fragment_textures_count; ++i)
{
@ -417,10 +419,10 @@ void GLGSRender::end()
{
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;
m_gl_texture_cache.create_temporary_subresource(unused, sampler_state->external_subresource_desc)->bind();
tmp_view->bind();
}
else
{
@ -967,10 +969,14 @@ void GLGSRender::clear_surface(u32 arg)
case rsx::surface_color_format::x32:
case rsx::surface_color_format::w16z16y16x16:
case rsx::surface_color_format::w32z32y32x32:
{
//Nop
break;
}
case rsx::surface_color_format::g8b8:
{
//NOP
break;
colormask = rsx::get_g8b8_r8g8_colormask(colormask);
// Fall through
}
default:
{

View File

@ -158,7 +158,7 @@ struct driver_state
{
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;
}
}
@ -166,10 +166,10 @@ struct driver_state
void color_mask(bool r, bool g, bool b, bool a)
{
u32 mask = 0;
if (r) mask |= 0x20;
if (g) mask |= 0x40;
if (b) mask |= 0x80;
if (a) mask |= 0x10;
if (r) mask |= 0x10;
if (g) mask |= 0x20;
if (b) mask |= 0x40;
if (a) mask |= 0x80;
color_mask(mask);
}

View File

@ -101,7 +101,7 @@ namespace vk
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);
}
@ -625,6 +625,9 @@ VKGSRender::VKGSRender() : GSRender()
m_depth_scaler.reset(new vk::depth_scaling_pass());
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()));
if (g_cfg.video.disable_vertex_cache)
@ -632,7 +635,7 @@ VKGSRender::VKGSRender() : GSRender()
else
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();
@ -752,6 +755,10 @@ VKGSRender::~VKGSRender()
m_depth_scaler->destroy();
m_depth_scaler.reset();
//Attachment clear helper
m_attachment_clear_pass->destroy();
m_attachment_clear_pass.reset();
//Pipeline descriptors
vkDestroyPipelineLayout(*m_device, pipeline_layout, nullptr);
vkDestroyDescriptorSetLayout(*m_device, descriptor_layouts, nullptr);
@ -1076,7 +1083,6 @@ void VKGSRender::end()
std::chrono::time_point<steady_clock> textures_start = vertex_end;
auto ds = std::get<1>(m_rtts.m_bound_depth_stencil);
//Check for data casts
@ -1084,6 +1090,13 @@ void VKGSRender::end()
{
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 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);
@ -1678,41 +1691,96 @@ void VKGSRender::clear_surface(u32 mask)
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();
depth_stencil_clear_values.depthStencil.stencil = clear_stencil;
depth_stencil_mask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
}
if (mask & 0xF0)
if (auto colormask = (mask & 0xF0))
{
if (m_draw_buffers_count > 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;
for (u32 index = 0; index < m_draw_buffers_count; ++index)
bool use_fast_clear = false;
bool ignore_clear = false;
switch (rsx::method_registers.surface_color())
{
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;
std::get<1>(rtt)->old_contents = nullptr;
for (u32 index = 0; index < m_draw_buffers_count; ++index)
{
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_attachment_clear_pass->free_resources();
m_depth_converter->free_resources();
m_depth_scaler->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 = {};
// Input assembly
bool 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);
properties.state.set_primitive_type(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;
if (rsx::method_registers.restart_index_enabled() && !vk::emulate_primitive_restart() && restarts_valid)
properties.ia.primitiveRestartEnable = VK_TRUE;
else
properties.ia.primitiveRestartEnable = VK_FALSE;
properties.state.enable_primitive_restart();
for (int i = 0; i < 4; ++i)
{
properties.att_state[i].colorWriteMask = 0xf;
properties.att_state[i].blendEnable = VK_FALSE;
}
// Rasterizer state
properties.state.set_attachment_count(m_draw_buffers_count);
properties.state.set_depth_mask(rsx::method_registers.depth_write_enabled());
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_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();
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);
}
VkColorComponentFlags mask = 0;
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;
}
properties.state.set_color_mask(color_mask_r, color_mask_g, color_mask_b, color_mask_a);
bool mrt_blend_enabled[] =
{
@ -2238,84 +2305,50 @@ void VKGSRender::load_program(const vk::vertex_upload_info& vertex_info)
{
if (mrt_blend_enabled[idx])
{
properties.att_state[idx].blendEnable = VK_TRUE;
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.state.enable_blend(idx, sfactor_rgb, sfactor_a, dfactor_rgb, dfactor_a, equation_rgb, 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())
{
properties.ds.stencilTestEnable = VK_TRUE;
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())
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.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.ds.back.compareOp = vk::get_compare_func(rsx::method_registers.back_stencil_func());
properties.state.set_stencil_mask(rsx::method_registers.stencil_mask());
properties.state.enable_stencil_test(
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
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_location = (int)m_current_renderpass_id;
properties.num_targets = m_draw_buffers_count;
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_scaling_pass> m_depth_scaler;
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;
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
{
enum program_input_type

View File

@ -30,15 +30,7 @@ namespace vk
std::string vs_src;
std::string fs_src;
struct
{
int color_attachments = 0;
bool write_color = true;
bool write_depth = true;
bool no_depth_test = true;
bool enable_blend = false;
}
renderpass_config;
graphics_pipeline_state renderpass_config;
bool initialized = false;
bool compiled = false;
@ -46,6 +38,15 @@ namespace vk
u32 num_drawable_elements = 4;
u32 first_vertex = 0;
overlay_pass()
{
//Override-able defaults
renderpass_config.set_primitive_type(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
}
~overlay_pass()
{}
void init_descriptors()
{
VkDescriptorPoolSize descriptor_pool_sizes[2] =
@ -173,51 +174,16 @@ namespace vk
ms.pSampleMask = NULL;
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineInputAssemblyStateCreateInfo ia = {};
ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
VkPipelineRasterizationStateCreateInfo rs = {};
rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rs.lineWidth = 1.f;
rs.polygonMode = VK_POLYGON_MODE_FILL;
VkPipelineColorBlendAttachmentState att = {};
if (renderpass_config.write_color)
{
att.colorWriteMask = 0xf;
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;
VkGraphicsPipelineCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
info.pVertexInputState = &vi;
info.pInputAssemblyState = &ia;
info.pRasterizationState = &rs;
info.pColorBlendState = &cs;
info.pInputAssemblyState = &renderpass_config.ia;
info.pRasterizationState = &renderpass_config.rs;
info.pColorBlendState = &renderpass_config.cs;
info.pMultisampleState = &ms;
info.pViewportState = &vp;
info.pDepthStencilState = &ds;
info.pDepthStencilState = &renderpass_config.ds;
info.stageCount = 2;
info.pStages = shader_stages;
info.pDynamicState = &dynamic_state_info;
@ -426,7 +392,8 @@ namespace vk
"}\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_fragment_shader.id = 100003;
@ -507,10 +474,13 @@ namespace vk
"}\n"
};
renderpass_config.color_attachments = 1;
renderpass_config.write_color = true;
renderpass_config.write_depth = false;
renderpass_config.enable_blend = true;
renderpass_config.set_attachment_count(1);
renderpass_config.set_color_mask(true, true, true, true);
renderpass_config.set_depth_mask(false);
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_fragment_shader.id = 100005;
@ -749,9 +719,96 @@ namespace vk
"}\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_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 "../Common/ProgramStateCache.h"
#include "Utilities/hash.h"
#include "VKHelpers.h"
namespace vk
{
struct pipeline_props
{
VkPipelineInputAssemblyStateCreateInfo ia;
VkPipelineDepthStencilStateCreateInfo ds;
VkPipelineColorBlendAttachmentState att_state[4];
VkPipelineColorBlendStateCreateInfo cs;
VkPipelineRasterizationStateCreateInfo rs;
graphics_pipeline_state state;
VkRenderPass render_pass;
int num_targets;
int render_pass_location;
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;
if (render_pass_location != other.render_pass_location)
return false;
if (memcmp(&rs, &other.rs, sizeof(VkPipelineRasterizationStateCreateInfo)))
if (memcmp(&state.rs, &other.state.rs, sizeof(VkPipelineRasterizationStateCreateInfo)))
return false;
//Cannot memcmp cs due to pAttachments being a pointer to memory
if (cs.attachmentCount != other.cs.attachmentCount ||
cs.flags != other.cs.flags ||
cs.logicOp != other.cs.logicOp ||
cs.logicOpEnable != other.cs.logicOpEnable ||
cs.sType != other.cs.sType ||
memcmp(cs.blendConstants, other.cs.blendConstants, 4 * sizeof(f32)))
if (state.cs.attachmentCount != other.state.cs.attachmentCount ||
state.cs.flags != other.state.cs.flags ||
state.cs.logicOp != other.state.cs.logicOp ||
state.cs.logicOpEnable != other.state.cs.logicOpEnable ||
state.cs.sType != other.state.cs.sType ||
memcmp(state.cs.blendConstants, other.state.cs.blendConstants, 4 * sizeof(f32)))
return false;
if (memcmp(&ia, &other.ia, sizeof(VkPipelineInputAssemblyStateCreateInfo)))
if (memcmp(&state.ia, &other.state.ia, sizeof(VkPipelineInputAssemblyStateCreateInfo)))
return false;
if (memcmp(&ds, &other.ds, sizeof(VkPipelineDepthStencilStateCreateInfo)))
if (memcmp(&state.ds, &other.state.ds, sizeof(VkPipelineDepthStencilStateCreateInfo)))
return false;
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 seed = hash_base<int>(pipelineProperties.num_targets);
seed ^= hash_struct(pipelineProperties.ia);
seed ^= hash_struct(pipelineProperties.ds);
seed ^= hash_struct(pipelineProperties.rs);
seed ^= hash_struct(pipelineProperties.state.ia);
seed ^= hash_struct(pipelineProperties.state.ds);
seed ^= hash_struct(pipelineProperties.state.rs);
//Do not compare pointers to memory!
auto tmp = pipelineProperties.cs;
auto tmp = pipelineProperties.state.cs;
tmp.pAttachments = nullptr;
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);
}
}
@ -99,17 +95,16 @@ struct VKTraits
void validate_pipeline_properties(const VKVertexProgram&, const VKFragmentProgram &fp, vk::pipeline_props& properties)
{
//Explicitly disable writing to undefined registers
properties.att_state[0].colorWriteMask &= fp.output_color_masks[0];
properties.att_state[1].colorWriteMask &= fp.output_color_masks[1];
properties.att_state[2].colorWriteMask &= fp.output_color_masks[2];
properties.att_state[3].colorWriteMask &= fp.output_color_masks[3];
properties.state.att_state[0].colorWriteMask &= fp.output_color_masks[0];
properties.state.att_state[1].colorWriteMask &= fp.output_color_masks[1];
properties.state.att_state[2].colorWriteMask &= fp.output_color_masks[2];
properties.state.att_state[3].colorWriteMask &= fp.output_color_masks[3];
}
static
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)
{
VkPipelineShaderStageCreateInfo shader_stages[2] = {};
shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
@ -151,12 +146,12 @@ struct VKTraits
VkGraphicsPipelineCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
info.pVertexInputState = &vi;
info.pInputAssemblyState = &pipelineProperties.ia;
info.pRasterizationState = &pipelineProperties.rs;
info.pColorBlendState = &pipelineProperties.cs;
info.pInputAssemblyState = &pipelineProperties.state.ia;
info.pRasterizationState = &pipelineProperties.state.rs;
info.pColorBlendState = &pipelineProperties.state.cs;
info.pMultisampleState = &ms;
info.pViewportState = &vp;
info.pDepthStencilState = &pipelineProperties.ds;
info.pDepthStencilState = &pipelineProperties.state.ds;
info.stageCount = 2;
info.pStages = shader_stages;
info.pDynamicState = &dynamic_state_info;
@ -208,7 +203,7 @@ public:
{
//Extract pointers from pipeline props
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;
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)
{
u32 result = 0;
if (mask & 0x40) result |= 0x40;
if (mask & 0x80) result |= 0x20;
if (mask & 0x20) result |= 0x20;
if (mask & 0x40) result |= 0x10;
return result;
}