mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2025-06-20 03:28:17 -05:00
Query Cache: address issues
This commit is contained in:
@ -7,21 +7,19 @@
|
||||
#include <deque>
|
||||
#include <utility>
|
||||
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace VideoCommon {
|
||||
|
||||
class BankBase {
|
||||
protected:
|
||||
const size_t base_bank_size;
|
||||
size_t bank_size;
|
||||
std::atomic<size_t> references;
|
||||
size_t current_slot;
|
||||
const size_t base_bank_size{};
|
||||
size_t bank_size{};
|
||||
std::atomic<size_t> references{};
|
||||
size_t current_slot{};
|
||||
|
||||
public:
|
||||
BankBase(size_t bank_size_)
|
||||
: base_bank_size{bank_size_}, bank_size(bank_size_), references(0), current_slot(0) {}
|
||||
explicit BankBase(size_t bank_size_) : base_bank_size{bank_size_}, bank_size(bank_size_) {}
|
||||
|
||||
virtual ~BankBase() = default;
|
||||
|
||||
@ -58,11 +56,11 @@ public:
|
||||
bank_size = current_slot;
|
||||
}
|
||||
|
||||
constexpr bool IsClosed() {
|
||||
bool IsClosed() const {
|
||||
return current_slot >= bank_size;
|
||||
}
|
||||
|
||||
bool IsDead() {
|
||||
bool IsDead() const {
|
||||
return IsClosed() && references == 0;
|
||||
}
|
||||
};
|
||||
|
@ -9,28 +9,28 @@
|
||||
namespace VideoCommon {
|
||||
|
||||
enum class QueryFlagBits : u32 {
|
||||
HasTimestamp = 1 << 0, ///< Indicates if this query has a tiemstamp.
|
||||
IsFinalValueSynced = 1 << 1, ///< Indicates if the query has been synced in the host
|
||||
IsHostSynced = 1 << 2, ///< Indicates if the query has been synced in the host
|
||||
IsGuestSynced = 1 << 3, ///< Indicates if the query has been synced with the guest.
|
||||
IsHostManaged = 1 << 4, ///< Indicates if this query points to a host query
|
||||
IsRewritten = 1 << 5, ///< Indicates if this query was rewritten by another query
|
||||
IsInvalidated = 1 << 6, ///< Indicates the value of th query has been nullified.
|
||||
IsOrphan = 1 << 7, ///< Indicates the query has not been set by a guest query.
|
||||
IsFence = 1 << 8, ///< Indicates the query is a fence.
|
||||
IsQueuedForAsyncFlush = 1 <<9,///< Indicates that the query can be flushed at any moment
|
||||
HasTimestamp = 1 << 0, ///< Indicates if this query has a timestamp.
|
||||
IsFinalValueSynced = 1 << 1, ///< Indicates if the query has been synced in the host
|
||||
IsHostSynced = 1 << 2, ///< Indicates if the query has been synced in the host
|
||||
IsGuestSynced = 1 << 3, ///< Indicates if the query has been synced with the guest.
|
||||
IsHostManaged = 1 << 4, ///< Indicates if this query points to a host query
|
||||
IsRewritten = 1 << 5, ///< Indicates if this query was rewritten by another query
|
||||
IsInvalidated = 1 << 6, ///< Indicates the value of th query has been nullified.
|
||||
IsOrphan = 1 << 7, ///< Indicates the query has not been set by a guest query.
|
||||
IsFence = 1 << 8, ///< Indicates the query is a fence.
|
||||
IsQueuedForAsyncFlush = 1 << 9, ///< Indicates that the query can be flushed at any moment
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(QueryFlagBits)
|
||||
|
||||
class QueryBase {
|
||||
public:
|
||||
VAddr guest_address;
|
||||
QueryFlagBits flags;
|
||||
u64 value;
|
||||
VAddr guest_address{};
|
||||
QueryFlagBits flags{};
|
||||
u64 value{};
|
||||
|
||||
protected:
|
||||
// Default constructor
|
||||
QueryBase() : guest_address(0), flags{}, value{} {}
|
||||
QueryBase() = default;
|
||||
|
||||
// Parameterized constructor
|
||||
QueryBase(VAddr address, QueryFlagBits flags_, u64 value_)
|
||||
@ -51,23 +51,21 @@ public:
|
||||
class HostQueryBase : public QueryBase {
|
||||
public:
|
||||
// Default constructor
|
||||
HostQueryBase()
|
||||
: QueryBase(0, QueryFlagBits::IsHostManaged | QueryFlagBits::IsOrphan, 0), start_bank_id{},
|
||||
size_banks{}, start_slot{}, size_slots{} {}
|
||||
HostQueryBase() : QueryBase(0, QueryFlagBits::IsHostManaged | QueryFlagBits::IsOrphan, 0) {}
|
||||
|
||||
// Parameterized constructor
|
||||
HostQueryBase(bool isLong, VAddr address)
|
||||
HostQueryBase(bool has_timestamp, VAddr address)
|
||||
: QueryBase(address, QueryFlagBits::IsHostManaged, 0), start_bank_id{}, size_banks{},
|
||||
start_slot{}, size_slots{} {
|
||||
if (isLong) {
|
||||
if (has_timestamp) {
|
||||
flags |= QueryFlagBits::HasTimestamp;
|
||||
}
|
||||
}
|
||||
|
||||
u32 start_bank_id;
|
||||
u32 size_banks;
|
||||
size_t start_slot;
|
||||
size_t size_slots;
|
||||
u32 start_bank_id{};
|
||||
u32 size_banks{};
|
||||
size_t start_slot{};
|
||||
size_t size_slots{};
|
||||
};
|
||||
|
||||
} // namespace VideoCommon
|
@ -54,7 +54,7 @@ public:
|
||||
return new_id;
|
||||
}
|
||||
|
||||
bool HasPendingSync() override {
|
||||
bool HasPendingSync() const override {
|
||||
return !pending_sync.empty();
|
||||
}
|
||||
|
||||
@ -71,8 +71,10 @@ public:
|
||||
continue;
|
||||
}
|
||||
query.flags |= QueryFlagBits::IsHostSynced;
|
||||
sync_values.emplace_back(query.guest_address, query.value,
|
||||
True(query.flags & QueryFlagBits::HasTimestamp) ? 8 : 4);
|
||||
sync_values.emplace_back(SyncValuesStruct{
|
||||
.address = query.guest_address,
|
||||
.value = query.value,
|
||||
.size = static_cast<u64>(True(query.flags & QueryFlagBits::HasTimestamp) ? 8 : 4)});
|
||||
}
|
||||
pending_sync.clear();
|
||||
if (sync_values.size() > 0) {
|
||||
@ -90,15 +92,20 @@ class StubStreamer : public GuestStreamer<Traits> {
|
||||
public:
|
||||
using RuntimeType = typename Traits::RuntimeType;
|
||||
|
||||
StubStreamer(size_t id_, RuntimeType& runtime_) : GuestStreamer<Traits>(id_, runtime_) {}
|
||||
StubStreamer(size_t id_, RuntimeType& runtime_, u32 stub_value_)
|
||||
: GuestStreamer<Traits>(id_, runtime_), stub_value{stub_value_} {}
|
||||
|
||||
~StubStreamer() override = default;
|
||||
|
||||
size_t WriteCounter(VAddr address, bool has_timestamp, [[maybe_unused]] u32 value,
|
||||
std::optional<u32> subreport = std::nullopt) override {
|
||||
size_t new_id = GuestStreamer<Traits>::WriteCounter(address, has_timestamp, 1U, subreport);
|
||||
size_t new_id =
|
||||
GuestStreamer<Traits>::WriteCounter(address, has_timestamp, stub_value, subreport);
|
||||
return new_id;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 stub_value;
|
||||
};
|
||||
|
||||
template <typename Traits>
|
||||
@ -113,7 +120,7 @@ struct QueryCacheBase<Traits>::QueryCacheBaseImpl {
|
||||
for (size_t i = 0; i < static_cast<size_t>(QueryType::MaxQueryTypes); i++) {
|
||||
streamers[i] = runtime.GetStreamerInterface(static_cast<QueryType>(i));
|
||||
if (streamers[i]) {
|
||||
streamer_mask |= 1ULL << i;
|
||||
streamer_mask |= 1ULL << streamers[i]->GetId();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -152,7 +159,7 @@ struct QueryCacheBase<Traits>::QueryCacheBaseImpl {
|
||||
QueryCacheBase<Traits>* owner;
|
||||
VideoCore::RasterizerInterface& rasterizer;
|
||||
Core::Memory::Memory& cpu_memory;
|
||||
Traits::RuntimeType& runtime;
|
||||
RuntimeType& runtime;
|
||||
Tegra::GPU& gpu;
|
||||
std::array<StreamerInterface*, static_cast<size_t>(QueryType::MaxQueryTypes)> streamers;
|
||||
u64 streamer_mask;
|
||||
@ -223,15 +230,11 @@ void QueryCacheBase<Traits>::CounterReport(GPUVAddr addr, QueryType counter_type
|
||||
const bool is_fence = True(flags & QueryPropertiesFlags::IsAFence);
|
||||
size_t streamer_id = static_cast<size_t>(counter_type);
|
||||
auto* streamer = impl->streamers[streamer_id];
|
||||
if (!streamer) [[unlikely]] {
|
||||
if (has_timestamp) {
|
||||
u64 timestamp = impl->gpu.GetTicks();
|
||||
gpu_memory->Write<u64>(addr + 8, timestamp);
|
||||
gpu_memory->Write<u64>(addr, 1ULL);
|
||||
} else {
|
||||
gpu_memory->Write<u32>(addr, 1U);
|
||||
}
|
||||
return;
|
||||
if (streamer == nullptr) [[unlikely]] {
|
||||
counter_type = QueryType::Payload;
|
||||
payload = 1U;
|
||||
streamer_id = static_cast<size_t>(counter_type);
|
||||
streamer = impl->streamers[streamer_id];
|
||||
}
|
||||
auto cpu_addr_opt = gpu_memory->GpuToCpuAddress(addr);
|
||||
if (!cpu_addr_opt) [[unlikely]] {
|
||||
@ -403,12 +406,6 @@ bool QueryCacheBase<Traits>::AccelerateHostConditionalRendering() {
|
||||
impl->runtime.EndHostConditionalRendering();
|
||||
return false;
|
||||
}
|
||||
/*if (!Settings::IsGPULevelHigh()) {
|
||||
impl->runtime.EndHostConditionalRendering();
|
||||
return gpu_memory->IsMemoryDirty(regs.render_enable.Address(), 24,
|
||||
VideoCommon::CacheType::BufferCache |
|
||||
VideoCommon::CacheType::QueryCache);
|
||||
}*/
|
||||
const ComparisonMode mode = static_cast<ComparisonMode>(regs.render_enable.mode);
|
||||
const GPUVAddr address = regs.render_enable.Address();
|
||||
switch (mode) {
|
||||
@ -442,6 +439,9 @@ bool QueryCacheBase<Traits>::AccelerateHostConditionalRendering() {
|
||||
// Async downloads
|
||||
template <typename Traits>
|
||||
void QueryCacheBase<Traits>::CommitAsyncFlushes() {
|
||||
// Make sure to have the results synced in Host.
|
||||
NotifyWFI();
|
||||
|
||||
u64 mask{};
|
||||
{
|
||||
std::scoped_lock lk(impl->flush_guard);
|
||||
@ -458,8 +458,19 @@ void QueryCacheBase<Traits>::CommitAsyncFlushes() {
|
||||
if (mask == 0) {
|
||||
return;
|
||||
}
|
||||
impl->ForEachStreamerIn(mask,
|
||||
[](StreamerInterface* streamer) { streamer->PushUnsyncedQueries(); });
|
||||
u64 ran_mask = ~mask;
|
||||
while (mask) {
|
||||
impl->ForEachStreamerIn(mask, [&mask, &ran_mask](StreamerInterface* streamer) {
|
||||
u64 dep_mask = streamer->GetDependentMask();
|
||||
if ((dep_mask & ~ran_mask) != 0) {
|
||||
return;
|
||||
}
|
||||
u64 index = streamer->GetId();
|
||||
ran_mask |= (1ULL << index);
|
||||
mask &= ~(1ULL << index);
|
||||
streamer->PushUnsyncedQueries();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
@ -489,13 +500,11 @@ void QueryCacheBase<Traits>::PopAsyncFlushes() {
|
||||
if (mask == 0) {
|
||||
return;
|
||||
}
|
||||
u64 ran_mask = 0;
|
||||
u64 next_phase = 0;
|
||||
u64 ran_mask = ~mask;
|
||||
while (mask) {
|
||||
impl->ForEachStreamerIn(mask, [&mask, &ran_mask, &next_phase](StreamerInterface* streamer) {
|
||||
impl->ForEachStreamerIn(mask, [&mask, &ran_mask](StreamerInterface* streamer) {
|
||||
u64 dep_mask = streamer->GetDependenceMask();
|
||||
if ((dep_mask & ~ran_mask) != 0) {
|
||||
next_phase |= dep_mask;
|
||||
return;
|
||||
}
|
||||
u64 index = streamer->GetId();
|
||||
@ -503,7 +512,6 @@ void QueryCacheBase<Traits>::PopAsyncFlushes() {
|
||||
mask &= ~(1ULL << index);
|
||||
streamer->PopUnsyncedQueries();
|
||||
});
|
||||
ran_mask |= next_phase;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
BitField<0, 27, u32> query_id;
|
||||
u32 raw;
|
||||
|
||||
std::pair<size_t, size_t> unpack() {
|
||||
std::pair<size_t, size_t> unpack() const {
|
||||
return {static_cast<size_t>(stream_id.Value()), static_cast<size_t>(query_id.Value())};
|
||||
}
|
||||
};
|
||||
@ -73,7 +73,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
static u64 BuildMask(std::span<QueryType> types) {
|
||||
static u64 BuildMask(std::span<const QueryType> types) {
|
||||
u64 mask = 0;
|
||||
for (auto query_type : types) {
|
||||
mask |= 1ULL << (static_cast<u64>(query_type));
|
||||
@ -160,7 +160,7 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
using ContentCache = typename std::unordered_map<u64, std::unordered_map<u32, QueryLocation>>;
|
||||
using ContentCache = std::unordered_map<u64, std::unordered_map<u32, QueryLocation>>;
|
||||
|
||||
void InvalidateQuery(QueryLocation location);
|
||||
bool IsQueryDirty(QueryLocation location);
|
||||
@ -175,7 +175,7 @@ protected:
|
||||
friend struct QueryCacheBaseImpl;
|
||||
friend RuntimeType;
|
||||
|
||||
std::unique_ptr<struct QueryCacheBaseImpl> impl;
|
||||
std::unique_ptr<QueryCacheBaseImpl> impl;
|
||||
};
|
||||
|
||||
} // namespace VideoCommon
|
@ -16,7 +16,7 @@ namespace VideoCommon {
|
||||
|
||||
class StreamerInterface {
|
||||
public:
|
||||
StreamerInterface(size_t id_, u64 dependance_mask_ = 0) : id{id_}, dependance_mask{dependance_mask_} {}
|
||||
explicit StreamerInterface(size_t id_) : id{id_}, dependence_mask{}, dependent_mask{} {}
|
||||
virtual ~StreamerInterface() = default;
|
||||
|
||||
virtual QueryBase* GetQuery(size_t id) = 0;
|
||||
@ -37,7 +37,7 @@ public:
|
||||
/* Do Nothing */
|
||||
}
|
||||
|
||||
virtual bool HasPendingSync() {
|
||||
virtual bool HasPendingSync() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ public:
|
||||
virtual size_t WriteCounter(VAddr address, bool has_timestamp, u32 value,
|
||||
std::optional<u32> subreport = std::nullopt) = 0;
|
||||
|
||||
virtual bool HasUnsyncedQueries() {
|
||||
virtual bool HasUnsyncedQueries() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -71,18 +71,28 @@ public:
|
||||
}
|
||||
|
||||
u64 GetDependenceMask() const {
|
||||
return dependance_mask;
|
||||
return dependence_mask;
|
||||
}
|
||||
|
||||
u64 GetDependentMask() const {
|
||||
return dependence_mask;
|
||||
}
|
||||
|
||||
protected:
|
||||
void MakeDependent(StreamerInterface* depend_on) {
|
||||
dependence_mask |= 1ULL << depend_on->id;
|
||||
depend_on->dependent_mask |= 1ULL << id;
|
||||
}
|
||||
|
||||
const size_t id;
|
||||
const u64 dependance_mask;
|
||||
u64 dependence_mask;
|
||||
u64 dependent_mask;
|
||||
};
|
||||
|
||||
template <typename QueryType>
|
||||
class SimpleStreamer : public StreamerInterface {
|
||||
public:
|
||||
SimpleStreamer(size_t id_, u64 dependance_mask_ = 0) : StreamerInterface{id_, dependance_mask_} {}
|
||||
explicit SimpleStreamer(size_t id_) : StreamerInterface{id_} {}
|
||||
virtual ~SimpleStreamer() = default;
|
||||
|
||||
protected:
|
||||
|
Reference in New Issue
Block a user