mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-07-23 10:35:03 +00:00
Fix segfault with clear mask
This commit is contained in:
parent
a6cdf2eac7
commit
2849e970cb
@ -3,23 +3,43 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
template <class Func>
|
template <class Func, class Enable = void>
|
||||||
struct FuncTraits {};
|
struct FuncTraits;
|
||||||
|
|
||||||
|
// Function type
|
||||||
template <class ReturnType_, class... Args>
|
template <class ReturnType_, class... Args>
|
||||||
struct FuncTraits<ReturnType_ (*)(Args...)> {
|
struct FuncTraits<ReturnType_(Args...), void> {
|
||||||
using ReturnType = ReturnType_;
|
using ReturnType = ReturnType_;
|
||||||
|
|
||||||
static constexpr size_t NUM_ARGS = sizeof...(Args);
|
static constexpr size_t NUM_ARGS = sizeof...(Args);
|
||||||
|
|
||||||
template <size_t I>
|
template <size_t I>
|
||||||
using ArgType = std::tuple_element_t<I, std::tuple<Args...>>;
|
using ArgType = std::tuple_element_t<I, std::tuple<Args...>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Function pointer
|
||||||
|
template <class ReturnType_, class... Args>
|
||||||
|
struct FuncTraits<ReturnType_ (*)(Args...), void> : FuncTraits<ReturnType_(Args...)> {};
|
||||||
|
|
||||||
|
// Member function pointer
|
||||||
|
template <class ClassType, class ReturnType_, class... Args>
|
||||||
|
struct FuncTraits<ReturnType_ (ClassType::*)(Args...), void> : FuncTraits<ReturnType_(Args...)> {};
|
||||||
|
|
||||||
|
template <class ClassType, class ReturnType_, class... Args>
|
||||||
|
struct FuncTraits<ReturnType_ (ClassType::*)(Args...) const, void>
|
||||||
|
: FuncTraits<ReturnType_(Args...)> {};
|
||||||
|
|
||||||
|
// Catch-all for callables
|
||||||
|
template <class Func>
|
||||||
|
struct FuncTraits<Func, std::void_t<decltype(&std::remove_reference_t<Func>::operator())>>
|
||||||
|
: FuncTraits<decltype(&std::remove_reference_t<Func>::operator())> {};
|
||||||
|
|
||||||
|
|
||||||
|
// For lambdas: for compat (may be removed)
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
struct LambdaTraits : LambdaTraits<decltype(&std::remove_reference_t<Func>::operator())> {};
|
struct LambdaTraits : LambdaTraits<decltype(&std::remove_reference_t<Func>::operator())> {};
|
||||||
|
|
||||||
|
@ -1064,8 +1064,11 @@ void BufferCache::SynchronizeBuffersForDma() {
|
|||||||
copies.clear();
|
copies.clear();
|
||||||
};
|
};
|
||||||
mapped_ranges.ForEach([&](VAddr device_addr, u64 size) {
|
mapped_ranges.ForEach([&](VAddr device_addr, u64 size) {
|
||||||
memory_tracker->ForEachUploadRange(device_addr, size, false, [&](u64 device_addr_out, u64 range_size) {
|
RENDERER_TRACE;
|
||||||
|
memory_tracker->ForEachUploadRange(device_addr, size, false, [&](u64 device_addr_out, u64 range_size, RegionBits& clear_mask) {
|
||||||
|
RENDERER_TRACE;
|
||||||
ForEachBufferInRange(device_addr_out, range_size, [&](BufferId buffer_id, Buffer& buffer) {
|
ForEachBufferInRange(device_addr_out, range_size, [&](BufferId buffer_id, Buffer& buffer) {
|
||||||
|
RENDERER_TRACE;
|
||||||
if (last_buffer_id != buffer_id) {
|
if (last_buffer_id != buffer_id) {
|
||||||
upload_pending();
|
upload_pending();
|
||||||
last_buffer_id = buffer_id;
|
last_buffer_id = buffer_id;
|
||||||
@ -1082,6 +1085,14 @@ void BufferCache::SynchronizeBuffersForDma() {
|
|||||||
.dstOffset = copy_start - buffer.CpuAddr(),
|
.dstOffset = copy_start - buffer.CpuAddr(),
|
||||||
.size = copy_size,
|
.size = copy_size,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// We need to use tracker page size here, we are marking the clear mask
|
||||||
|
const u64 page_start = (copy_start & TRACKER_HIGHER_PAGE_MASK) >> TRACKER_PAGE_BITS;
|
||||||
|
const u64 page_end =
|
||||||
|
Common::DivCeil((copy_end - 1) & TRACKER_HIGHER_PAGE_MASK, TRACKER_BYTES_PER_PAGE);
|
||||||
|
ASSERT(page_start < page_end);
|
||||||
|
LOG_WARNING(Render_Vulkan, "Page start {:#x}, end {:#x}", page_start, page_end);
|
||||||
|
clear_mask.SetRange(page_start, page_end);
|
||||||
});
|
});
|
||||||
}, upload_pending);
|
}, upload_pending);
|
||||||
});
|
});
|
||||||
|
@ -18,11 +18,10 @@ constexpr u64 TRACKER_HIGHER_PAGE_MASK = TRACKER_HIGHER_PAGE_SIZE - 1ULL;
|
|||||||
constexpr u64 NUM_PAGES_PER_REGION = TRACKER_HIGHER_PAGE_SIZE / TRACKER_BYTES_PER_PAGE;
|
constexpr u64 NUM_PAGES_PER_REGION = TRACKER_HIGHER_PAGE_SIZE / TRACKER_BYTES_PER_PAGE;
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
None = 0,
|
None,
|
||||||
CPU = 1 << 0,
|
CPU,
|
||||||
GPU = 1 << 1,
|
GPU,
|
||||||
};
|
};
|
||||||
DECLARE_ENUM_FLAG_OPERATORS(Type)
|
|
||||||
|
|
||||||
|
|
||||||
using RegionBits = Common::BitArray<NUM_PAGES_PER_REGION>;
|
using RegionBits = Common::BitArray<NUM_PAGES_PER_REGION>;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
#include "common/div_ceil.h"
|
#include "common/div_ceil.h"
|
||||||
|
#include "common/func_traits.h"
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include "common/adaptive_mutex.h"
|
#include "common/adaptive_mutex.h"
|
||||||
@ -69,20 +70,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <Type type, bool enable>
|
|
||||||
void PerformDeferredProtections() {
|
|
||||||
bool was_deferred = True(deferred_protection & type);
|
|
||||||
if (!was_deferred) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
deferred_protection &= ~type;
|
|
||||||
if constexpr (type == Type::CPU) {
|
|
||||||
UpdateProtection<!enable, false>();
|
|
||||||
} else if constexpr (type == Type::GPU) {
|
|
||||||
UpdateProtection<enable, true>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the state of a range of pages
|
* Change the state of a range of pages
|
||||||
*
|
*
|
||||||
@ -121,9 +108,11 @@ public:
|
|||||||
* @param size Size in bytes of the CPU range to loop over
|
* @param size Size in bytes of the CPU range to loop over
|
||||||
* @param func Function to call for each turned off region
|
* @param func Function to call for each turned off region
|
||||||
*/
|
*/
|
||||||
template <Type type, bool clear>
|
template <Type type, bool clear, typename F>
|
||||||
void ForEachModifiedRange(VAddr query_cpu_range, s64 size, auto&& func) {
|
void ForEachModifiedRange(VAddr query_cpu_range, s64 size, F&& func) {
|
||||||
RENDERER_TRACE;
|
RENDERER_TRACE;
|
||||||
|
using FuncTraits = Common::FuncTraits<F>;
|
||||||
|
constexpr bool uses_clear_mask = FuncTraits::NUM_ARGS == 3;
|
||||||
const size_t offset = query_cpu_range - cpu_addr;
|
const size_t offset = query_cpu_range - cpu_addr;
|
||||||
const size_t start_page = SanitizeAddress(offset) / TRACKER_BYTES_PER_PAGE;
|
const size_t start_page = SanitizeAddress(offset) / TRACKER_BYTES_PER_PAGE;
|
||||||
const size_t end_page =
|
const size_t end_page =
|
||||||
@ -135,18 +124,31 @@ public:
|
|||||||
RegionBits& bits = GetRegionBits<type>();
|
RegionBits& bits = GetRegionBits<type>();
|
||||||
RegionBits mask(bits, start_page, end_page);
|
RegionBits mask(bits, start_page, end_page);
|
||||||
|
|
||||||
|
if constexpr (uses_clear_mask) {
|
||||||
|
static_assert(clear, "Function must not use clear mask when not clearing");
|
||||||
|
RegionBits clear_mask;
|
||||||
|
for (const auto& [start, end] : mask) {
|
||||||
|
func(cpu_addr + start * TRACKER_BYTES_PER_PAGE,
|
||||||
|
(end - start) * TRACKER_BYTES_PER_PAGE, clear_mask);
|
||||||
|
}
|
||||||
|
bits &= ~clear_mask;
|
||||||
|
} else {
|
||||||
|
for (const auto& [start, end] : mask) {
|
||||||
|
func(cpu_addr + start * TRACKER_BYTES_PER_PAGE,
|
||||||
|
(end - start) * TRACKER_BYTES_PER_PAGE);
|
||||||
|
}
|
||||||
|
if constexpr (clear) {
|
||||||
|
bits &= ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if constexpr (clear) {
|
if constexpr (clear) {
|
||||||
bits.UnsetRange(start_page, end_page);
|
|
||||||
if constexpr (type == Type::CPU) {
|
if constexpr (type == Type::CPU) {
|
||||||
UpdateProtection<true, false>();
|
UpdateProtection<true, false>();
|
||||||
} else if (Config::readbacks()) {
|
} else if (Config::readbacks()) {
|
||||||
UpdateProtection<false, true>();
|
UpdateProtection<false, true>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& [start, end] : mask) {
|
|
||||||
func(cpu_addr + start * TRACKER_BYTES_PER_PAGE, (end - start) * TRACKER_BYTES_PER_PAGE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user