mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-01-15 03:15:13 +00:00
buffer_cache: Handle obtaining buffer views partially within buffers.
This commit is contained in:
parent
84e8168c8a
commit
cc0c49876b
|
@ -360,7 +360,8 @@ std::pair<Buffer*, u32> BufferCache::ObtainBuffer(VAddr device_addr, u32 size, b
|
||||||
return {&buffer, buffer.Offset(device_addr)};
|
return {&buffer, buffer.Offset(device_addr)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<Buffer*, u32> BufferCache::ObtainViewBuffer(VAddr gpu_addr, u32 size) {
|
std::pair<Buffer*, u32> BufferCache::ObtainViewBuffer(VAddr gpu_addr, u32 size, bool prefer_gpu) {
|
||||||
|
// Check if any buffer contains the full requested range.
|
||||||
const u64 page = gpu_addr >> CACHING_PAGEBITS;
|
const u64 page = gpu_addr >> CACHING_PAGEBITS;
|
||||||
const BufferId buffer_id = page_table[page];
|
const BufferId buffer_id = page_table[page];
|
||||||
if (buffer_id) {
|
if (buffer_id) {
|
||||||
|
@ -370,6 +371,13 @@ std::pair<Buffer*, u32> BufferCache::ObtainViewBuffer(VAddr gpu_addr, u32 size)
|
||||||
return {&buffer, buffer.Offset(gpu_addr)};
|
return {&buffer, buffer.Offset(gpu_addr)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If no buffer contains the full requested range but some buffer within was GPU-modified,
|
||||||
|
// fall back to ObtainBuffer to create a full buffer and avoid losing GPU modifications.
|
||||||
|
// This is only done if the request prefers to use GPU memory, otherwise we can skip it.
|
||||||
|
if (prefer_gpu && memory_tracker.IsRegionGpuModified(gpu_addr, size)) {
|
||||||
|
return ObtainBuffer(gpu_addr, size, false, false);
|
||||||
|
}
|
||||||
|
// In all other cases, just do a CPU copy to the staging buffer.
|
||||||
const u32 offset = staging_buffer.Copy(gpu_addr, size, 16);
|
const u32 offset = staging_buffer.Copy(gpu_addr, size, 16);
|
||||||
return {&staging_buffer, offset};
|
return {&staging_buffer, offset};
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,8 @@ public:
|
||||||
BufferId buffer_id = {});
|
BufferId buffer_id = {});
|
||||||
|
|
||||||
/// Attempts to obtain a buffer without modifying the cache contents.
|
/// Attempts to obtain a buffer without modifying the cache contents.
|
||||||
[[nodiscard]] std::pair<Buffer*, u32> ObtainViewBuffer(VAddr gpu_addr, u32 size);
|
[[nodiscard]] std::pair<Buffer*, u32> ObtainViewBuffer(VAddr gpu_addr, u32 size,
|
||||||
|
bool prefer_gpu);
|
||||||
|
|
||||||
/// Return true when a region is registered on the cache
|
/// Return true when a region is registered on the cache
|
||||||
[[nodiscard]] bool IsRegionRegistered(VAddr addr, size_t size);
|
[[nodiscard]] bool IsRegionRegistered(VAddr addr, size_t size);
|
||||||
|
|
|
@ -466,6 +466,9 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
|
||||||
const auto& num_mips = image.info.resources.levels;
|
const auto& num_mips = image.info.resources.levels;
|
||||||
ASSERT(num_mips == image.info.mips_layout.size());
|
ASSERT(num_mips == image.info.mips_layout.size());
|
||||||
|
|
||||||
|
const bool is_gpu_modified = True(image.flags & ImageFlagBits::GpuModified);
|
||||||
|
const bool is_gpu_dirty = True(image.flags & ImageFlagBits::GpuDirty);
|
||||||
|
|
||||||
boost::container::small_vector<vk::BufferImageCopy, 14> image_copy{};
|
boost::container::small_vector<vk::BufferImageCopy, 14> image_copy{};
|
||||||
for (u32 m = 0; m < num_mips; m++) {
|
for (u32 m = 0; m < num_mips; m++) {
|
||||||
const u32 width = std::max(image.info.size.width >> m, 1u);
|
const u32 width = std::max(image.info.size.width >> m, 1u);
|
||||||
|
@ -475,8 +478,6 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
|
||||||
const auto& mip = image.info.mips_layout[m];
|
const auto& mip = image.info.mips_layout[m];
|
||||||
|
|
||||||
// Protect GPU modified resources from accidental CPU reuploads.
|
// Protect GPU modified resources from accidental CPU reuploads.
|
||||||
const bool is_gpu_modified = True(image.flags & ImageFlagBits::GpuModified);
|
|
||||||
const bool is_gpu_dirty = True(image.flags & ImageFlagBits::GpuDirty);
|
|
||||||
if (is_gpu_modified && !is_gpu_dirty) {
|
if (is_gpu_modified && !is_gpu_dirty) {
|
||||||
const u8* addr = std::bit_cast<u8*>(image.info.guest_address);
|
const u8* addr = std::bit_cast<u8*>(image.info.guest_address);
|
||||||
const u64 hash = XXH3_64bits(addr + mip.offset, mip.size);
|
const u64 hash = XXH3_64bits(addr + mip.offset, mip.size);
|
||||||
|
@ -515,7 +516,8 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
|
||||||
|
|
||||||
const VAddr image_addr = image.info.guest_address;
|
const VAddr image_addr = image.info.guest_address;
|
||||||
const size_t image_size = image.info.guest_size_bytes;
|
const size_t image_size = image.info.guest_size_bytes;
|
||||||
const auto [vk_buffer, buf_offset] = buffer_cache.ObtainViewBuffer(image_addr, image_size);
|
const auto [vk_buffer, buf_offset] =
|
||||||
|
buffer_cache.ObtainViewBuffer(image_addr, image_size, is_gpu_dirty);
|
||||||
// The obtained buffer may be written by a shader so we need to emit a barrier to prevent RAW
|
// The obtained buffer may be written by a shader so we need to emit a barrier to prevent RAW
|
||||||
// hazard
|
// hazard
|
||||||
if (auto barrier = vk_buffer->GetBarrier(vk::AccessFlagBits2::eTransferRead,
|
if (auto barrier = vk_buffer->GetBarrier(vk::AccessFlagBits2::eTransferRead,
|
||||||
|
|
Loading…
Reference in a new issue