vk_rasterizer: Implement constant attributes

Constant attributes (in OpenGL known disabled attributes) are not
supported on Vulkan, even with extensions. To emulate this behavior we
return zero on reads from disabled vertex attributes in shader code.
This has no caching cost because attribute formats are not dynamic state
on Vulkan and we have to store it in the pipeline cache anyway.

- Fixes Animal Crossing: New Horizons terrain borders
This commit is contained in:
ReinUsesLisp 2020-05-13 04:32:41 -03:00
parent cf6a40fc12
commit 91dddca26e
4 changed files with 26 additions and 13 deletions

View File

@ -312,7 +312,9 @@ VKPipelineCache::DecompileShaders(const GraphicsPipelineCacheKey& key) {
ASSERT(point_size != 0.0f); ASSERT(point_size != 0.0f);
} }
for (std::size_t i = 0; i < Maxwell::NumVertexAttributes; ++i) { for (std::size_t i = 0; i < Maxwell::NumVertexAttributes; ++i) {
specialization.attribute_types[i] = fixed_state.vertex_input.attributes[i].Type(); const auto& attribute = fixed_state.vertex_input.attributes[i];
specialization.enabled_attributes[i] = attribute.enabled.Value() != 0;
specialization.attribute_types[i] = attribute.Type();
} }
specialization.ndc_minus_one_to_one = fixed_state.rasterizer.ndc_minus_one_to_one; specialization.ndc_minus_one_to_one = fixed_state.rasterizer.ndc_minus_one_to_one;

View File

@ -875,7 +875,7 @@ void RasterizerVulkan::SetupVertexArrays(FixedPipelineState::VertexInput& vertex
for (std::size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) { for (std::size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
const auto& attrib = regs.vertex_attrib_format[index]; const auto& attrib = regs.vertex_attrib_format[index];
if (!attrib.IsValid()) { if (attrib.IsConstant()) {
vertex_input.SetAttribute(index, false, 0, 0, {}, {}); vertex_input.SetAttribute(index, false, 0, 0, {}, {});
continue; continue;
} }

View File

@ -731,8 +731,10 @@ private:
if (!IsGenericAttribute(index)) { if (!IsGenericAttribute(index)) {
continue; continue;
} }
const u32 location = GetGenericAttributeLocation(index); const u32 location = GetGenericAttributeLocation(index);
if (!IsAttributeEnabled(location)) {
continue;
}
const auto type_descriptor = GetAttributeType(location); const auto type_descriptor = GetAttributeType(location);
Id type; Id type;
if (IsInputAttributeArray()) { if (IsInputAttributeArray()) {
@ -976,6 +978,10 @@ private:
return stage == ShaderType::TesselationControl; return stage == ShaderType::TesselationControl;
} }
bool IsAttributeEnabled(u32 location) const {
return stage != ShaderType::Vertex || specialization.enabled_attributes[location];
}
u32 GetNumInputVertices() const { u32 GetNumInputVertices() const {
switch (stage) { switch (stage) {
case ShaderType::Geometry: case ShaderType::Geometry:
@ -1192,16 +1198,20 @@ private:
UNIMPLEMENTED_MSG("Unmanaged FrontFacing element={}", element); UNIMPLEMENTED_MSG("Unmanaged FrontFacing element={}", element);
return {v_float_zero, Type::Float}; return {v_float_zero, Type::Float};
default: default:
if (IsGenericAttribute(attribute)) { if (!IsGenericAttribute(attribute)) {
const u32 location = GetGenericAttributeLocation(attribute); break;
const auto type_descriptor = GetAttributeType(location);
const Type type = type_descriptor.type;
const Id attribute_id = input_attributes.at(attribute);
const std::vector elements = {element};
const Id pointer = ArrayPass(type_descriptor.scalar, attribute_id, elements);
return {OpLoad(GetTypeDefinition(type), pointer), type};
} }
break; const u32 location = GetGenericAttributeLocation(attribute);
if (!IsAttributeEnabled(location)) {
// Disabled attributes (also known as constant attributes) always return zero.
return {v_float_zero, Type::Float};
}
const auto type_descriptor = GetAttributeType(location);
const Type type = type_descriptor.type;
const Id attribute_id = input_attributes.at(attribute);
const std::vector elements = {element};
const Id pointer = ArrayPass(type_descriptor.scalar, attribute_id, elements);
return {OpLoad(GetTypeDefinition(type), pointer), type};
} }
UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute));
return {v_float_zero, Type::Float}; return {v_float_zero, Type::Float};

View File

@ -88,7 +88,8 @@ struct Specialization final {
u32 shared_memory_size{}; u32 shared_memory_size{};
// Graphics specific // Graphics specific
std::optional<float> point_size{}; std::optional<float> point_size;
std::bitset<Maxwell::NumVertexAttributes> enabled_attributes;
std::array<Maxwell::VertexAttribute::Type, Maxwell::NumVertexAttributes> attribute_types{}; std::array<Maxwell::VertexAttribute::Type, Maxwell::NumVertexAttributes> attribute_types{};
bool ndc_minus_one_to_one{}; bool ndc_minus_one_to_one{};
}; };