[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

@@ -2135,11 +2135,12 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
}
// TODO(Triang3l): Memory export.
reg::RB_DEPTHCONTROL normalized_depth_control =
draw_util::GetNormalizedDepthControl(regs);
uint32_t normalized_color_mask =
pixel_shader ? draw_util::GetNormalizedColorMask(
regs, pixel_shader->writes_color_targets())
uint32_t ps_param_gen_pos = UINT32_MAX;
uint32_t interpolator_mask =
pixel_shader ? (vertex_shader->writes_interpolators() &
pixel_shader->GetInterpolatorInputMask(
regs.Get<reg::SQ_PROGRAM_CNTL>(),
regs.Get<reg::SQ_CONTEXT_MISC>(), ps_param_gen_pos))
: 0;
PrimitiveProcessor::ProcessingResult primitive_processing_result;
@@ -2177,11 +2178,11 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
// Shader modifications.
vertex_shader_modification =
pipeline_cache_->GetCurrentVertexShaderModification(
*vertex_shader,
primitive_processing_result.host_vertex_shader_type);
*vertex_shader, primitive_processing_result.host_vertex_shader_type,
interpolator_mask);
pixel_shader_modification =
pixel_shader ? pipeline_cache_->GetCurrentPixelShaderModification(
*pixel_shader, normalized_color_mask)
*pixel_shader, interpolator_mask, ps_param_gen_pos)
: SpirvShaderTranslator::Modification(0);
// Translate the shaders now to obtain the sampler bindings.
@@ -2270,6 +2271,12 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
}
// Set up the render targets - this may perform dispatches and draws.
reg::RB_DEPTHCONTROL normalized_depth_control =
draw_util::GetNormalizedDepthControl(regs);
uint32_t normalized_color_mask =
pixel_shader ? draw_util::GetNormalizedColorMask(
regs, pixel_shader->writes_color_targets())
: 0;
if (!render_target_cache_->Update(is_rasterization_done,
normalized_depth_control,
normalized_color_mask, *vertex_shader)) {

View File

@@ -16,6 +16,7 @@
#include <memory>
#include <utility>
#include "third_party/fmt/include/fmt/format.h"
#include "third_party/glslang/SPIRV/SpvBuilder.h"
#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
@@ -116,43 +117,56 @@ VulkanShader* VulkanPipelineCache::LoadShader(xenos::ShaderType shader_type,
SpirvShaderTranslator::Modification
VulkanPipelineCache::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 SpirvShaderTranslator::Modification(
SpirvShaderTranslator::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;
return modification;
}
SpirvShaderTranslator::Modification
VulkanPipelineCache::GetCurrentPixelShaderModification(
const Shader& shader, uint32_t normalized_color_mask) const {
const Shader& shader, uint32_t interpolator_mask,
uint32_t param_gen_pos) 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>();
SpirvShaderTranslator::Modification modification(
shader_translator_->GetDefaultPixelShaderModification(
shader.GetDynamicAddressableRegisterCount(
sq_program_cntl.ps_num_reg)));
regs.Get<reg::SQ_PROGRAM_CNTL>().ps_num_reg)));
if (sq_program_cntl.param_gen) {
auto sq_context_misc = regs.Get<reg::SQ_CONTEXT_MISC>();
if (sq_context_misc.param_gen_pos <
std::min(std::max(modification.pixel.dynamic_addressable_register_count,
shader.register_static_address_bound()),
xenos::kMaxInterpolators)) {
modification.pixel.param_gen_enable = 1;
modification.pixel.param_gen_interpolator = sq_context_misc.param_gen_pos;
auto vgt_draw_initiator = regs.Get<reg::VGT_DRAW_INITIATOR>();
modification.pixel.param_gen_point = uint32_t(
vgt_draw_initiator.prim_type == xenos::PrimitiveType::kPointList);
}
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;
}
using DepthStencilMode =
@@ -267,7 +281,10 @@ bool VulkanPipelineCache::ConfigurePipeline(
}
VkShaderModule geometry_shader = VK_NULL_HANDLE;
GeometryShaderKey geometry_shader_key;
if (GetGeometryShaderKey(description.geometry_shader, geometry_shader_key)) {
if (GetGeometryShaderKey(
description.geometry_shader,
SpirvShaderTranslator::Modification(vertex_shader->modification()),
geometry_shader_key)) {
geometry_shader = GetGeometryShader(geometry_shader_key);
if (geometry_shader == VK_NULL_HANDLE) {
return false;
@@ -796,20 +813,28 @@ bool VulkanPipelineCache::ArePipelineRequirementsMet(
}
bool VulkanPipelineCache::GetGeometryShaderKey(
PipelineGeometryShader geometry_shader_type, GeometryShaderKey& key_out) {
PipelineGeometryShader geometry_shader_type,
SpirvShaderTranslator::Modification vertex_shader_modification,
GeometryShaderKey& key_out) {
if (geometry_shader_type == PipelineGeometryShader::kNone) {
return false;
}
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 */ 0;
key.user_clip_plane_cull = 0;
key.has_vertex_kill_and = /* 1 */ 0;
key.has_point_size = /* 1 */ 0;
key.has_point_coordinates = /* 1 */ 0;
// TODO(Triang3l): Once all needed inputs and outputs are added, uncomment the
// real counts here.
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 */ 0;
key.user_clip_plane_cull =
/* vertex_shader_modification.vertex.user_clip_plane_cull */ 0;
key.has_vertex_kill_and =
/* vertex_shader_modification.vertex.vertex_kill_and */ 0;
key.has_point_size =
/* vertex_shader_modification.vertex.output_point_size */ 0;
key.has_point_coordinates =
/* pixel_shader_modification.pixel.param_gen_point */ 0;
key_out = key;
return true;
}
@@ -887,12 +912,6 @@ VkShaderModule VulkanPipelineCache::GetGeometryShader(GeometryShaderKey key) {
? builder.makeArrayType(
type_float, builder.makeUintConstant(cull_distance_count), 0)
: spv::NoType;
spv::Id type_interpolators =
key.interpolator_count
? builder.makeArrayType(
type_float4, builder.makeUintConstant(key.interpolator_count),
0)
: spv::NoType;
spv::Id type_point_coordinates = key.has_point_coordinates
? builder.makeVectorType(type_float, 2)
: spv::NoType;
@@ -958,15 +977,16 @@ VkShaderModule VulkanPipelineCache::GetGeometryShader(GeometryShaderKey key) {
type_array_in_gl_per_vertex, "gl_in");
main_interface.push_back(in_gl_per_vertex);
// Interpolators output.
spv::Id out_interpolators = spv::NoResult;
if (key.interpolator_count) {
out_interpolators =
builder.createVariable(spv::NoPrecision, spv::StorageClassOutput,
type_interpolators, "xe_out_interpolators");
builder.addDecoration(out_interpolators, spv::DecorationLocation, 0);
builder.addDecoration(out_interpolators, spv::DecorationInvariant);
main_interface.push_back(out_interpolators);
// Interpolators outputs.
std::array<spv::Id, xenos::kMaxInterpolators> out_interpolators;
for (uint32_t i = 0; i < key.interpolator_count; ++i) {
spv::Id out_interpolator = builder.createVariable(
spv::NoPrecision, spv::StorageClassOutput, type_float4,
fmt::format("xe_out_interpolator_{}", i).c_str());
out_interpolators[i] = out_interpolator;
builder.addDecoration(out_interpolator, spv::DecorationLocation, i);
builder.addDecoration(out_interpolator, spv::DecorationInvariant);
main_interface.push_back(out_interpolator);
}
// Point coordinate output.
@@ -981,16 +1001,17 @@ VkShaderModule VulkanPipelineCache::GetGeometryShader(GeometryShaderKey key) {
main_interface.push_back(out_point_coordinates);
}
// Interpolator input.
spv::Id in_interpolators = spv::NoResult;
if (key.interpolator_count) {
in_interpolators = builder.createVariable(
// Interpolator inputs.
std::array<spv::Id, xenos::kMaxInterpolators> in_interpolators;
for (uint32_t i = 0; i < key.interpolator_count; ++i) {
spv::Id in_interpolator = builder.createVariable(
spv::NoPrecision, spv::StorageClassInput,
builder.makeArrayType(type_interpolators,
const_input_primitive_vertex_count, 0),
"xe_in_interpolators");
builder.addDecoration(in_interpolators, spv::DecorationLocation, 0);
main_interface.push_back(in_interpolators);
builder.makeArrayType(type_float4, const_input_primitive_vertex_count,
0),
fmt::format("xe_in_interpolator_{}", i).c_str());
in_interpolators[i] = in_interpolator;
builder.addDecoration(in_interpolator, spv::DecorationLocation, i);
main_interface.push_back(in_interpolator);
}
// Point size input.
@@ -1295,15 +1316,15 @@ VkShaderModule VulkanPipelineCache::GetGeometryShader(GeometryShaderKey key) {
for (uint32_t i = 0; i < 3; ++i) {
spv::Id vertex_index = vertex_indices[i];
// Interpolators.
if (key.interpolator_count) {
id_vector_temp.clear();
id_vector_temp.push_back(vertex_index);
id_vector_temp.clear();
id_vector_temp.push_back(vertex_index);
for (uint32_t j = 0; j < key.interpolator_count; ++j) {
builder.createStore(
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_interpolators, id_vector_temp),
spv::NoPrecision),
out_interpolators);
builder.createLoad(builder.createAccessChain(
spv::StorageClassInput,
in_interpolators[j], id_vector_temp),
spv::NoPrecision),
out_interpolators[j]);
}
// Point coordinates.
if (key.has_point_coordinates) {
@@ -1350,13 +1371,11 @@ VkShaderModule VulkanPipelineCache::GetGeometryShader(GeometryShaderKey key) {
// Construct the fourth vertex.
// Interpolators.
for (uint32_t i = 0; i < key.interpolator_count; ++i) {
spv::Id const_int_i = builder.makeIntConstant(int32_t(i));
spv::Id in_interpolator = in_interpolators[i];
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(vertex_indices[0]);
id_vector_temp.push_back(const_int_i);
spv::Id vertex_interpolator_v0 = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_interpolators,
builder.createAccessChain(spv::StorageClassInput, in_interpolator,
id_vector_temp),
spv::NoPrecision);
id_vector_temp[0] = vertex_indices[1];
@@ -1364,7 +1383,7 @@ VkShaderModule VulkanPipelineCache::GetGeometryShader(GeometryShaderKey key) {
spv::OpFSub, type_float4,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_interpolators, id_vector_temp),
in_interpolator, id_vector_temp),
spv::NoPrecision),
vertex_interpolator_v0);
builder.addDecoration(vertex_interpolator_v01,
@@ -1374,16 +1393,11 @@ VkShaderModule VulkanPipelineCache::GetGeometryShader(GeometryShaderKey key) {
spv::OpFAdd, type_float4, vertex_interpolator_v01,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_interpolators, id_vector_temp),
in_interpolator, id_vector_temp),
spv::NoPrecision));
builder.addDecoration(vertex_interpolator_v3,
spv::DecorationNoContraction);
id_vector_temp.clear();
id_vector_temp.push_back(const_int_i);
builder.createStore(
vertex_interpolator_v3,
builder.createAccessChain(spv::StorageClassOutput,
out_interpolators, id_vector_temp));
builder.createStore(vertex_interpolator_v3, out_interpolators[i]);
}
// Point coordinates.
if (key.has_point_coordinates) {
@@ -1489,15 +1503,15 @@ VkShaderModule VulkanPipelineCache::GetGeometryShader(GeometryShaderKey key) {
spv::Id const_vertex_index =
builder.makeIntConstant(int32_t(i ^ (i >> 1)));
// Interpolators.
if (key.interpolator_count) {
id_vector_temp.clear();
id_vector_temp.push_back(const_vertex_index);
id_vector_temp.clear();
id_vector_temp.push_back(const_vertex_index);
for (uint32_t j = 0; j < key.interpolator_count; ++j) {
builder.createStore(
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_interpolators, id_vector_temp),
spv::NoPrecision),
out_interpolators);
builder.createLoad(builder.createAccessChain(
spv::StorageClassInput,
in_interpolators[j], id_vector_temp),
spv::NoPrecision),
out_interpolators[j]);
}
// Point coordinates.
if (key.has_point_coordinates) {

View File

@@ -70,9 +70,11 @@ class VulkanPipelineCache {
// have microcode analyzed.
SpirvShaderTranslator::Modification GetCurrentVertexShaderModification(
const Shader& shader,
Shader::HostVertexShaderType host_vertex_shader_type) const;
Shader::HostVertexShaderType host_vertex_shader_type,
uint32_t interpolator_mask) const;
SpirvShaderTranslator::Modification GetCurrentPixelShaderModification(
const Shader& shader, uint32_t normalized_color_mask) const;
const Shader& shader, uint32_t interpolator_mask,
uint32_t param_gen_pos) const;
bool EnsureShadersTranslated(VulkanShader::VulkanTranslation* vertex_shader,
VulkanShader::VulkanTranslation* pixel_shader);
@@ -262,8 +264,10 @@ class VulkanPipelineCache {
// Whether the pipeline for the given description is supported by the device.
bool ArePipelineRequirementsMet(const PipelineDescription& description) const;
static bool GetGeometryShaderKey(PipelineGeometryShader geometry_shader_type,
GeometryShaderKey& key_out);
static bool GetGeometryShaderKey(
PipelineGeometryShader geometry_shader_type,
SpirvShaderTranslator::Modification vertex_shader_modification,
GeometryShaderKey& key_out);
VkShaderModule GetGeometryShader(GeometryShaderKey key);
// Can be called from creation threads - all needed data must be fully set up