rsx/vk: Rework MSAA implementation

This commit is contained in:
kd-11 2022-03-13 11:32:04 +03:00 committed by kd-11
parent 9c5ed01130
commit bc7ed8eaab
30 changed files with 285 additions and 123 deletions

View File

@ -129,6 +129,7 @@ namespace rsx
rsx::texture_dimension_extended image_type = texture_dimension_extended::texture_dimension_2d; rsx::texture_dimension_extended image_type = texture_dimension_extended::texture_dimension_2d;
rsx::format_class format_class = RSX_FORMAT_CLASS_UNDEFINED; rsx::format_class format_class = RSX_FORMAT_CLASS_UNDEFINED;
bool is_cyclic_reference = false; bool is_cyclic_reference = false;
u8 samples = 1;
u32 ref_address = 0; u32 ref_address = 0;
u64 surface_cache_tag = 0; u64 surface_cache_tag = 0;
f32 scale_x = 1.f; f32 scale_x = 1.f;

View File

@ -172,7 +172,8 @@ namespace rsx
sampled_image_descriptor() = default; sampled_image_descriptor() = default;
sampled_image_descriptor(image_view_type handle, texture_upload_context ctx, rsx::format_class ftype, sampled_image_descriptor(image_view_type handle, texture_upload_context ctx, rsx::format_class ftype,
size3f scale, rsx::texture_dimension_extended type, bool cyclic_reference = false) size3f scale, rsx::texture_dimension_extended type, bool cyclic_reference = false,
u8 msaa_samples = 1)
{ {
image_handle = handle; image_handle = handle;
upload_context = ctx; upload_context = ctx;
@ -182,6 +183,7 @@ namespace rsx
scale_y = scale.height; scale_y = scale.height;
scale_z = scale.depth; scale_z = scale.depth;
image_type = type; image_type = type;
samples = msaa_samples;
} }
sampled_image_descriptor(image_resource_type external_handle, deferred_request_command reason, sampled_image_descriptor(image_resource_type external_handle, deferred_request_command reason,
@ -1888,7 +1890,7 @@ namespace rsx
} }
auto result = helpers::merge_cache_resources<sampled_image_descriptor>( auto result = helpers::merge_cache_resources<sampled_image_descriptor>(
overlapping_fbos, overlapping_locals, attr, scale, extended_dimension, encoded_remap, remap, _pool); cmd, overlapping_fbos, overlapping_locals, attr, scale, extended_dimension, encoded_remap, remap, _pool);
if (options.skip_texture_merge) if (options.skip_texture_merge)
{ {

View File

@ -228,8 +228,9 @@ namespace rsx
return { false, 0, dst_dimensions.width, dst_dimensions.height }; return { false, 0, dst_dimensions.width, dst_dimensions.height };
} }
template<typename section_storage_type, typename copy_region_type, typename surface_store_list_type> template<typename commandbuffer_type, typename section_storage_type, typename copy_region_type, typename surface_store_list_type>
void gather_texture_slices( void gather_texture_slices(
commandbuffer_type& cmd,
std::vector<copy_region_type>& out, std::vector<copy_region_type>& out,
const surface_store_list_type& fbos, const surface_store_list_type& fbos,
const std::vector<section_storage_type*>& local, const std::vector<section_storage_type*>& local,
@ -311,9 +312,11 @@ namespace rsx
std::tie(src_x, src_y) = rsx::apply_resolution_scale<false>(src_x, src_y, surface_width, surface_height); std::tie(src_x, src_y) = rsx::apply_resolution_scale<false>(src_x, src_y, surface_width, surface_height);
std::tie(dst_x, dst_y) = rsx::apply_resolution_scale<false>(dst_x, dst_y, attr.width, attr.height); std::tie(dst_x, dst_y) = rsx::apply_resolution_scale<false>(dst_x, dst_y, attr.width, attr.height);
section.surface->memory_barrier(cmd, rsx::surface_access::transfer_read);
out.push_back out.push_back
({ ({
section.surface->get_surface(rsx::surface_access::shader_read), section.surface->get_surface(rsx::surface_access::transfer_read),
surface_transform::identity, surface_transform::identity,
0, 0,
static_cast<u16>(src_x), static_cast<u16>(src_x),
@ -505,8 +508,6 @@ namespace rsx
bool surface_is_rop_target, bool surface_is_rop_target,
bool force_convert) bool force_convert)
{ {
texptr->read_barrier(cmd);
const auto surface_width = texptr->template get_surface_width<rsx::surface_metrics::samples>(); const auto surface_width = texptr->template get_surface_width<rsx::surface_metrics::samples>();
const auto surface_height = texptr->template get_surface_height<rsx::surface_metrics::samples>(); const auto surface_height = texptr->template get_surface_height<rsx::surface_metrics::samples>();
@ -553,26 +554,50 @@ namespace rsx
ensure(attr.height == 1); ensure(attr.height == 1);
} }
if ((surface_is_rop_target && g_cfg.video.strict_rendering_mode) || bool requires_processing = false;
attr.width < surface_width || rsx::surface_access access_type = rsx::surface_access::shader_read;
attr.height < surface_height ||
force_convert) if (attr.width != surface_width || attr.height != surface_height || force_convert)
{
// A GPU operation must be performed on the data before sampling. Implies transfer_read access
requires_processing = true;
}
else if (surface_is_rop_target && g_cfg.video.strict_rendering_mode)
{
// Framebuffer feedback avoidance. For MSAA, we do not need to make copies; just use the resolve target
if (texptr->samples() == 1)
{
requires_processing = true;
}
else
{
// Select resolve target instead of MSAA image
access_type = rsx::surface_access::transfer_read;
}
}
if (requires_processing)
{ {
const auto format_class = (force_convert) ? classify_format(attr2.gcm_format) : texptr->format_class(); const auto format_class = (force_convert) ? classify_format(attr2.gcm_format) : texptr->format_class();
const auto command = surface_is_rop_target ? deferred_request_command::copy_image_dynamic : deferred_request_command::copy_image_static; const auto command = surface_is_rop_target ? deferred_request_command::copy_image_dynamic : deferred_request_command::copy_image_static;
return { texptr->get_surface(rsx::surface_access::shader_read), command, attr2, {}, texptr->memory_barrier(cmd, rsx::surface_access::transfer_read);
return { texptr->get_surface(rsx::surface_access::transfer_read), command, attr2, {},
texture_upload_context::framebuffer_storage, format_class, scale, texture_upload_context::framebuffer_storage, format_class, scale,
extended_dimension, decoded_remap }; extended_dimension, decoded_remap };
} }
return{ texptr->get_view(encoded_remap, decoded_remap), texture_upload_context::framebuffer_storage, texptr->memory_barrier(cmd, access_type);
texptr->format_class(), scale, rsx::texture_dimension_extended::texture_dimension_2d, surface_is_rop_target }; auto viewed_surface = texptr->get_surface(access_type);
return { viewed_surface->get_view(encoded_remap, decoded_remap), texture_upload_context::framebuffer_storage,
texptr->format_class(), scale, rsx::texture_dimension_extended::texture_dimension_2d, surface_is_rop_target, viewed_surface->samples() };
} }
texptr->memory_barrier(cmd, rsx::surface_access::transfer_read);
if (extended_dimension == rsx::texture_dimension_extended::texture_dimension_3d) if (extended_dimension == rsx::texture_dimension_extended::texture_dimension_3d)
{ {
return{ texptr->get_surface(rsx::surface_access::shader_read), deferred_request_command::_3d_unwrap, return{ texptr->get_surface(rsx::surface_access::transfer_read), deferred_request_command::_3d_unwrap,
attr2, {}, attr2, {},
texture_upload_context::framebuffer_storage, texptr->format_class(), scale, texture_upload_context::framebuffer_storage, texptr->format_class(), scale,
rsx::texture_dimension_extended::texture_dimension_3d, decoded_remap }; rsx::texture_dimension_extended::texture_dimension_3d, decoded_remap };
@ -580,14 +605,15 @@ namespace rsx
ensure(extended_dimension == rsx::texture_dimension_extended::texture_dimension_cubemap); ensure(extended_dimension == rsx::texture_dimension_extended::texture_dimension_cubemap);
return{ texptr->get_surface(rsx::surface_access::shader_read), deferred_request_command::cubemap_unwrap, return{ texptr->get_surface(rsx::surface_access::transfer_read), deferred_request_command::cubemap_unwrap,
attr2, {}, attr2, {},
texture_upload_context::framebuffer_storage, texptr->format_class(), scale, texture_upload_context::framebuffer_storage, texptr->format_class(), scale,
rsx::texture_dimension_extended::texture_dimension_cubemap, decoded_remap }; rsx::texture_dimension_extended::texture_dimension_cubemap, decoded_remap };
} }
template <typename sampled_image_descriptor, typename surface_store_list_type, typename section_storage_type> template <typename sampled_image_descriptor, typename commandbuffer_type, typename surface_store_list_type, typename section_storage_type>
sampled_image_descriptor merge_cache_resources( sampled_image_descriptor merge_cache_resources(
commandbuffer_type& cmd,
const surface_store_list_type& fbos, const std::vector<section_storage_type*>& local, const surface_store_list_type& fbos, const std::vector<section_storage_type*>& local,
const image_section_attributes_t& attr, const image_section_attributes_t& attr,
const size3f& scale, const size3f& scale,
@ -664,7 +690,7 @@ namespace rsx
upload_context, format_class, scale, upload_context, format_class, scale,
rsx::texture_dimension_extended::texture_dimension_cubemap, decoded_remap }; rsx::texture_dimension_extended::texture_dimension_cubemap, decoded_remap };
gather_texture_slices(desc.external_subresource_desc.sections_to_copy, fbos, local, attr, 6, is_depth); gather_texture_slices(cmd, desc.external_subresource_desc.sections_to_copy, fbos, local, attr, 6, is_depth);
return desc; return desc;
} }
else if (extended_dimension == rsx::texture_dimension_extended::texture_dimension_3d && attr.depth > 1) else if (extended_dimension == rsx::texture_dimension_extended::texture_dimension_3d && attr.depth > 1)
@ -677,7 +703,7 @@ namespace rsx
upload_context, format_class, scale, upload_context, format_class, scale,
rsx::texture_dimension_extended::texture_dimension_3d, decoded_remap }; rsx::texture_dimension_extended::texture_dimension_3d, decoded_remap };
gather_texture_slices(desc.external_subresource_desc.sections_to_copy, fbos, local, attr, attr.depth, is_depth); gather_texture_slices(cmd, desc.external_subresource_desc.sections_to_copy, fbos, local, attr, attr.depth, is_depth);
return desc; return desc;
} }
@ -696,7 +722,7 @@ namespace rsx
attr2, {}, upload_context, format_class, attr2, {}, upload_context, format_class,
scale, rsx::texture_dimension_extended::texture_dimension_2d, decoded_remap }; scale, rsx::texture_dimension_extended::texture_dimension_2d, decoded_remap };
gather_texture_slices(result.external_subresource_desc.sections_to_copy, fbos, local, attr, 1, is_depth); gather_texture_slices(cmd, result.external_subresource_desc.sections_to_copy, fbos, local, attr, 1, is_depth);
result.simplify(); result.simplify();
return result; return result;
} }

View File

@ -3,7 +3,7 @@
#include <util/asm.hpp> #include <util/asm.hpp>
#include <util/sysinfo.hpp> #include <util/sysinfo.hpp>
extern u64 get_system_time(); #include "Emu/Cell/timers.hpp"
namespace rsx namespace rsx
{ {

View File

@ -15,7 +15,7 @@ u64 GLGSRender::get_cycles()
GLGSRender::GLGSRender() : GSRender() GLGSRender::GLGSRender() : GSRender()
{ {
m_shaders_cache = std::make_unique<gl::shader_cache>(m_prog_buffer, "opengl", "v1.92"); m_shaders_cache = std::make_unique<gl::shader_cache>(m_prog_buffer, "opengl", "v1.93");
if (g_cfg.video.disable_vertex_cache || g_cfg.video.multithreaded_rsx) if (g_cfg.video.disable_vertex_cache || g_cfg.video.multithreaded_rsx)
m_vertex_cache = std::make_unique<gl::null_vertex_cache>(); m_vertex_cache = std::make_unique<gl::null_vertex_cache>();

View File

@ -1594,6 +1594,11 @@ namespace gl
return m_pitch; return m_pitch;
} }
constexpr GLubyte samples() const
{
return 1;
}
GLboolean compressed() const GLboolean compressed() const
{ {
return m_compressed; return m_compressed;

View File

@ -28,7 +28,7 @@ gl::texture* GLGSRender::get_present_source(gl::present_surface_info* info, cons
gl::command_context cmd = { gl_state }; gl::command_context cmd = { gl_state };
const auto format_bpp = rsx::get_format_block_size_in_bytes(info->format); const auto format_bpp = rsx::get_format_block_size_in_bytes(info->format);
const auto overlap_info = m_rtts.get_merged_texture_memory_region(cmd, const auto overlap_info = m_rtts.get_merged_texture_memory_region(cmd,
info->address, info->width, info->height, info->pitch, format_bpp, rsx::surface_access::shader_read); info->address, info->width, info->height, info->pitch, format_bpp, rsx::surface_access::transfer_read);
if (!overlap_info.empty()) if (!overlap_info.empty())
{ {
@ -61,8 +61,7 @@ gl::texture* GLGSRender::get_present_source(gl::present_surface_info* info, cons
if (viable) if (viable)
{ {
surface->read_barrier(cmd); image = section.surface->get_surface(rsx::surface_access::transfer_read);
image = section.surface->get_surface(rsx::surface_access::shader_read);
std::tie(info->width, info->height) = rsx::apply_resolution_scale<true>( std::tie(info->width, info->height) = rsx::apply_resolution_scale<true>(
std::min(surface_width, info->width), std::min(surface_width, info->width),

View File

@ -84,10 +84,10 @@ namespace gl
static_cast<gl::render_target*>(t)->release(); static_cast<gl::render_target*>(t)->release();
} }
texture* get_surface(rsx::surface_access /*access_type*/) override viewable_image* get_surface(rsx::surface_access /*access_type*/) override
{ {
// TODO // TODO
return static_cast<gl::texture*>(this); return static_cast<gl::viewable_image*>(this);
} }
u32 raw_handle() const u32 raw_handle() const

View File

@ -1101,9 +1101,19 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode)
ensure(func_id <= FUNCTION::TEXTURE_SAMPLE_MAX_BASE_ENUM && func_id >= FUNCTION::TEXTURE_SAMPLE_BASE); ensure(func_id <= FUNCTION::TEXTURE_SAMPLE_MAX_BASE_ENUM && func_id >= FUNCTION::TEXTURE_SAMPLE_BASE);
if (!(m_prog.texture_state.multisampled_textures & ref_mask)) [[ likely ]]
{
// Clamp type to 3 types (1d, 2d, cube+3d) and offset into sampling redirection table // Clamp type to 3 types (1d, 2d, cube+3d) and offset into sampling redirection table
const auto type_offset = (std::min(static_cast<int>(type), 2) + 1) * static_cast<int>(FUNCTION::TEXTURE_SAMPLE_BASE_ENUM_COUNT); const auto type_offset = (std::min(static_cast<int>(type), 2) + 1) * static_cast<int>(FUNCTION::TEXTURE_SAMPLE_BASE_ENUM_COUNT);
func_id = static_cast<FUNCTION>(static_cast<int>(func_id) + type_offset); func_id = static_cast<FUNCTION>(static_cast<int>(func_id) + type_offset);
}
else
{
// Map to multisample op
ensure(type <= rsx::texture_dimension_extended::texture_dimension_2d);
properties.multisampled_sampler_mask |= ref_mask;
func_id = static_cast<FUNCTION>(static_cast<int>(func_id) - static_cast<int>(FUNCTION::TEXTURE_SAMPLE_BASE) + static_cast<int>(FUNCTION::TEXTURE_SAMPLE2DMS));
}
if (dst.exp_tex) if (dst.exp_tex)
{ {

View File

@ -275,6 +275,7 @@ public:
u16 common_access_sampler_mask = 0; u16 common_access_sampler_mask = 0;
u16 shadow_sampler_mask = 0; u16 shadow_sampler_mask = 0;
u16 redirected_sampler_mask = 0; u16 redirected_sampler_mask = 0;
u16 multisampled_sampler_mask = 0;
bool has_lit_op = false; bool has_lit_op = false;
bool has_gather_op = false; bool has_gather_op = false;

View File

@ -592,6 +592,9 @@ namespace glsl
"#define ALPHAKILL " << rsx::texture_control_bits::ALPHAKILL << "\n" "#define ALPHAKILL " << rsx::texture_control_bits::ALPHAKILL << "\n"
"#define RENORMALIZE " << rsx::texture_control_bits::RENORMALIZE << "\n" "#define RENORMALIZE " << rsx::texture_control_bits::RENORMALIZE << "\n"
"#define DEPTH_FLOAT " << rsx::texture_control_bits::DEPTH_FLOAT << "\n" "#define DEPTH_FLOAT " << rsx::texture_control_bits::DEPTH_FLOAT << "\n"
"#define DEPTH_COMPARE " << rsx::texture_control_bits::DEPTH_COMPARE_OP << "\n"
"#define FILTERED_BIT " << rsx::texture_control_bits::FILTERED << "\n"
"#define INT_COORDS_BIT " << rsx::texture_control_bits::UNNORMALIZED_COORDS << "\n"
"#define GAMMA_CTRL_MASK (GAMMA_R_MASK|GAMMA_G_MASK|GAMMA_B_MASK|GAMMA_A_MASK)\n" "#define GAMMA_CTRL_MASK (GAMMA_R_MASK|GAMMA_G_MASK|GAMMA_B_MASK|GAMMA_A_MASK)\n"
"#define SIGN_EXPAND_MASK (EXPAND_R_MASK|EXPAND_G_MASK|EXPAND_B_MASK|EXPAND_A_MASK)\n\n"; "#define SIGN_EXPAND_MASK (EXPAND_R_MASK|EXPAND_G_MASK|EXPAND_B_MASK|EXPAND_A_MASK)\n\n";
} }
@ -887,6 +890,40 @@ namespace glsl
"#define TEX2D_Z24X8_RGBA8(index, coord2) process_texel(convert_z24x8_to_rgba8(ZS_READ(index, COORD_SCALE2(index, coord2)), texture_parameters[index].remap, TEX_FLAGS(index)), TEX_FLAGS(index))\n" "#define TEX2D_Z24X8_RGBA8(index, coord2) process_texel(convert_z24x8_to_rgba8(ZS_READ(index, COORD_SCALE2(index, coord2)), texture_parameters[index].remap, TEX_FLAGS(index)), TEX_FLAGS(index))\n"
"#define TEX3D_Z24X8_RGBA8(index, coord3) process_texel(convert_z24x8_to_rgba8(ZS_READ(index, COORD_SCALE3(index, coord3)), texture_parameters[index].remap, TEX_FLAGS(index)), TEX_FLAGS(index))\n\n"; "#define TEX3D_Z24X8_RGBA8(index, coord3) process_texel(convert_z24x8_to_rgba8(ZS_READ(index, COORD_SCALE3(index, coord3)), texture_parameters[index].remap, TEX_FLAGS(index)), TEX_FLAGS(index))\n\n";
} }
if (props.require_msaa_ops)
{
OS <<
"#define ZCOMPARE_FUNC(index) _get_bits(TEX_FLAGS(index), DEPTH_COMPARE, 3)\n"
"#define ZS_READ_MS(index, coord) vec2(sampleTexture2DMS(TEX_NAME(index), coord, index).r, float(sampleTexture2DMS(TEX_NAME_STENCIL(index), coord, index).x))\n"
"#define TEX2D_MS(index, coord2) process_texel(sampleTexture2DMS(TEX_NAME(index), coord2, index), TEX_FLAGS(index))\n"
"#define TEX2D_SHADOW_MS(index, coord3) vec4(comparison_passes(sampleTexture2DMS(TEX_NAME(index), coord3.xy, index).x, coord3.z, ZCOMPARE_FUNC(index)))\n"
"#define TEX2D_SHADOWPROJ_MS(index, coord4) TEX2D_SHADOW_MS(index, (coord4.xyz / coord4.w))\n"
"#define TEX2D_Z24X8_RGBA8_MS(index, coord2) process_texel(convert_z24x8_to_rgba8(ZS_READ_MS(index, coord2), texture_parameters[index].remap, TEX_FLAGS(index)), TEX_FLAGS(index))\n\n";
auto insert_msaa_sample_code = [&OS](const std::string_view& sampler_type)
{
OS <<
"vec4 sampleTexture2DMS(in " << sampler_type << " tex, const in vec2 coords, const in int index)\n"
"{\n"
" const uint flags = TEX_FLAGS(index);\n"
" const ivec2 sample_count = ivec2(2, textureSamples(tex) / 2);\n"
" const ivec2 icoords = ivec2(COORD_SCALE2(index, coords) * textureSize(tex) * sample_count);\n"
"\n"
" const ivec2 resolve_coords = icoords * ivec2(bvec2(texture_parameters[index].scale_bias.xy));\n"
" const ivec2 aa_coords = resolve_coords / sample_count;\n"
" const ivec2 sample_loc = ivec2(resolve_coords % sample_count);\n"
" const int sample_index = sample_loc.x + (sample_loc.y * sample_count.y);\n"
" return texelFetch(tex, aa_coords, sample_index);\n"
"}\n\n";
};
insert_msaa_sample_code("sampler2DMS");
if (props.require_depth_conversion)
{
insert_msaa_sample_code("usampler2DMS");
}
}
} }
if (props.require_wpos) if (props.require_wpos)
@ -984,6 +1021,22 @@ namespace glsl
return "TEX3D_Z24X8_RGBA8($_i, $0.xyz)"; return "TEX3D_Z24X8_RGBA8($_i, $0.xyz)";
case FUNCTION::TEXTURE_SAMPLE3D_DEPTH_RGBA_PROJ: case FUNCTION::TEXTURE_SAMPLE3D_DEPTH_RGBA_PROJ:
return "TEX3D_Z24X8_RGBA8($_i, ($0.xyz / $0.w))"; return "TEX3D_Z24X8_RGBA8($_i, ($0.xyz / $0.w))";
case FUNCTION::TEXTURE_SAMPLE2DMS:
case FUNCTION::TEXTURE_SAMPLE2DMS_BIAS:
return "TEX2D_MS($_i, $0.xy)";
case FUNCTION::TEXTURE_SAMPLE2DMS_PROJ:
return "TEX2D_MS($_i, $0.xy / $0.w)";
case FUNCTION::TEXTURE_SAMPLE2DMS_LOD:
case FUNCTION::TEXTURE_SAMPLE2DMS_GRAD:
return "TEX2D_MS($_i, $0.xy)";
case FUNCTION::TEXTURE_SAMPLE2DMS_SHADOW:
return "TEX2D_SHADOW_MS($_i, $0.xyz)";
case FUNCTION::TEXTURE_SAMPLE2DMS_SHADOW_PROJ:
return "TEX2D_SHADOWPROJ_MS($_i, $0)";
case FUNCTION::TEXTURE_SAMPLE2DMS_DEPTH_RGBA:
return "TEX2D_Z24X8_RGBA8_MS($_i, $0.xy)";
case FUNCTION::TEXTURE_SAMPLE2DMS_DEPTH_RGBA_PROJ:
return "TEX2D_Z24X8_RGBA8_MS($_i, ($0.xy / $0.w))";
case FUNCTION::DFDX: case FUNCTION::DFDX:
return "dFdx($0)"; return "dFdx($0)";
case FUNCTION::DFDY: case FUNCTION::DFDY:
@ -995,6 +1048,8 @@ namespace glsl
case FUNCTION::VERTEX_TEXTURE_FETCH3D: case FUNCTION::VERTEX_TEXTURE_FETCH3D:
case FUNCTION::VERTEX_TEXTURE_FETCHCUBE: case FUNCTION::VERTEX_TEXTURE_FETCHCUBE:
return "textureLod($t, $0.xyz, 0)"; return "textureLod($t, $0.xyz, 0)";
case FUNCTION::VERTEX_TEXTURE_FETCH2DMS:
return "texelFetch($t, ivec2($0.xy * textureSize($t)), 0)";
} }
rsx_log.error("Unexpected function request: %d", static_cast<int>(f)); rsx_log.error("Unexpected function request: %d", static_cast<int>(f));

View File

@ -20,6 +20,11 @@ namespace rsx
EXPAND_G, EXPAND_G,
EXPAND_B, EXPAND_B,
DEPTH_FLOAT, DEPTH_FLOAT,
DEPTH_COMPARE_OP,
DEPTH_COMPARE_1,
DEPTH_COMPARE_2,
FILTERED,
UNNORMALIZED_COORDS,
GAMMA_CTRL_MASK = (1 << GAMMA_R) | (1 << GAMMA_G) | (1 << GAMMA_B) | (1 << GAMMA_A), GAMMA_CTRL_MASK = (1 << GAMMA_R) | (1 << GAMMA_G) | (1 << GAMMA_B) | (1 << GAMMA_A),
EXPAND_MASK = (1 << EXPAND_R) | (1 << EXPAND_G) | (1 << EXPAND_B) | (1 << EXPAND_A), EXPAND_MASK = (1 << EXPAND_R) | (1 << EXPAND_G) | (1 << EXPAND_B) | (1 << EXPAND_A),

View File

@ -27,6 +27,7 @@ namespace glsl
bool require_depth_conversion : 1; bool require_depth_conversion : 1;
bool require_texture_ops : 1; bool require_texture_ops : 1;
bool require_shadow_ops : 1; bool require_shadow_ops : 1;
bool require_msaa_ops : 1;
bool require_texture_expand : 1; bool require_texture_expand : 1;
bool require_srgb_to_linear : 1; bool require_srgb_to_linear : 1;
bool require_linear_to_srgb : 1; bool require_linear_to_srgb : 1;

View File

@ -307,6 +307,7 @@ usz vertex_program_storage_hash::operator()(const RSXVertexProgram &program) con
usz hash = vertex_program_utils::get_vertex_program_ucode_hash(program); usz hash = vertex_program_utils::get_vertex_program_ucode_hash(program);
hash ^= program.output_mask; hash ^= program.output_mask;
hash ^= program.texture_state.texture_dimensions; hash ^= program.texture_state.texture_dimensions;
hash ^= program.texture_state.multisampled_textures;
return hash; return hash;
} }
@ -507,6 +508,7 @@ usz fragment_program_storage_hash::operator()(const RSXFragmentProgram& program)
hash ^= program.texture_state.texture_dimensions; hash ^= program.texture_state.texture_dimensions;
hash ^= program.texture_state.shadow_textures; hash ^= program.texture_state.shadow_textures;
hash ^= program.texture_state.redirected_textures; hash ^= program.texture_state.redirected_textures;
hash ^= program.texture_state.multisampled_textures;
hash ^= program.texcoord_control_mask; hash ^= program.texcoord_control_mask;
return hash; return hash;

View File

@ -308,6 +308,8 @@ struct RSXFragmentProgram
bool valid = false; bool valid = false;
RSXFragmentProgram() = default;
rsx::texture_dimension_extended get_texture_dimension(u8 id) const rsx::texture_dimension_extended get_texture_dimension(u8 id) const
{ {
return rsx::texture_dimension_extended{static_cast<u8>((texture_state.texture_dimensions >> (id * 2)) & 0x3)}; return rsx::texture_dimension_extended{static_cast<u8>((texture_state.texture_dimensions >> (id * 2)) & 0x3)};
@ -324,10 +326,6 @@ struct RSXFragmentProgram
return !!(texcoord_control_mask & (1u << index)); return !!(texcoord_control_mask & (1u << index));
} }
RSXFragmentProgram()
{
}
static RSXFragmentProgram clone(const RSXFragmentProgram& prog) static RSXFragmentProgram clone(const RSXFragmentProgram& prog)
{ {
auto result = prog; auto result = prog;

View File

@ -64,10 +64,21 @@ enum class FUNCTION
TEXTURE_SAMPLE3D_DEPTH_RGBA, TEXTURE_SAMPLE3D_DEPTH_RGBA,
TEXTURE_SAMPLE3D_DEPTH_RGBA_PROJ, TEXTURE_SAMPLE3D_DEPTH_RGBA_PROJ,
TEXTURE_SAMPLE2DMS,
TEXTURE_SAMPLE2DMS_BIAS,
TEXTURE_SAMPLE2DMS_PROJ,
TEXTURE_SAMPLE2DMS_LOD,
TEXTURE_SAMPLE2DMS_GRAD,
TEXTURE_SAMPLE2DMS_SHADOW,
TEXTURE_SAMPLE2DMS_SHADOW_PROJ,
TEXTURE_SAMPLE2DMS_DEPTH_RGBA,
TEXTURE_SAMPLE2DMS_DEPTH_RGBA_PROJ,
VERTEX_TEXTURE_FETCH1D, VERTEX_TEXTURE_FETCH1D,
VERTEX_TEXTURE_FETCH2D, VERTEX_TEXTURE_FETCH2D,
VERTEX_TEXTURE_FETCH3D, VERTEX_TEXTURE_FETCH3D,
VERTEX_TEXTURE_FETCHCUBE, VERTEX_TEXTURE_FETCHCUBE,
VERTEX_TEXTURE_FETCH2DMS,
// Meta // Meta
TEXTURE_SAMPLE_MAX_BASE_ENUM = TEXTURE_SAMPLE_DEPTH_RGBA_PROJ_BASE, // Update if more base enums are added TEXTURE_SAMPLE_MAX_BASE_ENUM = TEXTURE_SAMPLE_DEPTH_RGBA_PROJ_BASE, // Update if more base enums are added

View File

@ -593,13 +593,15 @@ std::string VertexProgramDecompiler::Decompile()
case RSX_VEC_OPCODE_TXL: case RSX_VEC_OPCODE_TXL:
{ {
GetTex(); GetTex();
const bool is_multisampled = m_prog.texture_state.multisampled_textures & (1 << d2.tex_num);
switch (m_prog.get_texture_dimension(d2.tex_num)) switch (m_prog.get_texture_dimension(d2.tex_num))
{ {
case rsx::texture_dimension_extended::texture_dimension_1d: case rsx::texture_dimension_extended::texture_dimension_1d:
SetDSTVec(getFunction(FUNCTION::VERTEX_TEXTURE_FETCH1D)); SetDSTVec(is_multisampled ? getFunction(FUNCTION::VERTEX_TEXTURE_FETCH2DMS) : getFunction(FUNCTION::VERTEX_TEXTURE_FETCH1D));
break; break;
case rsx::texture_dimension_extended::texture_dimension_2d: case rsx::texture_dimension_extended::texture_dimension_2d:
SetDSTVec(getFunction(FUNCTION::VERTEX_TEXTURE_FETCH2D)); SetDSTVec(getFunction(is_multisampled ? FUNCTION::VERTEX_TEXTURE_FETCH2DMS : FUNCTION::VERTEX_TEXTURE_FETCH2D));
break; break;
case rsx::texture_dimension_extended::texture_dimension_3d: case rsx::texture_dimension_extended::texture_dimension_3d:
SetDSTVec(getFunction(FUNCTION::VERTEX_TEXTURE_FETCH3D)); SetDSTVec(getFunction(FUNCTION::VERTEX_TEXTURE_FETCH3D));

View File

@ -57,12 +57,14 @@ namespace rsx
const u16 clear_mask = ~(static_cast<u16>(1 << index)); const u16 clear_mask = ~(static_cast<u16>(1 << index));
redirected_textures &= clear_mask; redirected_textures &= clear_mask;
shadow_textures &= clear_mask; shadow_textures &= clear_mask;
multisampled_textures &= clear_mask;
} }
void fragment_program_texture_state::import(const fragment_program_texture_state& other, u16 mask) void fragment_program_texture_state::import(const fragment_program_texture_state& other, u16 mask)
{ {
redirected_textures = other.redirected_textures & mask; redirected_textures = other.redirected_textures & mask;
shadow_textures = other.shadow_textures & mask; shadow_textures = other.shadow_textures & mask;
multisampled_textures = other.multisampled_textures & mask;
texture_dimensions = other.texture_dimensions & duplicate_and_extend(mask); texture_dimensions = other.texture_dimensions & duplicate_and_extend(mask);
} }
@ -78,16 +80,19 @@ namespace rsx
{ {
return texture_dimensions == other.texture_dimensions && return texture_dimensions == other.texture_dimensions &&
redirected_textures == other.redirected_textures && redirected_textures == other.redirected_textures &&
shadow_textures == other.shadow_textures; shadow_textures == other.shadow_textures &&
multisampled_textures == other.multisampled_textures;
} }
void vertex_program_texture_state::clear(u32 /*index*/) void vertex_program_texture_state::clear(u32 index)
{ {
// Nothing to do yet const u16 clear_mask = ~(static_cast<u16>(1 << index));
multisampled_textures &= clear_mask;
} }
void vertex_program_texture_state::import(const vertex_program_texture_state& other, u16 mask) void vertex_program_texture_state::import(const vertex_program_texture_state& other, u16 mask)
{ {
multisampled_textures = other.multisampled_textures & mask;
texture_dimensions = other.texture_dimensions & duplicate_and_extend(mask); texture_dimensions = other.texture_dimensions & duplicate_and_extend(mask);
} }
@ -101,6 +106,7 @@ namespace rsx
bool vertex_program_texture_state::operator == (const vertex_program_texture_state& other) const bool vertex_program_texture_state::operator == (const vertex_program_texture_state& other) const
{ {
return texture_dimensions == other.texture_dimensions; return texture_dimensions == other.texture_dimensions &&
multisampled_textures == other.multisampled_textures;
} }
} }

View File

@ -38,6 +38,7 @@ namespace rsx
u32 texture_dimensions = 0; u32 texture_dimensions = 0;
u16 redirected_textures = 0; u16 redirected_textures = 0;
u16 shadow_textures = 0; u16 shadow_textures = 0;
u16 multisampled_textures = 0;
void clear(u32 index); void clear(u32 index);
void import(const fragment_program_texture_state& other, u16 mask); void import(const fragment_program_texture_state& other, u16 mask);
@ -48,6 +49,7 @@ namespace rsx
struct vertex_program_texture_state struct vertex_program_texture_state
{ {
u32 texture_dimensions = 0; u32 texture_dimensions = 0;
u16 multisampled_textures = 0;
void clear(u32 index); void clear(u32 index);
void import(const vertex_program_texture_state& other, u16 mask); void import(const vertex_program_texture_state& other, u16 mask);

View File

@ -1738,6 +1738,12 @@ namespace rsx
{ {
current_vp_texture_state.clear(i); current_vp_texture_state.clear(i);
current_vp_texture_state.set_dimension(sampler_descriptors[i]->image_type, i); current_vp_texture_state.set_dimension(sampler_descriptors[i]->image_type, i);
if (backend_config.supports_hw_msaa &&
sampler_descriptors[i]->samples > 1)
{
current_vp_texture_state.multisampled_textures |= (1 << i);
}
} }
} }
@ -1978,6 +1984,15 @@ namespace rsx
} }
} }
if (backend_config.supports_hw_msaa &&
sampler_descriptors[i]->samples > 1)
{
current_fp_texture_state.multisampled_textures |= (1 << i);
texture_control |= (static_cast<u32>(tex.zfunc()) << texture_control_bits::DEPTH_COMPARE_OP);
texture_control |= (static_cast<u32>(tex.mag_filter() != rsx::texture_magnify_filter::nearest) << texture_control_bits::FILTERED);
texture_control |= (((tex.format() & CELL_GCM_TEXTURE_UN) >> 6) << texture_control_bits::UNNORMALIZED_COORDS);
}
if (sampler_descriptors[i]->format_class != RSX_FORMAT_CLASS_COLOR) if (sampler_descriptors[i]->format_class != RSX_FORMAT_CLASS_COLOR)
{ {
switch (sampler_descriptors[i]->format_class) switch (sampler_descriptors[i]->format_class)

View File

@ -588,6 +588,7 @@ namespace rsx
bool supports_multidraw; // Draw call batching bool supports_multidraw; // Draw call batching
bool supports_hw_a2c; // Alpha to coverage bool supports_hw_a2c; // Alpha to coverage
bool supports_hw_renormalization; // Should be true on NV hardware which matches PS3 texture renormalization behaviour bool supports_hw_renormalization; // Should be true on NV hardware which matches PS3 texture renormalization behaviour
bool supports_hw_msaa; // MSAA support
bool supports_hw_a2one; // Alpha to one bool supports_hw_a2one; // Alpha to one
bool supports_hw_conditional_render; // Conditional render bool supports_hw_conditional_render; // Conditional render
bool supports_passthrough_dma; // DMA passthrough bool supports_passthrough_dma; // DMA passthrough

View File

@ -29,14 +29,25 @@ std::string VKFragmentDecompilerThread::compareFunction(COMPARE f, const std::st
void VKFragmentDecompilerThread::insertHeader(std::stringstream & OS) void VKFragmentDecompilerThread::insertHeader(std::stringstream & OS)
{ {
int version = 420;
std::vector<const char*> required_extensions;
if (device_props.has_native_half_support) if (device_props.has_native_half_support)
{ {
OS << "#version 450\n"; version = std::max(version, 450);
OS << "#extension GL_EXT_shader_explicit_arithmetic_types_float16: enable\n"; required_extensions.emplace_back("GL_EXT_shader_explicit_arithmetic_types_float16");
} }
else
if (properties.multisampled_sampler_mask)
{ {
OS << "#version 420\n"; version = std::max(version, 450);
required_extensions.emplace_back("GL_ARB_shader_texture_image_samples");
}
OS << "#version " << version << "\n";
for (const auto ext : required_extensions)
{
OS << "#extension " << ext << ": require\n";
} }
OS << "#extension GL_ARB_separate_shader_objects: enable\n\n"; OS << "#extension GL_ARB_separate_shader_objects: enable\n\n";
@ -128,11 +139,21 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS)
for (const ParamItem& PI : PT.items) for (const ParamItem& PI : PT.items)
{ {
std::string samplerType = PT.type; std::string samplerType = PT.type;
int index = atoi(&PI.name[3]);
ensure(PI.name.length() > 3);
int index = atoi(&PI.name[3]);
const auto mask = (1 << index); const auto mask = (1 << index);
if (properties.shadow_sampler_mask & mask) if (properties.multisampled_sampler_mask & mask)
{
if (samplerType != "sampler1D" && samplerType != "sampler2D")
{
rsx_log.error("Unexpected multisampled image type '%s'", samplerType);
}
samplerType = "sampler2DMS";
}
else if (properties.shadow_sampler_mask & mask)
{ {
if (properties.common_access_sampler_mask & mask) if (properties.common_access_sampler_mask & mask)
{ {
@ -162,7 +183,7 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS)
inputs.push_back(in); inputs.push_back(in);
OS << "layout(set=0, binding=" << location++ << ") uniform u" << PT.type << " " << in.name << ";\n"; OS << "layout(set=0, binding=" << location++ << ") uniform u" << samplerType << " " << in.name << ";\n";
} }
} }
} }
@ -243,6 +264,7 @@ void VKFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS)
m_shader_props.require_wpos = !!(properties.in_register_mask & in_wpos); m_shader_props.require_wpos = !!(properties.in_register_mask & in_wpos);
m_shader_props.require_texture_ops = properties.has_tex_op; m_shader_props.require_texture_ops = properties.has_tex_op;
m_shader_props.require_shadow_ops = properties.shadow_sampler_mask != 0; m_shader_props.require_shadow_ops = properties.shadow_sampler_mask != 0;
m_shader_props.require_msaa_ops = m_prog.texture_state.multisampled_textures != 0;
m_shader_props.require_texture_expand = properties.has_exp_tex_op; m_shader_props.require_texture_expand = properties.has_exp_tex_op;
m_shader_props.require_srgb_to_linear = properties.has_upg; m_shader_props.require_srgb_to_linear = properties.has_upg;
m_shader_props.require_linear_to_srgb = properties.has_pkg; m_shader_props.require_linear_to_srgb = properties.has_pkg;

View File

@ -506,7 +506,7 @@ VKGSRender::VKGSRender() : GSRender()
else else
m_vertex_cache = std::make_unique<vk::weak_vertex_cache>(); m_vertex_cache = std::make_unique<vk::weak_vertex_cache>();
m_shaders_cache = std::make_unique<vk::shader_cache>(*m_prog_buffer, "vulkan", "v1.92"); m_shaders_cache = std::make_unique<vk::shader_cache>(*m_prog_buffer, "vulkan", "v1.93");
for (u32 i = 0; i < m_swapchain->get_swap_image_count(); ++i) for (u32 i = 0; i < m_swapchain->get_swap_image_count(); ++i)
{ {
@ -539,7 +539,8 @@ VKGSRender::VKGSRender() : GSRender()
// This is here for visual consistency - will be removed when AA problems due to mipmaps are fixed // This is here for visual consistency - will be removed when AA problems due to mipmaps are fixed
if (g_cfg.video.antialiasing_level != msaa_level::none) if (g_cfg.video.antialiasing_level != msaa_level::none)
{ {
backend_config.supports_hw_a2c = VK_TRUE; backend_config.supports_hw_msaa = true;
backend_config.supports_hw_a2c = true;
backend_config.supports_hw_a2one = m_device->get_alpha_to_one_support(); backend_config.supports_hw_a2one = m_device->get_alpha_to_one_support();
} }
@ -2233,7 +2234,7 @@ void VKGSRender::close_and_submit_command_buffer(vk::fence* pFence, VkSemaphore
primary_submit_info.wait_on(wait_semaphore, pipeline_stage_flags); primary_submit_info.wait_on(wait_semaphore, pipeline_stage_flags);
} }
if (const auto wait_sema = std::exchange(m_dangling_semaphore_signal, VK_NULL_HANDLE)) if (const auto wait_sema = std::exchange(m_dangling_semaphore_signal, nullptr))
{ {
// TODO: Sync on VS stage // TODO: Sync on VS stage
primary_submit_info.wait_on(wait_sema, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); primary_submit_info.wait_on(wait_sema, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);

View File

@ -278,7 +278,7 @@ vk::viewable_image* VKGSRender::get_present_source(vk::present_surface_info* inf
// Check the surface store first // Check the surface store first
const auto format_bpp = rsx::get_format_block_size_in_bytes(info->format); const auto format_bpp = rsx::get_format_block_size_in_bytes(info->format);
const auto overlap_info = m_rtts.get_merged_texture_memory_region(*m_current_command_buffer, const auto overlap_info = m_rtts.get_merged_texture_memory_region(*m_current_command_buffer,
info->address, info->width, info->height, info->pitch, format_bpp, rsx::surface_access::shader_read); info->address, info->width, info->height, info->pitch, format_bpp, rsx::surface_access::transfer_read);
if (!overlap_info.empty()) if (!overlap_info.empty())
{ {
@ -311,8 +311,7 @@ vk::viewable_image* VKGSRender::get_present_source(vk::present_surface_info* inf
if (viable) if (viable)
{ {
surface->read_barrier(*m_current_command_buffer); image_to_flip = section.surface->get_surface(rsx::surface_access::transfer_read);
image_to_flip = section.surface->get_surface(rsx::surface_access::shader_read);
std::tie(info->width, info->height) = rsx::apply_resolution_scale<true>( std::tie(info->width, info->height) = rsx::apply_resolution_scale<true>(
std::min(surface_width, info->width), std::min(surface_width, info->width),

View File

@ -337,8 +337,6 @@ namespace vk
if (!is_depth_surface()) [[likely]] if (!is_depth_surface()) [[likely]]
{ {
ensure(current_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// This is the source; finish writing before reading // This is the source; finish writing before reading
vk::insert_image_memory_barrier( vk::insert_image_memory_barrier(
cmd, this->value, cmd, this->value,
@ -767,17 +765,11 @@ namespace vk
{ {
last_rw_access_tag = rsx::get_shared_tag(); last_rw_access_tag = rsx::get_shared_tag();
if (samples() == 1 || access_type == rsx::surface_access::shader_write) if (samples() == 1 || !access_type.is_transfer())
{ {
return this; return this;
} }
if (access_type == rsx::surface_access::gpu_reference)
{
// WARNING: Can return MSAA data result if no read barrier was issued
return resolve_surface ? resolve_surface.get() : this;
}
// A read barrier should have been called before this! // A read barrier should have been called before this!
ensure(resolve_surface); // "Read access without explicit barrier" ensure(resolve_surface); // "Read access without explicit barrier"
ensure(!(msaa_flags & rsx::surface_state_flags::require_resolve)); ensure(!(msaa_flags & rsx::surface_state_flags::require_resolve));
@ -802,20 +794,11 @@ namespace vk
} }
void render_target::texture_barrier(vk::command_buffer& cmd) void render_target::texture_barrier(vk::command_buffer& cmd)
{
if (samples() == 1)
{ {
if (!write_barrier_sync_tag) write_barrier_sync_tag++; // Activate barrier sync if (!write_barrier_sync_tag) write_barrier_sync_tag++; // Activate barrier sync
cyclic_reference_sync_tag = write_barrier_sync_tag; // Match tags cyclic_reference_sync_tag = write_barrier_sync_tag; // Match tags
vk::insert_texture_barrier(cmd, this, VK_IMAGE_LAYOUT_GENERAL); vk::insert_texture_barrier(cmd, this, VK_IMAGE_LAYOUT_GENERAL);
return;
}
if (msaa_flags & rsx::surface_state_flags::require_resolve)
{
resolve(cmd);
}
} }
void render_target::reset_surface_counters() void render_target::reset_surface_counters()
@ -832,15 +815,8 @@ namespace vk
return vk::viewable_image::get_view(VK_REMAP_IDENTITY, remap, mask); return vk::viewable_image::get_view(VK_REMAP_IDENTITY, remap, mask);
} }
if (!resolve_surface) [[likely]]
{
return vk::viewable_image::get_view(remap_encoding, remap, mask); return vk::viewable_image::get_view(remap_encoding, remap, mask);
} }
else
{
return resolve_surface->get_view(remap_encoding, remap, mask);
}
}
void render_target::memory_barrier(vk::command_buffer& cmd, rsx::surface_access access) void render_target::memory_barrier(vk::command_buffer& cmd, rsx::surface_access access)
{ {
@ -933,7 +909,7 @@ namespace vk
if (msaa_flags & rsx::surface_state_flags::require_resolve) if (msaa_flags & rsx::surface_state_flags::require_resolve)
{ {
if (access.is_transfer_or_read()) if (access.is_transfer() && access.is_read())
{ {
// Only do this step when read access is required // Only do this step when read access is required
get_resolve_target_safe(cmd); get_resolve_target_safe(cmd);
@ -967,7 +943,7 @@ namespace vk
{ {
auto& section = old_contents[i]; auto& section = old_contents[i];
auto src_texture = static_cast<vk::render_target*>(section.source); auto src_texture = static_cast<vk::render_target*>(section.source);
src_texture->read_barrier(cmd); src_texture->memory_barrier(cmd, rsx::surface_access::transfer_read);
if (!accept_all && !src_texture->test()) [[likely]] if (!accept_all && !src_texture->test()) [[likely]]
{ {

View File

@ -91,7 +91,7 @@ namespace vk
static std::pair<VkImageUsageFlags, VkImageCreateFlags> get_attachment_create_flags(VkFormat format, u8 samples) static std::pair<VkImageUsageFlags, VkImageCreateFlags> get_attachment_create_flags(VkFormat format, u8 samples)
{ {
if (g_cfg.video.strict_rendering_mode || samples > 1) if (g_cfg.video.strict_rendering_mode)
{ {
return {}; return {};
} }
@ -152,11 +152,11 @@ namespace vk
} }
auto [usage_flags, create_flags] = get_attachment_create_flags(requested_format, samples); auto [usage_flags, create_flags] = get_attachment_create_flags(requested_format, samples);
usage_flags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; usage_flags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
if (samples == 1) [[likely]] if (samples == 1) [[likely]]
{ {
usage_flags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; usage_flags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
} }
else else
{ {

View File

@ -197,8 +197,8 @@ namespace vk
if (context == rsx::texture_upload_context::framebuffer_storage) if (context == rsx::texture_upload_context::framebuffer_storage)
{ {
auto surface = vk::as_rtt(vram_texture); auto surface = vk::as_rtt(vram_texture);
surface->read_barrier(cmd); surface->memory_barrier(cmd, rsx::surface_access::transfer_read);
locked_resource = surface->get_surface(rsx::surface_access::shader_read); locked_resource = surface->get_surface(rsx::surface_access::transfer_read);
transfer_width *= surface->samples_x; transfer_width *= surface->samples_x;
transfer_height *= surface->samples_y; transfer_height *= surface->samples_y;
} }

View File

@ -134,7 +134,25 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std
inputs.push_back(in); inputs.push_back(in);
OS << "layout(set = 0, binding=" << location++ << ") uniform " << PT.type << " " << PI.name << ";\n"; auto samplerType = PT.type;
if (m_prog.texture_state.multisampled_textures) [[ unlikely ]]
{
ensure(PI.name.length() > 3);
int index = atoi(&PI.name[3]);
if (m_prog.texture_state.multisampled_textures & (1 << index))
{
if (samplerType != "sampler1D" && samplerType != "sampler2D")
{
rsx_log.error("Unexpected multisampled sampler type '%s'", samplerType);
}
samplerType = "sampler2DMS";
}
}
OS << "layout(set = 0, binding=" << location++ << ") uniform " << samplerType << " " << PI.name << ";\n";
} }
} }
} }

View File

@ -113,12 +113,6 @@ namespace vk
void insert_texture_barrier(VkCommandBuffer cmd, vk::image* image, VkImageLayout new_layout) void insert_texture_barrier(VkCommandBuffer cmd, vk::image* image, VkImageLayout new_layout)
{ {
if (image->samples() > 1)
{
// This barrier is pointless for multisampled images as they require a resolve operation before access anyway
return;
}
insert_texture_barrier(cmd, image->value, image->current_layout, new_layout, { image->aspect(), 0, 1, 0, 1 }); insert_texture_barrier(cmd, image->value, image->current_layout, new_layout, { image->aspect(), 0, 1, 0, 1 });
image->current_layout = new_layout; image->current_layout = new_layout;
} }

View File

@ -36,6 +36,10 @@ namespace rsx
u32 vp_entry; u32 vp_entry;
u16 vp_jump_table[32]; u16 vp_jump_table[32];
u16 vp_multisampled_textures;
u16 vp_reserved_0;
u32 vp_reserved_1;
u32 fp_ctrl; u32 fp_ctrl;
u32 fp_texture_dimensions; u32 fp_texture_dimensions;
u32 fp_texcoord_control; u32 fp_texcoord_control;
@ -44,8 +48,8 @@ namespace rsx
u16 fp_lighting_flags; u16 fp_lighting_flags;
u16 fp_shadow_textures; u16 fp_shadow_textures;
u16 fp_redirected_textures; u16 fp_redirected_textures;
u16 unused_0; // Retained for binary compatibility u16 fp_multisampled_textures;
u64 unused_1; // Retained for binary compatibility u64 fp_reserved_0;
pipeline_storage_type pipeline_properties; pipeline_storage_type pipeline_properties;
}; };
@ -311,6 +315,8 @@ namespace rsx
state_hash ^= rpcs3::hash_base<u16>(data.fp_lighting_flags); state_hash ^= rpcs3::hash_base<u16>(data.fp_lighting_flags);
state_hash ^= rpcs3::hash_base<u16>(data.fp_shadow_textures); state_hash ^= rpcs3::hash_base<u16>(data.fp_shadow_textures);
state_hash ^= rpcs3::hash_base<u16>(data.fp_redirected_textures); state_hash ^= rpcs3::hash_base<u16>(data.fp_redirected_textures);
state_hash ^= rpcs3::hash_base<u16>(data.vp_multisampled_textures);
state_hash ^= rpcs3::hash_base<u16>(data.fp_multisampled_textures);
const std::string pipeline_file_name = fmt::format("%llX+%llX+%llX+%llX.bin", data.vertex_program_hash, data.fragment_program_hash, data.pipeline_storage_hash, state_hash); const std::string pipeline_file_name = fmt::format("%llX+%llX+%llX+%llX.bin", data.vertex_program_hash, data.fragment_program_hash, data.pipeline_storage_hash, state_hash);
const std::string pipeline_path = root_path + "/pipelines/" + pipeline_class_name + "/" + version_prefix + "/" + pipeline_file_name; const std::string pipeline_path = root_path + "/pipelines/" + pipeline_class_name + "/" + version_prefix + "/" + pipeline_file_name;
@ -358,6 +364,7 @@ namespace rsx
vp.output_mask = data.vp_ctrl; vp.output_mask = data.vp_ctrl;
vp.texture_state.texture_dimensions = data.vp_texture_dimensions; vp.texture_state.texture_dimensions = data.vp_texture_dimensions;
vp.texture_state.multisampled_textures = data.vp_multisampled_textures;
vp.base_address = data.vp_base_address; vp.base_address = data.vp_base_address;
vp.entry = data.vp_entry; vp.entry = data.vp_entry;
@ -379,6 +386,7 @@ namespace rsx
fp.texture_state.texture_dimensions = data.fp_texture_dimensions; fp.texture_state.texture_dimensions = data.fp_texture_dimensions;
fp.texture_state.shadow_textures = data.fp_shadow_textures; fp.texture_state.shadow_textures = data.fp_shadow_textures;
fp.texture_state.redirected_textures = data.fp_redirected_textures; fp.texture_state.redirected_textures = data.fp_redirected_textures;
fp.texture_state.multisampled_textures = data.fp_multisampled_textures;
fp.texcoord_control_mask = data.fp_texcoord_control; fp.texcoord_control_mask = data.fp_texcoord_control;
fp.two_sided_lighting = !!(data.fp_lighting_flags & 0x1); fp.two_sided_lighting = !!(data.fp_lighting_flags & 0x1);
@ -395,6 +403,7 @@ namespace rsx
data_block.vp_ctrl = vp.output_mask; data_block.vp_ctrl = vp.output_mask;
data_block.vp_texture_dimensions = vp.texture_state.texture_dimensions; data_block.vp_texture_dimensions = vp.texture_state.texture_dimensions;
data_block.vp_multisampled_textures = vp.texture_state.multisampled_textures;
data_block.vp_base_address = vp.base_address; data_block.vp_base_address = vp.base_address;
data_block.vp_entry = vp.entry; data_block.vp_entry = vp.entry;
@ -424,6 +433,7 @@ namespace rsx
data_block.fp_lighting_flags = u16(fp.two_sided_lighting); data_block.fp_lighting_flags = u16(fp.two_sided_lighting);
data_block.fp_shadow_textures = fp.texture_state.shadow_textures; data_block.fp_shadow_textures = fp.texture_state.shadow_textures;
data_block.fp_redirected_textures = fp.texture_state.redirected_textures; data_block.fp_redirected_textures = fp.texture_state.redirected_textures;
data_block.fp_multisampled_textures = fp.texture_state.multisampled_textures;
return data_block; return data_block;
} }