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:
parent
cf6a40fc12
commit
91dddca26e
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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{};
|
||||||
};
|
};
|
||||||
|
|
Reference in New Issue