[GPU] Eliminate unused shader I/O, UCP culling, centroid on Vulkan

For more optimal usage of exports and the parameter cache on the host regardless of how effective the optimizations in the host GPU driver are. Also reserve space for Vulkan/Metal/D3D11-specific HostVertexShaderTypes to use one more bit for the host vertex shader type in the shader modification bits, so that won't have to be done in the future as that would require invalidating shader storages (which are invalidated by this commit) again.
This commit is contained in:
Triang3l
2022-07-21 12:32:28 +03:00
parent 0a94b86cb8
commit 1a95bef8b3
22 changed files with 3366 additions and 3235 deletions

View File

@@ -643,8 +643,13 @@ void PipelineCache::InitializeShaderStorage(
}
GeometryShaderKey pipeline_geometry_shader_key;
pipeline_runtime_description.geometry_shader =
GetGeometryShaderKey(pipeline_description.geometry_shader,
pipeline_geometry_shader_key)
GetGeometryShaderKey(
pipeline_description.geometry_shader,
DxbcShaderTranslator::Modification(
pipeline_description.vertex_shader_modification),
DxbcShaderTranslator::Modification(
pipeline_description.pixel_shader_modification),
pipeline_geometry_shader_key)
? &GetGeometryShader(pipeline_geometry_shader_key)
: nullptr;
pipeline_runtime_description.root_signature =
@@ -855,29 +860,71 @@ D3D12Shader* PipelineCache::LoadShader(xenos::ShaderType shader_type,
DxbcShaderTranslator::Modification
PipelineCache::GetCurrentVertexShaderModification(
const Shader& shader,
Shader::HostVertexShaderType host_vertex_shader_type) const {
const Shader& shader, Shader::HostVertexShaderType host_vertex_shader_type,
uint32_t interpolator_mask) const {
assert_true(shader.type() == xenos::ShaderType::kVertex);
assert_true(shader.is_ucode_analyzed());
const auto& regs = register_file_;
auto sq_program_cntl = regs.Get<reg::SQ_PROGRAM_CNTL>();
return DxbcShaderTranslator::Modification(
DxbcShaderTranslator::Modification modification(
shader_translator_->GetDefaultVertexShaderModification(
shader.GetDynamicAddressableRegisterCount(sq_program_cntl.vs_num_reg),
shader.GetDynamicAddressableRegisterCount(
regs.Get<reg::SQ_PROGRAM_CNTL>().vs_num_reg),
host_vertex_shader_type));
modification.vertex.interpolator_mask = interpolator_mask;
auto pa_cl_clip_cntl = regs.Get<reg::PA_CL_CLIP_CNTL>();
uint32_t user_clip_planes =
pa_cl_clip_cntl.clip_disable ? 0 : pa_cl_clip_cntl.ucp_ena;
modification.vertex.user_clip_plane_count = xe::bit_count(user_clip_planes);
modification.vertex.user_clip_plane_cull =
uint32_t(user_clip_planes && pa_cl_clip_cntl.ucp_cull_only_ena);
modification.vertex.vertex_kill_and =
uint32_t((shader.writes_point_size_edge_flag_kill_vertex() & 0b100) &&
!pa_cl_clip_cntl.vtx_kill_or);
modification.vertex.output_point_size =
uint32_t((shader.writes_point_size_edge_flag_kill_vertex() & 0b001) &&
regs.Get<reg::VGT_DRAW_INITIATOR>().prim_type ==
xenos::PrimitiveType::kPointList);
return modification;
}
DxbcShaderTranslator::Modification
PipelineCache::GetCurrentPixelShaderModification(
const Shader& shader, reg::RB_DEPTHCONTROL normalized_depth_control) const {
const Shader& shader, uint32_t interpolator_mask, uint32_t param_gen_pos,
reg::RB_DEPTHCONTROL normalized_depth_control) const {
assert_true(shader.type() == xenos::ShaderType::kPixel);
assert_true(shader.is_ucode_analyzed());
const auto& regs = register_file_;
auto sq_program_cntl = regs.Get<reg::SQ_PROGRAM_CNTL>();
DxbcShaderTranslator::Modification modification(
shader_translator_->GetDefaultPixelShaderModification(
shader.GetDynamicAddressableRegisterCount(
sq_program_cntl.ps_num_reg)));
regs.Get<reg::SQ_PROGRAM_CNTL>().ps_num_reg)));
modification.pixel.interpolator_mask = interpolator_mask;
modification.pixel.interpolators_centroid =
interpolator_mask &
~xenos::GetInterpolatorSamplingPattern(
regs.Get<reg::RB_SURFACE_INFO>().msaa_samples,
regs.Get<reg::SQ_CONTEXT_MISC>().sc_sample_cntl,
regs.Get<reg::SQ_INTERPOLATOR_CNTL>().sampling_pattern);
if (param_gen_pos < xenos::kMaxInterpolators) {
modification.pixel.param_gen_enable = 1;
modification.pixel.param_gen_interpolator = param_gen_pos;
modification.pixel.param_gen_point =
uint32_t(regs.Get<reg::VGT_DRAW_INITIATOR>().prim_type ==
xenos::PrimitiveType::kPointList);
} else {
modification.pixel.param_gen_enable = 0;
modification.pixel.param_gen_interpolator = 0;
modification.pixel.param_gen_point = 0;
}
if (render_target_cache_.GetPath() ==
RenderTargetCache::Path::kHostRenderTargets) {
using DepthStencilMode =
@@ -901,6 +948,7 @@ PipelineCache::GetCurrentPixelShaderModification(
}
}
}
return modification;
}
@@ -1086,6 +1134,8 @@ bool PipelineCache::TranslateAnalyzedShader(
host_shader_type = "patch-indexed quad domain";
break;
default:
assert(modification.vertex.host_vertex_shader_type ==
Shader::HostVertexShaderType::kVertex);
host_shader_type = "vertex";
}
} else {
@@ -1356,7 +1406,12 @@ bool PipelineCache::GetCurrentStateDescription(
}
GeometryShaderKey geometry_shader_key;
runtime_description_out.geometry_shader =
GetGeometryShaderKey(description_out.geometry_shader, geometry_shader_key)
GetGeometryShaderKey(
description_out.geometry_shader,
DxbcShaderTranslator::Modification(vertex_shader->modification()),
DxbcShaderTranslator::Modification(
pixel_shader ? pixel_shader->modification() : 0),
geometry_shader_key)
? &GetGeometryShader(geometry_shader_key)
: nullptr;
@@ -1631,20 +1686,26 @@ bool PipelineCache::GetCurrentStateDescription(
}
bool PipelineCache::GetGeometryShaderKey(
PipelineGeometryShader geometry_shader_type, GeometryShaderKey& key_out) {
PipelineGeometryShader geometry_shader_type,
DxbcShaderTranslator::Modification vertex_shader_modification,
DxbcShaderTranslator::Modification pixel_shader_modification,
GeometryShaderKey& key_out) {
if (geometry_shader_type == PipelineGeometryShader::kNone) {
return false;
}
assert_true(vertex_shader_modification.vertex.interpolator_mask ==
pixel_shader_modification.pixel.interpolator_mask);
GeometryShaderKey key;
key.type = geometry_shader_type;
// TODO(Triang3l): Make the linkage parameters depend on the real needs of the
// vertex and the pixel shader.
key.interpolator_count = xenos::kMaxInterpolators;
key.user_clip_plane_count = 6;
key.user_clip_plane_cull = 0;
key.has_vertex_kill_and = 1;
key.has_point_size = 1;
key.has_point_coordinates = 1;
key.interpolator_count =
xe::bit_count(vertex_shader_modification.vertex.interpolator_mask);
key.user_clip_plane_count =
vertex_shader_modification.vertex.user_clip_plane_count;
key.user_clip_plane_cull =
vertex_shader_modification.vertex.user_clip_plane_cull;
key.has_vertex_kill_and = vertex_shader_modification.vertex.vertex_kill_and;
key.has_point_size = vertex_shader_modification.vertex.output_point_size;
key.has_point_coordinates = pixel_shader_modification.pixel.param_gen_point;
key_out = key;
return true;
}
@@ -1886,16 +1947,15 @@ void PipelineCache::CreateDxbcGeometryShader(
uint32_t input_clip_and_cull_distance_count =
input_clip_distance_count + input_cull_distance_count;
// Interpolators, point size, position, clip and cull distances (parameters
// containing only clip or cull distances, and also one parameter containing
// both if present).
// TODO(Triang3l): Reorder as needed when the respective changes are done in
// the shader translator.
// Interpolators, position, clip and cull distances (parameters containing
// only clip or cull distances, and also one parameter containing both if
// present), point size.
uint32_t isgn_parameter_count =
key.interpolator_count + key.has_point_size + 1 +
key.interpolator_count + 1 +
((input_clip_and_cull_distance_count + 3) / 4) +
uint32_t(input_cull_distance_count &&
(input_clip_distance_count & 3) != 0);
(input_clip_distance_count & 3) != 0) +
key.has_point_size;
// Reserve space for the header and the parameters.
shader_out[blob_offset_position_dwords] =
@@ -1910,7 +1970,7 @@ void PipelineCache::CreateDxbcGeometryShader(
name_ptr =
uint32_t((shader_out.size() - isgn_position_dwords) * sizeof(uint32_t));
uint32_t isgn_name_ptr_texcoord = name_ptr;
if (key.interpolator_count || key.has_point_size) {
if (key.interpolator_count) {
name_ptr += dxbc::AppendAlignedString(shader_out, "TEXCOORD");
}
uint32_t isgn_name_ptr_sv_position = name_ptr;
@@ -1923,12 +1983,16 @@ void PipelineCache::CreateDxbcGeometryShader(
if (input_cull_distance_count) {
name_ptr += dxbc::AppendAlignedString(shader_out, "SV_CullDistance");
}
uint32_t isgn_name_ptr_xepsize = name_ptr;
if (key.has_point_size) {
name_ptr += dxbc::AppendAlignedString(shader_out, "XEPSIZE");
}
// Header and parameters.
uint32_t input_register_interpolators = UINT32_MAX;
uint32_t input_register_point_size = UINT32_MAX;
uint32_t input_register_position;
uint32_t input_register_clip_and_cull_distances = UINT32_MAX;
uint32_t input_register_point_size = UINT32_MAX;
{
// Header.
auto& isgn_header = *reinterpret_cast<dxbc::Signature*>(
@@ -1960,27 +2024,7 @@ void PipelineCache::CreateDxbcGeometryShader(
}
}
// Point size.
// TODO(Triang3l): Put the size in X of float1, not in Z of float3, when
// linkage via shader modifications is done.
// TODO(Triang3l): Rename from TEXCOORD# to XEPSIZE when linkage via shader
// modifications is done.
if (key.has_point_size) {
input_register_point_size = input_register_index;
assert_true(isgn_parameter_index < isgn_parameter_count);
dxbc::SignatureParameter& isgn_point_size =
isgn_parameters[isgn_parameter_index++];
isgn_point_size.semantic_name_ptr = isgn_name_ptr_texcoord;
isgn_point_size.semantic_index = key.interpolator_count;
isgn_point_size.component_type =
dxbc::SignatureRegisterComponentType::kFloat32;
isgn_point_size.register_index = input_register_index++;
isgn_point_size.mask = 0b0111;
isgn_point_size.always_reads_mask =
key.type == PipelineGeometryShader::kPointList ? 0b0100 : 0;
}
// Position.
// Position (SV_Position).
input_register_position = input_register_index;
assert_true(isgn_parameter_index < isgn_parameter_count);
dxbc::SignatureParameter& isgn_sv_position =
@@ -1993,7 +2037,7 @@ void PipelineCache::CreateDxbcGeometryShader(
isgn_sv_position.mask = 0b1111;
isgn_sv_position.always_reads_mask = 0b1111;
// Clip and cull distances.
// Clip and cull distances (SV_ClipDistance#, SV_CullDistance#).
if (input_clip_and_cull_distance_count) {
input_register_clip_and_cull_distances = input_register_index;
uint32_t isgn_cull_distance_semantic_index = 0;
@@ -2041,6 +2085,21 @@ void PipelineCache::CreateDxbcGeometryShader(
}
}
// Point size (XEPSIZE).
if (key.has_point_size) {
input_register_point_size = input_register_index;
assert_true(isgn_parameter_index < isgn_parameter_count);
dxbc::SignatureParameter& isgn_point_size =
isgn_parameters[isgn_parameter_index++];
isgn_point_size.semantic_name_ptr = isgn_name_ptr_xepsize;
isgn_point_size.component_type =
dxbc::SignatureRegisterComponentType::kFloat32;
isgn_point_size.register_index = input_register_index++;
isgn_point_size.mask = 0b0001;
isgn_point_size.always_reads_mask =
key.type == PipelineGeometryShader::kPointList ? 0b0001 : 0;
}
assert_true(isgn_parameter_index == isgn_parameter_count);
}
@@ -2059,8 +2118,6 @@ void PipelineCache::CreateDxbcGeometryShader(
// ***************************************************************************
// Interpolators, point coordinates, position, clip distances.
// TODO(Triang3l): Reorder as needed when the respective changes are done in
// the shader translator.
uint32_t osgn_parameter_count = key.interpolator_count +
key.has_point_coordinates + 1 +
((input_clip_distance_count + 3) / 4);
@@ -2078,9 +2135,13 @@ void PipelineCache::CreateDxbcGeometryShader(
name_ptr =
uint32_t((shader_out.size() - osgn_position_dwords) * sizeof(uint32_t));
uint32_t osgn_name_ptr_texcoord = name_ptr;
if (key.interpolator_count || key.has_point_coordinates) {
if (key.interpolator_count) {
name_ptr += dxbc::AppendAlignedString(shader_out, "TEXCOORD");
}
uint32_t osgn_name_ptr_xespritetexcoord = name_ptr;
if (key.has_point_coordinates) {
name_ptr += dxbc::AppendAlignedString(shader_out, "XESPRITETEXCOORD");
}
uint32_t osgn_name_ptr_sv_position = name_ptr;
name_ptr += dxbc::AppendAlignedString(shader_out, "SV_Position");
uint32_t osgn_name_ptr_sv_clip_distance = name_ptr;
@@ -2123,26 +2184,21 @@ void PipelineCache::CreateDxbcGeometryShader(
}
}
// Point coordinates.
// TODO(Triang3l): Put the coordinates in XY of float2 when linkage via
// shader modifications is done.
// TODO(Triang3l): Rename from TEXCOORD# to XESPRITETEXCOORD when linkage
// via shader modifications is done.
// Point coordinates (XESPRITETEXCOORD).
if (key.has_point_coordinates) {
output_register_point_coordinates = output_register_index;
assert_true(osgn_parameter_index < osgn_parameter_count);
dxbc::SignatureParameterForGS& osgn_point_coordinates =
osgn_parameters[osgn_parameter_index++];
osgn_point_coordinates.semantic_name_ptr = osgn_name_ptr_texcoord;
osgn_point_coordinates.semantic_index = key.interpolator_count;
osgn_point_coordinates.semantic_name_ptr = osgn_name_ptr_xespritetexcoord;
osgn_point_coordinates.component_type =
dxbc::SignatureRegisterComponentType::kFloat32;
osgn_point_coordinates.register_index = output_register_index++;
osgn_point_coordinates.mask = 0b0111;
osgn_point_coordinates.mask = 0b0011;
osgn_point_coordinates.never_writes_mask = 0b1100;
}
// Position.
// Position (SV_Position).
output_register_position = output_register_index;
assert_true(osgn_parameter_index < osgn_parameter_count);
dxbc::SignatureParameterForGS& osgn_sv_position =
@@ -2154,7 +2210,7 @@ void PipelineCache::CreateDxbcGeometryShader(
osgn_sv_position.register_index = output_register_index++;
osgn_sv_position.mask = 0b1111;
// Clip distances.
// Clip distances (SV_ClipDistance#).
if (input_clip_distance_count) {
output_register_clip_distances = output_register_index;
for (uint32_t i = 0; i < input_clip_distance_count; i += 4) {
@@ -2256,11 +2312,6 @@ void PipelineCache::CreateDxbcGeometryShader(
a.OpDclInput(dxbc::Dest::V2D(input_primitive_vertex_count,
input_register_interpolators + i));
}
if (key.has_point_size && key.type == PipelineGeometryShader::kPointList) {
assert_true(input_register_point_size != UINT32_MAX);
a.OpDclInput(dxbc::Dest::V2D(input_primitive_vertex_count,
input_register_point_size, 0b0100));
}
a.OpDclInputSIV(
dxbc::Dest::V2D(input_primitive_vertex_count, input_register_position),
dxbc::Name::kPosition);
@@ -2292,6 +2343,11 @@ void PipelineCache::CreateDxbcGeometryShader(
cull_distance_mask));
}
}
if (key.has_point_size && key.type == PipelineGeometryShader::kPointList) {
assert_true(input_register_point_size != UINT32_MAX);
a.OpDclInput(dxbc::Dest::V2D(input_primitive_vertex_count,
input_register_point_size, 0b0001));
}
// At least 1 temporary register needed to discard primitives with NaN
// position.
@@ -2394,10 +2450,10 @@ void PipelineCache::CreateDxbcGeometryShader(
// constant size. The per-vertex diameter is already clamped in the
// vertex shader (combined with making it non-negative).
a.OpGE(dxbc::Dest::R(0, 0b0001),
dxbc::Src::V2D(0, input_register_point_size, dxbc::Src::kZZZZ),
dxbc::Src::V2D(0, input_register_point_size, dxbc::Src::kXXXX),
dxbc::Src::LF(0.0f));
a.OpMovC(dxbc::Dest::R(0, 0b0011), dxbc::Src::R(0, dxbc::Src::kXXXX),
dxbc::Src::V2D(0, input_register_point_size, dxbc::Src::kZZZZ),
dxbc::Src::V2D(0, input_register_point_size, dxbc::Src::kXXXX),
point_size_src);
point_size_src = dxbc::Src::R(0, 0b0100);
}