summaryrefslogtreecommitdiffstats
path: root/src/video_core/query_cache
diff options
context:
space:
mode:
authorFernando Sahmkow <fsahmkow27@gmail.com>2023-08-06 09:38:16 +0200
committerFernando Sahmkow <fsahmkow27@gmail.com>2023-09-23 23:05:30 +0200
commit282ae8fa51e060e6d4ef026b734aa871b1b9331e (patch)
tree3bc4603b6add0582315dc65544f1986427e4182d /src/video_core/query_cache
parentQueryCache: Implement dependant queries. (diff)
downloadyuzu-282ae8fa51e060e6d4ef026b734aa871b1b9331e.tar
yuzu-282ae8fa51e060e6d4ef026b734aa871b1b9331e.tar.gz
yuzu-282ae8fa51e060e6d4ef026b734aa871b1b9331e.tar.bz2
yuzu-282ae8fa51e060e6d4ef026b734aa871b1b9331e.tar.lz
yuzu-282ae8fa51e060e6d4ef026b734aa871b1b9331e.tar.xz
yuzu-282ae8fa51e060e6d4ef026b734aa871b1b9331e.tar.zst
yuzu-282ae8fa51e060e6d4ef026b734aa871b1b9331e.zip
Diffstat (limited to 'src/video_core/query_cache')
-rw-r--r--src/video_core/query_cache/bank_base.h16
-rw-r--r--src/video_core/query_cache/query_base.h44
-rw-r--r--src/video_core/query_cache/query_cache.h66
-rw-r--r--src/video_core/query_cache/query_cache_base.h8
-rw-r--r--src/video_core/query_cache/query_stream.h22
5 files changed, 85 insertions, 71 deletions
diff --git a/src/video_core/query_cache/bank_base.h b/src/video_core/query_cache/bank_base.h
index 4246a609d..420927091 100644
--- a/src/video_core/query_cache/bank_base.h
+++ b/src/video_core/query_cache/bank_base.h
@@ -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;
}
};
diff --git a/src/video_core/query_cache/query_base.h b/src/video_core/query_cache/query_base.h
index 0ae23af9f..993a13eac 100644
--- a/src/video_core/query_cache/query_base.h
+++ b/src/video_core/query_cache/query_base.h
@@ -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 \ No newline at end of file
diff --git a/src/video_core/query_cache/query_cache.h b/src/video_core/query_cache/query_cache.h
index f1393d5c7..042af053c 100644
--- a/src/video_core/query_cache/query_cache.h
+++ b/src/video_core/query_cache/query_cache.h
@@ -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;
}
}
diff --git a/src/video_core/query_cache/query_cache_base.h b/src/video_core/query_cache/query_cache_base.h
index 55f508dd1..07be421c6 100644
--- a/src/video_core/query_cache/query_cache_base.h
+++ b/src/video_core/query_cache/query_cache_base.h
@@ -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 \ No newline at end of file
diff --git a/src/video_core/query_cache/query_stream.h b/src/video_core/query_cache/query_stream.h
index 0e9275565..e7aac955b 100644
--- a/src/video_core/query_cache/query_stream.h
+++ b/src/video_core/query_cache/query_stream.h
@@ -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: