mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-05 00:42:48 +00:00
Merge branch 'shadps4-emu:main' into main
This commit is contained in:
commit
a4f9c72901
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@ -14,14 +14,14 @@ env:
|
||||
|
||||
jobs:
|
||||
reuse:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: fsfe/reuse-action@v5
|
||||
|
||||
clang-format:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -39,7 +39,7 @@ jobs:
|
||||
run: ./.ci/clang-format.sh
|
||||
|
||||
get-info:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
date: ${{ steps.vars.outputs.date }}
|
||||
shorthash: ${{ steps.vars.outputs.shorthash }}
|
||||
@ -57,7 +57,7 @@ jobs:
|
||||
echo "fullhash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
windows-sdl:
|
||||
runs-on: windows-latest
|
||||
runs-on: windows-2025
|
||||
needs: get-info
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -101,7 +101,7 @@ jobs:
|
||||
path: ${{github.workspace}}/build/shadPS4.exe
|
||||
|
||||
windows-qt:
|
||||
runs-on: windows-latest
|
||||
runs-on: windows-2025
|
||||
needs: get-info
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -119,19 +119,23 @@ public:
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::optional<vk::BufferMemoryBarrier2> GetBarrier(vk::AccessFlagBits2 dst_acess_mask,
|
||||
vk::PipelineStageFlagBits2 dst_stage) {
|
||||
std::optional<vk::BufferMemoryBarrier2> GetBarrier(
|
||||
vk::Flags<vk::AccessFlagBits2> dst_acess_mask, vk::PipelineStageFlagBits2 dst_stage,
|
||||
u32 offset = 0) {
|
||||
if (dst_acess_mask == access_mask && stage == dst_stage) {
|
||||
return {};
|
||||
}
|
||||
|
||||
DEBUG_ASSERT(offset < size_bytes);
|
||||
|
||||
auto barrier = vk::BufferMemoryBarrier2{
|
||||
.srcStageMask = stage,
|
||||
.srcAccessMask = access_mask,
|
||||
.dstStageMask = dst_stage,
|
||||
.dstAccessMask = dst_acess_mask,
|
||||
.buffer = buffer.buffer,
|
||||
.size = size_bytes,
|
||||
.offset = offset,
|
||||
.size = size_bytes - offset,
|
||||
};
|
||||
access_mask = dst_acess_mask;
|
||||
stage = dst_stage;
|
||||
@ -150,8 +154,10 @@ public:
|
||||
Vulkan::Scheduler* scheduler;
|
||||
MemoryUsage usage;
|
||||
UniqueBuffer buffer;
|
||||
vk::AccessFlagBits2 access_mask{vk::AccessFlagBits2::eNone};
|
||||
vk::PipelineStageFlagBits2 stage{vk::PipelineStageFlagBits2::eNone};
|
||||
vk::Flags<vk::AccessFlagBits2> access_mask{
|
||||
vk::AccessFlagBits2::eMemoryRead | vk::AccessFlagBits2::eMemoryWrite |
|
||||
vk::AccessFlagBits2::eTransferRead | vk::AccessFlagBits2::eTransferWrite};
|
||||
vk::PipelineStageFlagBits2 stage{vk::PipelineStageFlagBits2::eAllCommands};
|
||||
};
|
||||
|
||||
class StreamBuffer : public Buffer {
|
||||
|
@ -34,21 +34,10 @@ BufferCache::BufferCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& s
|
||||
|
||||
// Ensure the first slot is used for the null buffer
|
||||
const auto null_id =
|
||||
slot_buffers.insert(instance, scheduler, MemoryUsage::DeviceLocal, 0, ReadFlags, 1);
|
||||
slot_buffers.insert(instance, scheduler, MemoryUsage::DeviceLocal, 0, ReadFlags, 16);
|
||||
ASSERT(null_id.index == 0);
|
||||
const vk::Buffer& null_buffer = slot_buffers[null_id].buffer;
|
||||
Vulkan::SetObjectName(instance.GetDevice(), null_buffer, "Null Buffer");
|
||||
|
||||
const vk::BufferViewCreateInfo null_view_ci = {
|
||||
.buffer = null_buffer,
|
||||
.format = vk::Format::eR8Unorm,
|
||||
.offset = 0,
|
||||
.range = VK_WHOLE_SIZE,
|
||||
};
|
||||
const auto [null_view_result, null_view] = instance.GetDevice().createBufferView(null_view_ci);
|
||||
ASSERT_MSG(null_view_result == vk::Result::eSuccess, "Failed to create null buffer view.");
|
||||
null_buffer_view = null_view;
|
||||
Vulkan::SetObjectName(instance.GetDevice(), null_buffer_view, "Null Buffer View");
|
||||
}
|
||||
|
||||
BufferCache::~BufferCache() = default;
|
||||
@ -479,43 +468,36 @@ void BufferCache::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id,
|
||||
};
|
||||
scheduler.EndRendering();
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
const std::array pre_barriers = {
|
||||
vk::BufferMemoryBarrier2{
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eAllCommands,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eMemoryRead | vk::AccessFlagBits2::eMemoryWrite,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||
.dstAccessMask = vk::AccessFlagBits2::eTransferRead,
|
||||
.buffer = overlap.Handle(),
|
||||
.offset = 0,
|
||||
.size = overlap.SizeBytes(),
|
||||
},
|
||||
};
|
||||
const std::array post_barriers = {
|
||||
vk::BufferMemoryBarrier2{
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eTransferRead,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eAllCommands,
|
||||
.dstAccessMask = vk::AccessFlagBits2::eMemoryWrite,
|
||||
.buffer = overlap.Handle(),
|
||||
.offset = 0,
|
||||
.size = overlap.SizeBytes(),
|
||||
},
|
||||
vk::BufferMemoryBarrier2{
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eAllCommands,
|
||||
.dstAccessMask = vk::AccessFlagBits2::eMemoryRead | vk::AccessFlagBits2::eMemoryWrite,
|
||||
.buffer = new_buffer.Handle(),
|
||||
.offset = dst_base_offset,
|
||||
.size = overlap.SizeBytes(),
|
||||
},
|
||||
};
|
||||
|
||||
boost::container::static_vector<vk::BufferMemoryBarrier2, 2> pre_barriers{};
|
||||
if (auto src_barrier = overlap.GetBarrier(vk::AccessFlagBits2::eTransferRead,
|
||||
vk::PipelineStageFlagBits2::eTransfer)) {
|
||||
pre_barriers.push_back(*src_barrier);
|
||||
}
|
||||
if (auto dst_barrier =
|
||||
new_buffer.GetBarrier(vk::AccessFlagBits2::eTransferWrite,
|
||||
vk::PipelineStageFlagBits2::eTransfer, dst_base_offset)) {
|
||||
pre_barriers.push_back(*dst_barrier);
|
||||
}
|
||||
cmdbuf.pipelineBarrier2(vk::DependencyInfo{
|
||||
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
|
||||
.bufferMemoryBarrierCount = 1,
|
||||
.bufferMemoryBarrierCount = static_cast<u32>(pre_barriers.size()),
|
||||
.pBufferMemoryBarriers = pre_barriers.data(),
|
||||
});
|
||||
|
||||
cmdbuf.copyBuffer(overlap.Handle(), new_buffer.Handle(), copy);
|
||||
|
||||
boost::container::static_vector<vk::BufferMemoryBarrier2, 2> post_barriers{};
|
||||
if (auto src_barrier =
|
||||
overlap.GetBarrier(vk::AccessFlagBits2::eMemoryRead | vk::AccessFlagBits2::eMemoryWrite,
|
||||
vk::PipelineStageFlagBits2::eAllCommands)) {
|
||||
post_barriers.push_back(*src_barrier);
|
||||
}
|
||||
if (auto dst_barrier = new_buffer.GetBarrier(
|
||||
vk::AccessFlagBits2::eMemoryRead | vk::AccessFlagBits2::eMemoryWrite,
|
||||
vk::PipelineStageFlagBits2::eAllCommands, dst_base_offset)) {
|
||||
post_barriers.push_back(*dst_barrier);
|
||||
}
|
||||
cmdbuf.pipelineBarrier2(vk::DependencyInfo{
|
||||
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
|
||||
.bufferMemoryBarrierCount = static_cast<u32>(post_barriers.size()),
|
||||
@ -626,7 +608,8 @@ void BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size,
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
const vk::BufferMemoryBarrier2 pre_barrier = {
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eAllCommands,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eMemoryRead,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eMemoryRead | vk::AccessFlagBits2::eMemoryWrite |
|
||||
vk::AccessFlagBits2::eTransferRead | vk::AccessFlagBits2::eTransferWrite,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||
.dstAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||
.buffer = buffer.Handle(),
|
||||
|
@ -71,10 +71,6 @@ public:
|
||||
return slot_buffers[id];
|
||||
}
|
||||
|
||||
[[nodiscard]] vk::BufferView& NullBufferView() {
|
||||
return null_buffer_view;
|
||||
}
|
||||
|
||||
/// Invalidates any buffer in the logical page range.
|
||||
void InvalidateMemory(VAddr device_addr, u64 size);
|
||||
|
||||
@ -160,7 +156,6 @@ private:
|
||||
std::shared_mutex mutex;
|
||||
Common::SlotVector<Buffer> slot_buffers;
|
||||
RangeSet gpu_modified_ranges;
|
||||
vk::BufferView null_buffer_view;
|
||||
MemoryTracker memory_tracker;
|
||||
PageTable page_table;
|
||||
};
|
||||
|
@ -537,6 +537,7 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding
|
||||
}
|
||||
|
||||
// Second pass to re-bind buffers that were updated after binding
|
||||
auto& null_buffer = buffer_cache.GetBuffer(VideoCore::NULL_BUFFER_ID);
|
||||
for (u32 i = 0; i < buffer_bindings.size(); i++) {
|
||||
const auto& [buffer_id, vsharp] = buffer_bindings[i];
|
||||
const auto& desc = stage.buffers[i];
|
||||
@ -548,7 +549,6 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding
|
||||
} else if (instance.IsNullDescriptorSupported()) {
|
||||
buffer_infos.emplace_back(VK_NULL_HANDLE, 0, VK_WHOLE_SIZE);
|
||||
} else {
|
||||
auto& null_buffer = buffer_cache.GetBuffer(VideoCore::NULL_BUFFER_ID);
|
||||
buffer_infos.emplace_back(null_buffer.Handle(), 0, VK_WHOLE_SIZE);
|
||||
}
|
||||
} else {
|
||||
@ -582,17 +582,19 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding
|
||||
++binding.buffer;
|
||||
}
|
||||
|
||||
const auto null_buffer_view =
|
||||
instance.IsNullDescriptorSupported() ? VK_NULL_HANDLE : buffer_cache.NullBufferView();
|
||||
for (u32 i = 0; i < texbuffer_bindings.size(); i++) {
|
||||
const auto& [buffer_id, vsharp] = texbuffer_bindings[i];
|
||||
const auto& desc = stage.texture_buffers[i];
|
||||
vk::BufferView& buffer_view = buffer_views.emplace_back(null_buffer_view);
|
||||
// Fallback format for null buffer view; never used in valid buffer case.
|
||||
const auto data_fmt = vsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid
|
||||
? vsharp.GetDataFmt()
|
||||
: AmdGpu::DataFormat::Format8;
|
||||
const u32 fmt_stride = AmdGpu::NumBits(data_fmt) >> 3;
|
||||
vk::BufferView buffer_view;
|
||||
if (buffer_id) {
|
||||
const u32 alignment = instance.TexelBufferMinAlignment();
|
||||
const auto [vk_buffer, offset] = buffer_cache.ObtainBuffer(
|
||||
vsharp.base_address, vsharp.GetSize(), desc.is_written, true, buffer_id);
|
||||
const u32 fmt_stride = AmdGpu::NumBits(vsharp.GetDataFmt()) >> 3;
|
||||
const u32 buf_stride = vsharp.GetStride();
|
||||
ASSERT_MSG(buf_stride % fmt_stride == 0,
|
||||
"Texel buffer stride must match format stride");
|
||||
@ -600,9 +602,8 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding
|
||||
const u32 adjust = offset - offset_aligned;
|
||||
ASSERT(adjust % fmt_stride == 0);
|
||||
push_data.AddTexelOffset(binding.buffer, buf_stride / fmt_stride, adjust / fmt_stride);
|
||||
buffer_view =
|
||||
vk_buffer->View(offset_aligned, vsharp.GetSize() + adjust, desc.is_written,
|
||||
vsharp.GetDataFmt(), vsharp.GetNumberFmt());
|
||||
buffer_view = vk_buffer->View(offset_aligned, vsharp.GetSize() + adjust,
|
||||
desc.is_written, data_fmt, vsharp.GetNumberFmt());
|
||||
if (auto barrier =
|
||||
vk_buffer->GetBarrier(desc.is_written ? vk::AccessFlagBits2::eShaderWrite
|
||||
: vk::AccessFlagBits2::eShaderRead,
|
||||
@ -612,6 +613,11 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding
|
||||
if (desc.is_written) {
|
||||
texture_cache.InvalidateMemoryFromGPU(vsharp.base_address, vsharp.GetSize());
|
||||
}
|
||||
} else if (instance.IsNullDescriptorSupported()) {
|
||||
buffer_view = VK_NULL_HANDLE;
|
||||
} else {
|
||||
buffer_view =
|
||||
null_buffer.View(0, fmt_stride, desc.is_written, data_fmt, vsharp.GetNumberFmt());
|
||||
}
|
||||
|
||||
set_writes.push_back({
|
||||
@ -621,7 +627,7 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = desc.is_written ? vk::DescriptorType::eStorageTexelBuffer
|
||||
: vk::DescriptorType::eUniformTexelBuffer,
|
||||
.pTexelBufferView = &buffer_view,
|
||||
.pTexelBufferView = &buffer_views.emplace_back(buffer_view),
|
||||
});
|
||||
++binding.buffer;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user