mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-07-27 04:25:12 +00:00
vulkan: tighten buffer merging & enforce alignment to fix Bloodborne cracks
This commit is contained in:
parent
99ccf56938
commit
4beb21f19b
@ -216,16 +216,18 @@ void BufferCache::BindVertexBuffers(const Vulkan::GraphicsPipeline& pipeline) {
|
|||||||
// Merge connecting ranges together
|
// Merge connecting ranges together
|
||||||
Vulkan::VertexInputs<BufferRange> ranges_merged{};
|
Vulkan::VertexInputs<BufferRange> ranges_merged{};
|
||||||
if (!ranges.empty()) {
|
if (!ranges.empty()) {
|
||||||
std::ranges::sort(ranges, [](const BufferRange& lhv, const BufferRange& rhv) {
|
std::ranges::sort(ranges, [](auto& a, auto& b) { return a.base_address < b.base_address; });
|
||||||
return lhv.base_address < rhv.base_address;
|
|
||||||
});
|
|
||||||
ranges_merged.emplace_back(ranges[0]);
|
ranges_merged.emplace_back(ranges[0]);
|
||||||
for (auto range : ranges) {
|
static constexpr VAddr MAX_GAP = 64; // max gap (bytes) to merge
|
||||||
auto& prev_range = ranges_merged.back();
|
static constexpr VAddr SAFETY_PAD = 128; // pad merged ranges
|
||||||
if (prev_range.end_address < range.base_address) {
|
for (size_t i = 1; i < ranges.size(); ++i) {
|
||||||
ranges_merged.emplace_back(range);
|
auto& curr = ranges[i];
|
||||||
|
auto& prev = ranges_merged.back();
|
||||||
|
const VAddr gap = curr.base_address - prev.end_address;
|
||||||
|
if (gap <= MAX_GAP) {
|
||||||
|
prev.end_address = curr.end_address + SAFETY_PAD;
|
||||||
} else {
|
} else {
|
||||||
prev_range.end_address = std::max(prev_range.end_address, range.end_address);
|
ranges_merged.emplace_back(curr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,9 +324,12 @@ void GraphicsPipeline::GetVertexInputs(VertexInputs<Attribute>& attributes,
|
|||||||
.format = LiverpoolToVK::SurfaceFormat(buffer.GetDataFmt(), buffer.GetNumberFmt()),
|
.format = LiverpoolToVK::SurfaceFormat(buffer.GetDataFmt(), buffer.GetNumberFmt()),
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
});
|
});
|
||||||
|
// ensure vertex stride is 4-byte aligned
|
||||||
|
const u32 rawStride = buffer.GetStride();
|
||||||
|
const u32 safeStride = Common::AlignUp(rawStride, 4u);
|
||||||
bindings.push_back(Binding{
|
bindings.push_back(Binding{
|
||||||
.binding = attrib.semantic,
|
.binding = attrib.semantic,
|
||||||
.stride = buffer.GetStride(),
|
.stride = safeStride,
|
||||||
.inputRate = attrib.GetStepRate() == Shader::Gcn::VertexAttribute::InstanceIdType::None
|
.inputRate = attrib.GetStepRate() == Shader::Gcn::VertexAttribute::InstanceIdType::None
|
||||||
? vk::VertexInputRate::eVertex
|
? vk::VertexInputRate::eVertex
|
||||||
: vk::VertexInputRate::eInstance,
|
: vk::VertexInputRate::eInstance,
|
||||||
|
@ -577,13 +577,16 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding
|
|||||||
} else {
|
} else {
|
||||||
const auto [vk_buffer, offset] = buffer_cache.ObtainBuffer(
|
const auto [vk_buffer, offset] = buffer_cache.ObtainBuffer(
|
||||||
vsharp.base_address, size, desc.is_written, desc.is_formatted, buffer_id);
|
vsharp.base_address, size, desc.is_written, desc.is_formatted, buffer_id);
|
||||||
const u32 alignment =
|
// enforce at least 16-byte alignment on vertex buffer offsets
|
||||||
|
const u32 baseAlign =
|
||||||
is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment();
|
is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment();
|
||||||
const u32 offset_aligned = Common::AlignDown(offset, alignment);
|
const u32 minAlign = std::max<u32>(baseAlign, 16u);
|
||||||
const u32 adjust = offset - offset_aligned;
|
const u32 offset_align = Common::AlignDown(offset, minAlign);
|
||||||
ASSERT(adjust % 4 == 0);
|
const u32 adjust = offset - offset_align;
|
||||||
|
ASSERT_MSG(adjust % 4 == 0 && adjust < minAlign,
|
||||||
|
"Unsafe vertex offset adjust %u >= align %u", adjust, minAlign);
|
||||||
push_data.AddOffset(binding.buffer, adjust);
|
push_data.AddOffset(binding.buffer, adjust);
|
||||||
buffer_infos.emplace_back(vk_buffer->Handle(), offset_aligned, size + adjust);
|
buffer_infos.emplace_back(vk_buffer->Handle(), offset_align, size + adjust);
|
||||||
if (auto barrier =
|
if (auto barrier =
|
||||||
vk_buffer->GetBarrier(desc.is_written ? vk::AccessFlagBits2::eShaderWrite
|
vk_buffer->GetBarrier(desc.is_written ? vk::AccessFlagBits2::eShaderWrite
|
||||||
: vk::AccessFlagBits2::eShaderRead,
|
: vk::AccessFlagBits2::eShaderRead,
|
||||||
|
Loading…
Reference in New Issue
Block a user