Browse Source

[vk:fp] properly differentiate attributes from the fixed pipeline dirty tracker

Signed-off-by: lizzie <lizzie@eden-emu.dev>
lizzie/vids-ratatata
lizzie 2 months ago
committed by crueter
parent
commit
951432028a
  1. 30
      src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
  2. 2
      src/video_core/renderer_vulkan/fixed_pipeline_state.h
  3. 99
      src/video_core/renderer_vulkan/vk_rasterizer.cpp

30
src/video_core/renderer_vulkan/fixed_pipeline_state.cpp

@ -105,22 +105,24 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
if (maxwell3d.dirty.flags[Dirty::VertexInput]) {
if (features.has_dynamic_vertex_input) {
// Dirty flag will be reset by the command buffer update
static constexpr std::array LUT{
0u, // Invalid
1u, // SignedNorm
1u, // UnsignedNorm
2u, // SignedInt
3u, // UnsignedInt
1u, // UnsignedScaled
1u, // SignedScaled
1u, // Float
};
// 0u, // Invalid
// 1u, // SignedNorm
// 2u, // UnsignedNorm
// 3u, // SignedInt
// 4u, // UnsignedInt
// 5u, // UnsignedScaled
// 6u, // SignedScaled
// 7u, // Float
// We sparsely store the bits for each of them, so if they clash we don't deal
// with the fixed pipeline taking in invalid vertices! :)
const auto& attrs = regs.vertex_attrib_format;
attribute_types = 0;
attribute_types[0] = attribute_types[1] = attribute_types[2] = attribute_types[3] = 0;
for (size_t i = 0; i < Maxwell::NumVertexAttributes; ++i) {
const u32 mask = attrs[i].constant != 0 ? 0 : 3;
const u32 type = LUT[static_cast<size_t>(attrs[i].type.Value())];
attribute_types |= static_cast<u64>(type & mask) << (i * 2);
u32 const mask = attrs[i].constant != 0 ? 0 : 0x07; // non-constant equates invalid
u32 const type = size_t(attrs[i].type.Value());
attribute_types[0] |= u64((type >> 0) & 1) << i;
attribute_types[1] |= u64((type >> 1) & 1) << i;
attribute_types[2] |= u64((type >> 2) & 1) << i;
}
} else {
maxwell3d.dirty.flags[Dirty::VertexInput] = false;

2
src/video_core/renderer_vulkan/fixed_pipeline_state.h

@ -226,7 +226,7 @@ struct FixedPipelineState {
std::array<u16, Maxwell::NumViewports> viewport_swizzles;
union {
u64 attribute_types; // Used with VK_EXT_vertex_input_dynamic_state
u64 attribute_types[3]; // Used with VK_EXT_vertex_input_dynamic_state
u64 enabled_divisors;
};

99
src/video_core/renderer_vulkan/vk_rasterizer.cpp

@ -1758,61 +1758,60 @@ void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs&
}
void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs) {
auto& dirty{maxwell3d->dirty.flags};
if (!dirty[Dirty::VertexInput]) {
return;
}
dirty[Dirty::VertexInput] = false;
boost::container::static_vector<VkVertexInputBindingDescription2EXT, 32> bindings;
boost::container::static_vector<VkVertexInputAttributeDescription2EXT, 32> attributes;
// There seems to be a bug on Nvidia's driver where updating only higher attributes ends up
// generating dirty state. Track the highest dirty attribute and update all attributes until
// that one.
size_t highest_dirty_attr{};
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
if (dirty[Dirty::VertexAttribute0 + index]) {
highest_dirty_attr = index;
auto& dirty = maxwell3d->dirty.flags;
if (dirty[Dirty::VertexInput]) {
dirty[Dirty::VertexInput] = false;
boost::container::static_vector<VkVertexInputBindingDescription2EXT, Maxwell::NumVertexAttributes> bindings;
boost::container::static_vector<VkVertexInputAttributeDescription2EXT, Maxwell::NumVertexAttributes> attributes;
// There seems to be a bug on Nvidia's driver where updating only higher attributes ends up
// generating dirty state. Track the highest dirty attribute and update all attributes until
// that one.
size_t highest_dirty_attr = 0;
if (device.IsNvidia()) {
for (size_t i = 0; i < Maxwell::NumVertexAttributes; ++i)
if (dirty[Dirty::VertexAttribute0 + i])
highest_dirty_attr = i;
} else {
highest_dirty_attr = Maxwell::NumVertexAttributes;
}
}
for (size_t index = 0; index < highest_dirty_attr; ++index) {
const Maxwell::VertexAttribute attribute{regs.vertex_attrib_format[index]};
const u32 binding{attribute.buffer};
dirty[Dirty::VertexAttribute0 + index] = false;
dirty[Dirty::VertexBinding0 + static_cast<size_t>(binding)] = true;
if (!attribute.constant) {
attributes.push_back({
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT,
.pNext = nullptr,
.location = static_cast<u32>(index),
.binding = binding,
.format = MaxwellToVK::VertexFormat(device, attribute.type, attribute.size),
.offset = attribute.offset,
});
for (size_t i = 0; i < highest_dirty_attr; ++i) {
if (dirty[Dirty::VertexAttribute0 + i]) {
dirty[Dirty::VertexAttribute0 + i] = false;
Maxwell::VertexAttribute const attribute = regs.vertex_attrib_format[i];
u32 const binding = attribute.buffer;
dirty[Dirty::VertexBinding0 + size_t(binding)] = true;
if (!attribute.constant) {
attributes.push_back({
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT,
.pNext = nullptr,
.location = u32(i),
.binding = binding,
.format = MaxwellToVK::VertexFormat(device, attribute.type, attribute.size),
.offset = attribute.offset,
});
}
}
}
}
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
if (!dirty[Dirty::VertexBinding0 + index]) {
continue;
for (size_t i = 0; i < Maxwell::NumVertexAttributes; ++i) {
if (dirty[Dirty::VertexBinding0 + i]) {
dirty[Dirty::VertexBinding0 + i] = false;
const u32 binding = u32(i);
const auto& input_binding = regs.vertex_streams[binding];
const bool is_instanced = regs.vertex_stream_instances.IsInstancingEnabled(binding);
bindings.push_back({
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT,
.pNext = nullptr,
.binding = binding,
.stride = input_binding.stride,
.inputRate = is_instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX,
.divisor = is_instanced ? input_binding.frequency : 1,
});
}
}
dirty[Dirty::VertexBinding0 + index] = false;
const u32 binding{static_cast<u32>(index)};
const auto& input_binding{regs.vertex_streams[binding]};
const bool is_instanced{regs.vertex_stream_instances.IsInstancingEnabled(binding)};
bindings.push_back({
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT,
.pNext = nullptr,
.binding = binding,
.stride = input_binding.stride,
.inputRate = is_instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX,
.divisor = is_instanced ? input_binding.frequency : 1,
scheduler.Record([bindings, attributes](vk::CommandBuffer cmdbuf) {
cmdbuf.SetVertexInputEXT(bindings, attributes);
});
}
scheduler.Record([bindings, attributes](vk::CommandBuffer cmdbuf) {
cmdbuf.SetVertexInputEXT(bindings, attributes);
});
}
void RasterizerVulkan::InitializeChannel(Tegra::Control::ChannelState& channel) {

Loading…
Cancel
Save