Compare commits
2 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b143ce8134 | ||
|
|
2afaa7aed7 |
631
src/common/intrusive_list.h
Normal file
631
src/common/intrusive_list.h
Normal file
@@ -0,0 +1,631 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/parent_of_member.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
// Forward declare implementation class for Node.
|
||||
namespace impl {
|
||||
|
||||
class IntrusiveListImpl;
|
||||
|
||||
}
|
||||
|
||||
class IntrusiveListNode {
|
||||
YUZU_NON_COPYABLE(IntrusiveListNode);
|
||||
|
||||
private:
|
||||
friend class impl::IntrusiveListImpl;
|
||||
|
||||
IntrusiveListNode* m_prev;
|
||||
IntrusiveListNode* m_next;
|
||||
|
||||
public:
|
||||
constexpr IntrusiveListNode() : m_prev(this), m_next(this) {}
|
||||
|
||||
constexpr bool IsLinked() const {
|
||||
return m_next != this;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr void LinkPrev(IntrusiveListNode* node) {
|
||||
// We can't link an already linked node.
|
||||
ASSERT(!node->IsLinked());
|
||||
this->SplicePrev(node, node);
|
||||
}
|
||||
|
||||
constexpr void SplicePrev(IntrusiveListNode* first, IntrusiveListNode* last) {
|
||||
// Splice a range into the list.
|
||||
auto last_prev = last->m_prev;
|
||||
first->m_prev = m_prev;
|
||||
last_prev->m_next = this;
|
||||
m_prev->m_next = first;
|
||||
m_prev = last_prev;
|
||||
}
|
||||
|
||||
constexpr void LinkNext(IntrusiveListNode* node) {
|
||||
// We can't link an already linked node.
|
||||
ASSERT(!node->IsLinked());
|
||||
return this->SpliceNext(node, node);
|
||||
}
|
||||
|
||||
constexpr void SpliceNext(IntrusiveListNode* first, IntrusiveListNode* last) {
|
||||
// Splice a range into the list.
|
||||
auto last_prev = last->m_prev;
|
||||
first->m_prev = this;
|
||||
last_prev->m_next = m_next;
|
||||
m_next->m_prev = last_prev;
|
||||
m_next = first;
|
||||
}
|
||||
|
||||
constexpr void Unlink() {
|
||||
this->Unlink(m_next);
|
||||
}
|
||||
|
||||
constexpr void Unlink(IntrusiveListNode* last) {
|
||||
// Unlink a node from a next node.
|
||||
auto last_prev = last->m_prev;
|
||||
m_prev->m_next = last;
|
||||
last->m_prev = m_prev;
|
||||
last_prev->m_next = this;
|
||||
m_prev = last_prev;
|
||||
}
|
||||
|
||||
constexpr IntrusiveListNode* GetPrev() {
|
||||
return m_prev;
|
||||
}
|
||||
|
||||
constexpr const IntrusiveListNode* GetPrev() const {
|
||||
return m_prev;
|
||||
}
|
||||
|
||||
constexpr IntrusiveListNode* GetNext() {
|
||||
return m_next;
|
||||
}
|
||||
|
||||
constexpr const IntrusiveListNode* GetNext() const {
|
||||
return m_next;
|
||||
}
|
||||
};
|
||||
// DEPRECATED: static_assert(std::is_literal_type<IntrusiveListNode>::value);
|
||||
|
||||
namespace impl {
|
||||
|
||||
class IntrusiveListImpl {
|
||||
YUZU_NON_COPYABLE(IntrusiveListImpl);
|
||||
|
||||
private:
|
||||
IntrusiveListNode m_root_node;
|
||||
|
||||
public:
|
||||
template <bool Const>
|
||||
class Iterator;
|
||||
|
||||
using value_type = IntrusiveListNode;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using iterator = Iterator<false>;
|
||||
using const_iterator = Iterator<true>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
template <bool Const>
|
||||
class Iterator {
|
||||
public:
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = typename IntrusiveListImpl::value_type;
|
||||
using difference_type = typename IntrusiveListImpl::difference_type;
|
||||
using pointer =
|
||||
std::conditional_t<Const, IntrusiveListImpl::const_pointer, IntrusiveListImpl::pointer>;
|
||||
using reference = std::conditional_t<Const, IntrusiveListImpl::const_reference,
|
||||
IntrusiveListImpl::reference>;
|
||||
|
||||
private:
|
||||
pointer m_node;
|
||||
|
||||
public:
|
||||
constexpr explicit Iterator(pointer n) : m_node(n) {}
|
||||
|
||||
constexpr bool operator==(const Iterator& rhs) const {
|
||||
return m_node == rhs.m_node;
|
||||
}
|
||||
|
||||
constexpr pointer operator->() const {
|
||||
return m_node;
|
||||
}
|
||||
|
||||
constexpr reference operator*() const {
|
||||
return *m_node;
|
||||
}
|
||||
|
||||
constexpr Iterator& operator++() {
|
||||
m_node = m_node->m_next;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Iterator& operator--() {
|
||||
m_node = m_node->m_prev;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Iterator operator++(int) {
|
||||
const Iterator it{*this};
|
||||
++(*this);
|
||||
return it;
|
||||
}
|
||||
|
||||
constexpr Iterator operator--(int) {
|
||||
const Iterator it{*this};
|
||||
--(*this);
|
||||
return it;
|
||||
}
|
||||
|
||||
constexpr operator Iterator<true>() const {
|
||||
return Iterator<true>(m_node);
|
||||
}
|
||||
|
||||
constexpr Iterator<false> GetNonConstIterator() const {
|
||||
return Iterator<false>(const_cast<IntrusiveListImpl::pointer>(m_node));
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
constexpr IntrusiveListImpl() : m_root_node() {}
|
||||
|
||||
// Iterator accessors.
|
||||
constexpr iterator begin() {
|
||||
return iterator(m_root_node.GetNext());
|
||||
}
|
||||
|
||||
constexpr const_iterator begin() const {
|
||||
return const_iterator(m_root_node.GetNext());
|
||||
}
|
||||
|
||||
constexpr iterator end() {
|
||||
return iterator(std::addressof(m_root_node));
|
||||
}
|
||||
|
||||
constexpr const_iterator end() const {
|
||||
return const_iterator(std::addressof(m_root_node));
|
||||
}
|
||||
|
||||
constexpr iterator iterator_to(reference v) {
|
||||
// Only allow iterator_to for values in lists.
|
||||
ASSERT(v.IsLinked());
|
||||
return iterator(std::addressof(v));
|
||||
}
|
||||
|
||||
constexpr const_iterator iterator_to(const_reference v) const {
|
||||
// Only allow iterator_to for values in lists.
|
||||
ASSERT(v.IsLinked());
|
||||
return const_iterator(std::addressof(v));
|
||||
}
|
||||
|
||||
// Content management.
|
||||
constexpr bool empty() const {
|
||||
return !m_root_node.IsLinked();
|
||||
}
|
||||
|
||||
constexpr size_type size() const {
|
||||
return static_cast<size_type>(std::distance(this->begin(), this->end()));
|
||||
}
|
||||
|
||||
constexpr reference back() {
|
||||
return *m_root_node.GetPrev();
|
||||
}
|
||||
|
||||
constexpr const_reference back() const {
|
||||
return *m_root_node.GetPrev();
|
||||
}
|
||||
|
||||
constexpr reference front() {
|
||||
return *m_root_node.GetNext();
|
||||
}
|
||||
|
||||
constexpr const_reference front() const {
|
||||
return *m_root_node.GetNext();
|
||||
}
|
||||
|
||||
constexpr void push_back(reference node) {
|
||||
m_root_node.LinkPrev(std::addressof(node));
|
||||
}
|
||||
|
||||
constexpr void push_front(reference node) {
|
||||
m_root_node.LinkNext(std::addressof(node));
|
||||
}
|
||||
|
||||
constexpr void pop_back() {
|
||||
m_root_node.GetPrev()->Unlink();
|
||||
}
|
||||
|
||||
constexpr void pop_front() {
|
||||
m_root_node.GetNext()->Unlink();
|
||||
}
|
||||
|
||||
constexpr iterator insert(const_iterator pos, reference node) {
|
||||
pos.GetNonConstIterator()->LinkPrev(std::addressof(node));
|
||||
return iterator(std::addressof(node));
|
||||
}
|
||||
|
||||
constexpr void splice(const_iterator pos, IntrusiveListImpl& o) {
|
||||
splice_impl(pos, o.begin(), o.end());
|
||||
}
|
||||
|
||||
constexpr void splice(const_iterator pos, IntrusiveListImpl& o, const_iterator first) {
|
||||
const_iterator last(first);
|
||||
std::advance(last, 1);
|
||||
splice_impl(pos, first, last);
|
||||
}
|
||||
|
||||
constexpr void splice(const_iterator pos, IntrusiveListImpl& o, const_iterator first,
|
||||
const_iterator last) {
|
||||
splice_impl(pos, first, last);
|
||||
}
|
||||
|
||||
constexpr iterator erase(const_iterator pos) {
|
||||
if (pos == this->end()) {
|
||||
return this->end();
|
||||
}
|
||||
iterator it(pos.GetNonConstIterator());
|
||||
(it++)->Unlink();
|
||||
return it;
|
||||
}
|
||||
|
||||
constexpr void clear() {
|
||||
while (!this->empty()) {
|
||||
this->pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr void splice_impl(const_iterator _pos, const_iterator _first, const_iterator _last) {
|
||||
if (_first == _last) {
|
||||
return;
|
||||
}
|
||||
iterator pos(_pos.GetNonConstIterator());
|
||||
iterator first(_first.GetNonConstIterator());
|
||||
iterator last(_last.GetNonConstIterator());
|
||||
first->Unlink(std::addressof(*last));
|
||||
pos->SplicePrev(std::addressof(*first), std::addressof(*first));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace impl
|
||||
|
||||
template <class T, class Traits>
|
||||
class IntrusiveList {
|
||||
YUZU_NON_COPYABLE(IntrusiveList);
|
||||
|
||||
private:
|
||||
impl::IntrusiveListImpl m_impl;
|
||||
|
||||
public:
|
||||
template <bool Const>
|
||||
class Iterator;
|
||||
|
||||
using value_type = T;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using iterator = Iterator<false>;
|
||||
using const_iterator = Iterator<true>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
template <bool Const>
|
||||
class Iterator {
|
||||
public:
|
||||
friend class Common::IntrusiveList<T, Traits>;
|
||||
|
||||
using ImplIterator =
|
||||
std::conditional_t<Const, Common::impl::IntrusiveListImpl::const_iterator,
|
||||
Common::impl::IntrusiveListImpl::iterator>;
|
||||
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = typename IntrusiveList::value_type;
|
||||
using difference_type = typename IntrusiveList::difference_type;
|
||||
using pointer =
|
||||
std::conditional_t<Const, IntrusiveList::const_pointer, IntrusiveList::pointer>;
|
||||
using reference =
|
||||
std::conditional_t<Const, IntrusiveList::const_reference, IntrusiveList::reference>;
|
||||
|
||||
private:
|
||||
ImplIterator m_iterator;
|
||||
|
||||
private:
|
||||
constexpr explicit Iterator(ImplIterator it) : m_iterator(it) {}
|
||||
|
||||
constexpr ImplIterator GetImplIterator() const {
|
||||
return m_iterator;
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr bool operator==(const Iterator& rhs) const {
|
||||
return m_iterator == rhs.m_iterator;
|
||||
}
|
||||
|
||||
constexpr pointer operator->() const {
|
||||
return std::addressof(Traits::GetParent(*m_iterator));
|
||||
}
|
||||
|
||||
constexpr reference operator*() const {
|
||||
return Traits::GetParent(*m_iterator);
|
||||
}
|
||||
|
||||
constexpr Iterator& operator++() {
|
||||
++m_iterator;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Iterator& operator--() {
|
||||
--m_iterator;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Iterator operator++(int) {
|
||||
const Iterator it{*this};
|
||||
++m_iterator;
|
||||
return it;
|
||||
}
|
||||
|
||||
constexpr Iterator operator--(int) {
|
||||
const Iterator it{*this};
|
||||
--m_iterator;
|
||||
return it;
|
||||
}
|
||||
|
||||
constexpr operator Iterator<true>() const {
|
||||
return Iterator<true>(m_iterator);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
static constexpr IntrusiveListNode& GetNode(reference ref) {
|
||||
return Traits::GetNode(ref);
|
||||
}
|
||||
|
||||
static constexpr IntrusiveListNode const& GetNode(const_reference ref) {
|
||||
return Traits::GetNode(ref);
|
||||
}
|
||||
|
||||
static constexpr reference GetParent(IntrusiveListNode& node) {
|
||||
return Traits::GetParent(node);
|
||||
}
|
||||
|
||||
static constexpr const_reference GetParent(IntrusiveListNode const& node) {
|
||||
return Traits::GetParent(node);
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr IntrusiveList() : m_impl() {}
|
||||
|
||||
// Iterator accessors.
|
||||
constexpr iterator begin() {
|
||||
return iterator(m_impl.begin());
|
||||
}
|
||||
|
||||
constexpr const_iterator begin() const {
|
||||
return const_iterator(m_impl.begin());
|
||||
}
|
||||
|
||||
constexpr iterator end() {
|
||||
return iterator(m_impl.end());
|
||||
}
|
||||
|
||||
constexpr const_iterator end() const {
|
||||
return const_iterator(m_impl.end());
|
||||
}
|
||||
|
||||
constexpr const_iterator cbegin() const {
|
||||
return this->begin();
|
||||
}
|
||||
|
||||
constexpr const_iterator cend() const {
|
||||
return this->end();
|
||||
}
|
||||
|
||||
constexpr reverse_iterator rbegin() {
|
||||
return reverse_iterator(this->end());
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator rbegin() const {
|
||||
return const_reverse_iterator(this->end());
|
||||
}
|
||||
|
||||
constexpr reverse_iterator rend() {
|
||||
return reverse_iterator(this->begin());
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(this->begin());
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator crbegin() const {
|
||||
return this->rbegin();
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator crend() const {
|
||||
return this->rend();
|
||||
}
|
||||
|
||||
constexpr iterator iterator_to(reference v) {
|
||||
return iterator(m_impl.iterator_to(GetNode(v)));
|
||||
}
|
||||
|
||||
constexpr const_iterator iterator_to(const_reference v) const {
|
||||
return const_iterator(m_impl.iterator_to(GetNode(v)));
|
||||
}
|
||||
|
||||
// Content management.
|
||||
constexpr bool empty() const {
|
||||
return m_impl.empty();
|
||||
}
|
||||
|
||||
constexpr size_type size() const {
|
||||
return m_impl.size();
|
||||
}
|
||||
|
||||
constexpr reference back() {
|
||||
return GetParent(m_impl.back());
|
||||
}
|
||||
|
||||
constexpr const_reference back() const {
|
||||
return GetParent(m_impl.back());
|
||||
}
|
||||
|
||||
constexpr reference front() {
|
||||
return GetParent(m_impl.front());
|
||||
}
|
||||
|
||||
constexpr const_reference front() const {
|
||||
return GetParent(m_impl.front());
|
||||
}
|
||||
|
||||
constexpr void push_back(reference ref) {
|
||||
m_impl.push_back(GetNode(ref));
|
||||
}
|
||||
|
||||
constexpr void push_front(reference ref) {
|
||||
m_impl.push_front(GetNode(ref));
|
||||
}
|
||||
|
||||
constexpr void pop_back() {
|
||||
m_impl.pop_back();
|
||||
}
|
||||
|
||||
constexpr void pop_front() {
|
||||
m_impl.pop_front();
|
||||
}
|
||||
|
||||
constexpr iterator insert(const_iterator pos, reference ref) {
|
||||
return iterator(m_impl.insert(pos.GetImplIterator(), GetNode(ref)));
|
||||
}
|
||||
|
||||
constexpr void splice(const_iterator pos, IntrusiveList& o) {
|
||||
m_impl.splice(pos.GetImplIterator(), o.m_impl);
|
||||
}
|
||||
|
||||
constexpr void splice(const_iterator pos, IntrusiveList& o, const_iterator first) {
|
||||
m_impl.splice(pos.GetImplIterator(), o.m_impl, first.GetImplIterator());
|
||||
}
|
||||
|
||||
constexpr void splice(const_iterator pos, IntrusiveList& o, const_iterator first,
|
||||
const_iterator last) {
|
||||
m_impl.splice(pos.GetImplIterator(), o.m_impl, first.GetImplIterator(),
|
||||
last.GetImplIterator());
|
||||
}
|
||||
|
||||
constexpr iterator erase(const_iterator pos) {
|
||||
return iterator(m_impl.erase(pos.GetImplIterator()));
|
||||
}
|
||||
|
||||
constexpr void clear() {
|
||||
m_impl.clear();
|
||||
}
|
||||
};
|
||||
|
||||
template <auto T, class Derived = Common::impl::GetParentType<T>>
|
||||
class IntrusiveListMemberTraits;
|
||||
|
||||
template <class Parent, IntrusiveListNode Parent::*Member, class Derived>
|
||||
class IntrusiveListMemberTraits<Member, Derived> {
|
||||
public:
|
||||
using ListType = IntrusiveList<Derived, IntrusiveListMemberTraits>;
|
||||
|
||||
private:
|
||||
friend class IntrusiveList<Derived, IntrusiveListMemberTraits>;
|
||||
|
||||
static constexpr IntrusiveListNode& GetNode(Derived& parent) {
|
||||
return parent.*Member;
|
||||
}
|
||||
|
||||
static constexpr IntrusiveListNode const& GetNode(Derived const& parent) {
|
||||
return parent.*Member;
|
||||
}
|
||||
|
||||
static Derived& GetParent(IntrusiveListNode& node) {
|
||||
return Common::GetParentReference<Member, Derived>(std::addressof(node));
|
||||
}
|
||||
|
||||
static Derived const& GetParent(IntrusiveListNode const& node) {
|
||||
return Common::GetParentReference<Member, Derived>(std::addressof(node));
|
||||
}
|
||||
};
|
||||
|
||||
template <auto T, class Derived = Common::impl::GetParentType<T>>
|
||||
class IntrusiveListMemberTraitsByNonConstexprOffsetOf;
|
||||
|
||||
template <class Parent, IntrusiveListNode Parent::*Member, class Derived>
|
||||
class IntrusiveListMemberTraitsByNonConstexprOffsetOf<Member, Derived> {
|
||||
public:
|
||||
using ListType = IntrusiveList<Derived, IntrusiveListMemberTraitsByNonConstexprOffsetOf>;
|
||||
|
||||
private:
|
||||
friend class IntrusiveList<Derived, IntrusiveListMemberTraitsByNonConstexprOffsetOf>;
|
||||
|
||||
static constexpr IntrusiveListNode& GetNode(Derived& parent) {
|
||||
return parent.*Member;
|
||||
}
|
||||
|
||||
static constexpr IntrusiveListNode const& GetNode(Derived const& parent) {
|
||||
return parent.*Member;
|
||||
}
|
||||
|
||||
static Derived& GetParent(IntrusiveListNode& node) {
|
||||
return *reinterpret_cast<Derived*>(reinterpret_cast<char*>(std::addressof(node)) -
|
||||
GetOffset());
|
||||
}
|
||||
|
||||
static Derived const& GetParent(IntrusiveListNode const& node) {
|
||||
return *reinterpret_cast<const Derived*>(
|
||||
reinterpret_cast<const char*>(std::addressof(node)) - GetOffset());
|
||||
}
|
||||
|
||||
static uintptr_t GetOffset() {
|
||||
return reinterpret_cast<uintptr_t>(std::addressof(reinterpret_cast<Derived*>(0)->*Member));
|
||||
}
|
||||
};
|
||||
|
||||
template <class Derived>
|
||||
class IntrusiveListBaseNode : public IntrusiveListNode {};
|
||||
|
||||
template <class Derived>
|
||||
class IntrusiveListBaseTraits {
|
||||
public:
|
||||
using ListType = IntrusiveList<Derived, IntrusiveListBaseTraits>;
|
||||
|
||||
private:
|
||||
friend class IntrusiveList<Derived, IntrusiveListBaseTraits>;
|
||||
|
||||
static constexpr IntrusiveListNode& GetNode(Derived& parent) {
|
||||
return static_cast<IntrusiveListNode&>(
|
||||
static_cast<IntrusiveListBaseNode<Derived>&>(parent));
|
||||
}
|
||||
|
||||
static constexpr IntrusiveListNode const& GetNode(Derived const& parent) {
|
||||
return static_cast<const IntrusiveListNode&>(
|
||||
static_cast<const IntrusiveListBaseNode<Derived>&>(parent));
|
||||
}
|
||||
|
||||
static constexpr Derived& GetParent(IntrusiveListNode& node) {
|
||||
return static_cast<Derived&>(static_cast<IntrusiveListBaseNode<Derived>&>(node));
|
||||
}
|
||||
|
||||
static constexpr Derived const& GetParent(IntrusiveListNode const& node) {
|
||||
return static_cast<const Derived&>(
|
||||
static_cast<const IntrusiveListBaseNode<Derived>&>(node));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
@@ -5,14 +5,15 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
#include "core/hle/kernel/svc_types.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KEventInfo : public KSlabAllocated<KEventInfo>, public boost::intrusive::list_base_hook<> {
|
||||
class KEventInfo : public KSlabAllocated<KEventInfo>,
|
||||
public Common::IntrusiveListBaseNode<KEventInfo> {
|
||||
public:
|
||||
struct InfoCreateThread {
|
||||
u32 thread_id{};
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <boost/intrusive/list.hpp>
|
||||
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
@@ -15,13 +16,14 @@ namespace Kernel {
|
||||
|
||||
class KObjectNameGlobalData;
|
||||
|
||||
class KObjectName : public KSlabAllocated<KObjectName>, public boost::intrusive::list_base_hook<> {
|
||||
class KObjectName : public KSlabAllocated<KObjectName>,
|
||||
public Common::IntrusiveListBaseNode<KObjectName> {
|
||||
public:
|
||||
explicit KObjectName(KernelCore&) {}
|
||||
virtual ~KObjectName() = default;
|
||||
|
||||
static constexpr size_t NameLengthMax = 12;
|
||||
using List = boost::intrusive::list<KObjectName>;
|
||||
using List = Common::IntrusiveListBaseTraits<KObjectName>::ListType;
|
||||
|
||||
static Result NewFromName(KernelCore& kernel, KAutoObject* obj, const char* name);
|
||||
static Result Delete(KernelCore& kernel, KAutoObject* obj, const char* name);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
#include "core/hle/kernel/k_server_session.h"
|
||||
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
bool IsSignaled() const override;
|
||||
|
||||
private:
|
||||
using SessionList = boost::intrusive::list<KServerSession>;
|
||||
using SessionList = Common::IntrusiveListBaseTraits<KServerSession>::ListType;
|
||||
|
||||
void CleanupSessions();
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/k_session_request.h"
|
||||
@@ -27,7 +27,7 @@ class KSession;
|
||||
class KThread;
|
||||
|
||||
class KServerSession final : public KSynchronizationObject,
|
||||
public boost::intrusive::list_base_hook<> {
|
||||
public Common::IntrusiveListBaseNode<KServerSession> {
|
||||
KERNEL_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject);
|
||||
|
||||
friend class ServiceThread;
|
||||
@@ -67,7 +67,8 @@ private:
|
||||
KSession* m_parent{};
|
||||
|
||||
/// List of threads which are pending a reply.
|
||||
boost::intrusive::list<KSessionRequest> m_request_list{};
|
||||
using RequestList = Common::IntrusiveListBaseTraits<KSessionRequest>::ListType;
|
||||
RequestList m_request_list{};
|
||||
KSessionRequest* m_current_request{};
|
||||
|
||||
KLightLock m_lock;
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
#include "core/hle/kernel/k_auto_object.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_memory_block.h"
|
||||
@@ -16,7 +18,7 @@ namespace Kernel {
|
||||
|
||||
class KSessionRequest final : public KSlabAllocated<KSessionRequest>,
|
||||
public KAutoObject,
|
||||
public boost::intrusive::list_base_hook<> {
|
||||
public Common::IntrusiveListBaseNode<KSessionRequest> {
|
||||
KERNEL_AUTOOBJECT_TRAITS(KSessionRequest, KAutoObject);
|
||||
|
||||
public:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Kernel {
|
||||
class KSharedMemory;
|
||||
|
||||
class KSharedMemoryInfo final : public KSlabAllocated<KSharedMemoryInfo>,
|
||||
public boost::intrusive::list_base_hook<> {
|
||||
public Common::IntrusiveListBaseNode<KSharedMemoryInfo> {
|
||||
|
||||
public:
|
||||
explicit KSharedMemoryInfo(KernelCore&) {}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
#include "common/intrusive_red_black_tree.h"
|
||||
#include "common/spin_lock.h"
|
||||
@@ -119,7 +119,7 @@ s32 GetCurrentCoreId(KernelCore& kernel);
|
||||
Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel);
|
||||
|
||||
class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>,
|
||||
public boost::intrusive::list_base_hook<>,
|
||||
public Common::IntrusiveListBaseNode<KThread>,
|
||||
public KTimerTask {
|
||||
KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject);
|
||||
|
||||
@@ -138,7 +138,7 @@ public:
|
||||
public:
|
||||
using ThreadContext32 = Core::ARM_Interface::ThreadContext32;
|
||||
using ThreadContext64 = Core::ARM_Interface::ThreadContext64;
|
||||
using WaiterList = boost::intrusive::list<KThread>;
|
||||
using WaiterList = Common::IntrusiveListBaseTraits<KThread>::ListType;
|
||||
|
||||
/**
|
||||
* Gets the thread's current priority
|
||||
@@ -750,8 +750,9 @@ private:
|
||||
ConditionVariableThreadTreeTraits::TreeType<LockWithPriorityInheritanceComparator>;
|
||||
|
||||
public:
|
||||
class LockWithPriorityInheritanceInfo : public KSlabAllocated<LockWithPriorityInheritanceInfo>,
|
||||
public boost::intrusive::list_base_hook<> {
|
||||
class LockWithPriorityInheritanceInfo
|
||||
: public KSlabAllocated<LockWithPriorityInheritanceInfo>,
|
||||
public Common::IntrusiveListBaseNode<LockWithPriorityInheritanceInfo> {
|
||||
public:
|
||||
explicit LockWithPriorityInheritanceInfo(KernelCore&) {}
|
||||
|
||||
@@ -839,7 +840,7 @@ public:
|
||||
|
||||
private:
|
||||
using LockWithPriorityInheritanceInfoList =
|
||||
boost::intrusive::list<LockWithPriorityInheritanceInfo>;
|
||||
Common::IntrusiveListBaseTraits<LockWithPriorityInheritanceInfo>::ListType;
|
||||
|
||||
ConditionVariableThreadTree* m_condvar_tree{};
|
||||
u64 m_condvar_key{};
|
||||
|
||||
@@ -109,37 +109,14 @@ public:
|
||||
}
|
||||
|
||||
bool RumblePlay(const Common::Input::VibrationStatus vibration) {
|
||||
constexpr u32 rumble_max_duration_ms = 2000;
|
||||
constexpr f32 low_start_sensitivity_limit = 140.0;
|
||||
constexpr f32 low_width_sensitivity_limit = 400.0;
|
||||
constexpr f32 high_start_sensitivity_limit = 200.0;
|
||||
constexpr f32 high_width_sensitivity_limit = 700.0;
|
||||
// Try to provide some feeling of the frequency by reducing the amplitude depending on it.
|
||||
f32 low_frequency_scale = 1.0;
|
||||
if (vibration.low_frequency > low_start_sensitivity_limit) {
|
||||
low_frequency_scale =
|
||||
std::max(1.0f - (vibration.low_frequency - low_start_sensitivity_limit) /
|
||||
low_width_sensitivity_limit,
|
||||
0.3f);
|
||||
}
|
||||
f32 low_amplitude = vibration.low_amplitude * low_frequency_scale;
|
||||
|
||||
f32 high_frequency_scale = 1.0;
|
||||
if (vibration.high_frequency > high_start_sensitivity_limit) {
|
||||
high_frequency_scale =
|
||||
std::max(1.0f - (vibration.high_frequency - high_start_sensitivity_limit) /
|
||||
high_width_sensitivity_limit,
|
||||
0.3f);
|
||||
}
|
||||
f32 high_amplitude = vibration.high_amplitude * high_frequency_scale;
|
||||
|
||||
constexpr u32 rumble_max_duration_ms = 1000;
|
||||
if (sdl_controller) {
|
||||
return SDL_GameControllerRumble(sdl_controller.get(), static_cast<u16>(low_amplitude),
|
||||
static_cast<u16>(high_amplitude),
|
||||
rumble_max_duration_ms) != -1;
|
||||
return SDL_GameControllerRumble(
|
||||
sdl_controller.get(), static_cast<u16>(vibration.low_amplitude),
|
||||
static_cast<u16>(vibration.high_amplitude), rumble_max_duration_ms) != -1;
|
||||
} else if (sdl_joystick) {
|
||||
return SDL_JoystickRumble(sdl_joystick.get(), static_cast<u16>(low_amplitude),
|
||||
static_cast<u16>(high_amplitude),
|
||||
return SDL_JoystickRumble(sdl_joystick.get(), static_cast<u16>(vibration.low_amplitude),
|
||||
static_cast<u16>(vibration.high_amplitude),
|
||||
rumble_max_duration_ms) != -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -223,9 +223,6 @@ void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool
|
||||
}
|
||||
|
||||
void Maxwell3D::RefreshParametersImpl() {
|
||||
if (!Settings::IsGPULevelHigh()) {
|
||||
return;
|
||||
}
|
||||
size_t current_index = 0;
|
||||
for (auto& segment : macro_segments) {
|
||||
if (segment.first == 0) {
|
||||
|
||||
@@ -1287,7 +1287,8 @@ bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info,
|
||||
}
|
||||
const u32 buffer_size = static_cast<u32>(buffer_operand.pitch * buffer_operand.height);
|
||||
static constexpr auto sync_info = VideoCommon::ObtainBufferSynchronize::FullSynchronize;
|
||||
const auto post_op = VideoCommon::ObtainBufferOperation::DoNothing;
|
||||
const auto post_op = IS_IMAGE_UPLOAD ? VideoCommon::ObtainBufferOperation::DoNothing
|
||||
: VideoCommon::ObtainBufferOperation::MarkAsWritten;
|
||||
const auto [buffer, offset] =
|
||||
buffer_cache.ObtainBuffer(buffer_operand.address, buffer_size, sync_info, post_op);
|
||||
|
||||
@@ -1298,8 +1299,7 @@ bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info,
|
||||
if constexpr (IS_IMAGE_UPLOAD) {
|
||||
image->UploadMemory(buffer->Handle(), offset, copy_span);
|
||||
} else {
|
||||
texture_cache.DownloadImageIntoBuffer(image, buffer->Handle(), offset, copy_span,
|
||||
buffer_operand.address, buffer_size);
|
||||
image->DownloadMemory(buffer->Handle(), offset, copy_span);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -803,40 +803,30 @@ void Image::UploadMemory(const ImageBufferMap& map,
|
||||
|
||||
void Image::DownloadMemory(GLuint buffer_handle, size_t buffer_offset,
|
||||
std::span<const VideoCommon::BufferImageCopy> copies) {
|
||||
std::array buffer_handles{buffer_handle};
|
||||
std::array buffer_offsets{buffer_offset};
|
||||
DownloadMemory(buffer_handles, buffer_offsets, copies);
|
||||
}
|
||||
|
||||
void Image::DownloadMemory(std::span<GLuint> buffer_handles, std::span<size_t> buffer_offsets,
|
||||
std::span<const VideoCommon::BufferImageCopy> copies) {
|
||||
const bool is_rescaled = True(flags & ImageFlagBits::Rescaled);
|
||||
if (is_rescaled) {
|
||||
ScaleDown();
|
||||
}
|
||||
glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT); // TODO: Move this to its own API
|
||||
for (size_t i = 0; i < buffer_handles.size(); i++) {
|
||||
auto& buffer_handle = buffer_handles[i];
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer_handle);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer_handle);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
|
||||
u32 current_row_length = std::numeric_limits<u32>::max();
|
||||
u32 current_image_height = std::numeric_limits<u32>::max();
|
||||
u32 current_row_length = std::numeric_limits<u32>::max();
|
||||
u32 current_image_height = std::numeric_limits<u32>::max();
|
||||
|
||||
for (const VideoCommon::BufferImageCopy& copy : copies) {
|
||||
if (copy.image_subresource.base_level >= gl_num_levels) {
|
||||
continue;
|
||||
}
|
||||
if (current_row_length != copy.buffer_row_length) {
|
||||
current_row_length = copy.buffer_row_length;
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, current_row_length);
|
||||
}
|
||||
if (current_image_height != copy.buffer_image_height) {
|
||||
current_image_height = copy.buffer_image_height;
|
||||
glPixelStorei(GL_PACK_IMAGE_HEIGHT, current_image_height);
|
||||
}
|
||||
CopyImageToBuffer(copy, buffer_offsets[i]);
|
||||
for (const VideoCommon::BufferImageCopy& copy : copies) {
|
||||
if (copy.image_subresource.base_level >= gl_num_levels) {
|
||||
continue;
|
||||
}
|
||||
if (current_row_length != copy.buffer_row_length) {
|
||||
current_row_length = copy.buffer_row_length;
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, current_row_length);
|
||||
}
|
||||
if (current_image_height != copy.buffer_image_height) {
|
||||
current_image_height = copy.buffer_image_height;
|
||||
glPixelStorei(GL_PACK_IMAGE_HEIGHT, current_image_height);
|
||||
}
|
||||
CopyImageToBuffer(copy, buffer_offset);
|
||||
}
|
||||
if (is_rescaled) {
|
||||
ScaleUp(true);
|
||||
|
||||
@@ -215,9 +215,6 @@ public:
|
||||
void DownloadMemory(GLuint buffer_handle, size_t buffer_offset,
|
||||
std::span<const VideoCommon::BufferImageCopy> copies);
|
||||
|
||||
void DownloadMemory(std::span<GLuint> buffer_handle, std::span<size_t> buffer_offset,
|
||||
std::span<const VideoCommon::BufferImageCopy> copies);
|
||||
|
||||
void DownloadMemory(ImageBufferMap& map, std::span<const VideoCommon::BufferImageCopy> copies);
|
||||
|
||||
GLuint StorageHandle() noexcept;
|
||||
@@ -379,7 +376,6 @@ struct TextureCacheParams {
|
||||
using Sampler = OpenGL::Sampler;
|
||||
using Framebuffer = OpenGL::Framebuffer;
|
||||
using AsyncBuffer = u32;
|
||||
using BufferType = GLuint;
|
||||
};
|
||||
|
||||
using TextureCache = VideoCommon::TextureCache<TextureCacheParams>;
|
||||
|
||||
@@ -696,13 +696,6 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
ShaderPools& pools, const ComputePipelineCacheKey& key, Shader::Environment& env,
|
||||
PipelineStatistics* statistics, bool build_in_parallel) try {
|
||||
// TODO: Remove this when Intel fixes their shader compiler.
|
||||
// https://github.com/IGCIT/Intel-GPU-Community-Issue-Tracker-IGCIT/issues/159
|
||||
if (device.GetDriverID() == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) {
|
||||
LOG_ERROR(Render_Vulkan, "Skipping 0x{:016x}", key.Hash());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash());
|
||||
|
||||
Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()};
|
||||
|
||||
@@ -781,7 +781,8 @@ bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info,
|
||||
}
|
||||
const u32 buffer_size = static_cast<u32>(buffer_operand.pitch * buffer_operand.height);
|
||||
static constexpr auto sync_info = VideoCommon::ObtainBufferSynchronize::FullSynchronize;
|
||||
const auto post_op = VideoCommon::ObtainBufferOperation::DoNothing;
|
||||
const auto post_op = IS_IMAGE_UPLOAD ? VideoCommon::ObtainBufferOperation::DoNothing
|
||||
: VideoCommon::ObtainBufferOperation::MarkAsWritten;
|
||||
const auto [buffer, offset] =
|
||||
buffer_cache.ObtainBuffer(buffer_operand.address, buffer_size, sync_info, post_op);
|
||||
|
||||
@@ -792,8 +793,7 @@ bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info,
|
||||
if constexpr (IS_IMAGE_UPLOAD) {
|
||||
image->UploadMemory(buffer->Handle(), offset, copy_span);
|
||||
} else {
|
||||
texture_cache.DownloadImageIntoBuffer(image, buffer->Handle(), offset, copy_span,
|
||||
buffer_operand.address, buffer_size);
|
||||
image->DownloadMemory(buffer->Handle(), offset, copy_span);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#include "common/bit_cast.h"
|
||||
#include "common/bit_util.h"
|
||||
@@ -1344,31 +1343,14 @@ void Image::UploadMemory(const StagingBufferRef& map, std::span<const BufferImag
|
||||
|
||||
void Image::DownloadMemory(VkBuffer buffer, VkDeviceSize offset,
|
||||
std::span<const VideoCommon::BufferImageCopy> copies) {
|
||||
std::array buffer_handles{
|
||||
buffer,
|
||||
};
|
||||
std::array buffer_offsets{
|
||||
offset,
|
||||
};
|
||||
DownloadMemory(buffer_handles, buffer_offsets, copies);
|
||||
}
|
||||
|
||||
void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<VkDeviceSize> offsets_span,
|
||||
std::span<const VideoCommon::BufferImageCopy> copies) {
|
||||
const bool is_rescaled = True(flags & ImageFlagBits::Rescaled);
|
||||
if (is_rescaled) {
|
||||
ScaleDown();
|
||||
}
|
||||
boost::container::small_vector<VkBuffer, 1> buffers_vector{};
|
||||
boost::container::small_vector<std::vector<VkBufferImageCopy>, 1> vk_copies;
|
||||
for (size_t index = 0; index < buffers_span.size(); index++) {
|
||||
buffers_vector.emplace_back(buffers_span[index]);
|
||||
vk_copies.emplace_back(
|
||||
TransformBufferImageCopies(copies, offsets_span[index], aspect_mask));
|
||||
}
|
||||
std::vector vk_copies = TransformBufferImageCopies(copies, offset, aspect_mask);
|
||||
scheduler->RequestOutsideRenderPassOperationContext();
|
||||
scheduler->Record([buffers = std::move(buffers_vector), image = *original_image,
|
||||
aspect_mask = aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) {
|
||||
scheduler->Record([buffer, image = *original_image, aspect_mask = aspect_mask,
|
||||
vk_copies](vk::CommandBuffer cmdbuf) {
|
||||
const VkImageMemoryBarrier read_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
@@ -1387,20 +1369,6 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<VkDeviceS
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, read_barrier);
|
||||
|
||||
for (size_t index = 0; index < buffers.size(); index++) {
|
||||
cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffers[index],
|
||||
vk_copies[index]);
|
||||
}
|
||||
|
||||
const VkMemoryBarrier memory_write_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
};
|
||||
const VkImageMemoryBarrier image_write_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
@@ -1419,6 +1387,15 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<VkDeviceS
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
const VkMemoryBarrier memory_write_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, read_barrier);
|
||||
cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, vk_copies);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
0, memory_write_barrier, nullptr, image_write_barrier);
|
||||
});
|
||||
@@ -1428,13 +1405,7 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<VkDeviceS
|
||||
}
|
||||
|
||||
void Image::DownloadMemory(const StagingBufferRef& map, std::span<const BufferImageCopy> copies) {
|
||||
std::array buffers{
|
||||
map.buffer,
|
||||
};
|
||||
std::array offsets{
|
||||
map.offset,
|
||||
};
|
||||
DownloadMemory(buffers, offsets, copies);
|
||||
DownloadMemory(map.buffer, map.offset, copies);
|
||||
}
|
||||
|
||||
bool Image::IsRescaled() const noexcept {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -141,9 +141,6 @@ public:
|
||||
void DownloadMemory(VkBuffer buffer, VkDeviceSize offset,
|
||||
std::span<const VideoCommon::BufferImageCopy> copies);
|
||||
|
||||
void DownloadMemory(std::span<VkBuffer> buffers, std::span<VkDeviceSize> offsets,
|
||||
std::span<const VideoCommon::BufferImageCopy> copies);
|
||||
|
||||
void DownloadMemory(const StagingBufferRef& map,
|
||||
std::span<const VideoCommon::BufferImageCopy> copies);
|
||||
|
||||
@@ -374,7 +371,6 @@ struct TextureCacheParams {
|
||||
using Sampler = Vulkan::Sampler;
|
||||
using Framebuffer = Vulkan::Framebuffer;
|
||||
using AsyncBuffer = Vulkan::StagingBufferRef;
|
||||
using BufferType = VkBuffer;
|
||||
};
|
||||
|
||||
using TextureCache = VideoCommon::TextureCache<TextureCacheParams>;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/settings.h"
|
||||
@@ -18,10 +17,15 @@
|
||||
|
||||
namespace VideoCommon {
|
||||
|
||||
using Tegra::Texture::SwizzleSource;
|
||||
using Tegra::Texture::TextureType;
|
||||
using Tegra::Texture::TICEntry;
|
||||
using Tegra::Texture::TSCEntry;
|
||||
using VideoCore::Surface::GetFormatType;
|
||||
using VideoCore::Surface::IsCopyCompatible;
|
||||
using VideoCore::Surface::PixelFormat;
|
||||
using VideoCore::Surface::PixelFormatFromDepthFormat;
|
||||
using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
|
||||
using VideoCore::Surface::SurfaceType;
|
||||
using namespace Common::Literals;
|
||||
|
||||
@@ -139,13 +143,6 @@ void TextureCache<P>::TickFrame() {
|
||||
runtime.TickFrame();
|
||||
critical_gc = 0;
|
||||
++frame_tick;
|
||||
|
||||
if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
|
||||
for (auto& buffer : async_buffers_death_ring) {
|
||||
runtime.FreeDeferredStagingBuffer(buffer);
|
||||
}
|
||||
async_buffers_death_ring.clear();
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
@@ -664,39 +661,25 @@ template <class P>
|
||||
void TextureCache<P>::CommitAsyncFlushes() {
|
||||
// This is intentionally passing the value by copy
|
||||
if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
|
||||
auto& download_ids = uncommitted_downloads;
|
||||
const std::span<const ImageId> download_ids = uncommitted_downloads;
|
||||
if (download_ids.empty()) {
|
||||
committed_downloads.emplace_back(std::move(uncommitted_downloads));
|
||||
uncommitted_downloads.clear();
|
||||
async_buffers.emplace_back(std::move(uncommitted_async_buffers));
|
||||
uncommitted_async_buffers.clear();
|
||||
async_buffers.emplace_back(std::optional<AsyncBuffer>{});
|
||||
return;
|
||||
}
|
||||
size_t total_size_bytes = 0;
|
||||
size_t last_async_buffer_id = uncommitted_async_buffers.size();
|
||||
bool any_none_dma = false;
|
||||
for (PendingDownload& download_info : download_ids) {
|
||||
if (download_info.is_swizzle) {
|
||||
total_size_bytes +=
|
||||
Common::AlignUp(slot_images[download_info.object_id].unswizzled_size_bytes, 64);
|
||||
any_none_dma = true;
|
||||
download_info.async_buffer_id = last_async_buffer_id;
|
||||
}
|
||||
for (const ImageId image_id : download_ids) {
|
||||
total_size_bytes += slot_images[image_id].unswizzled_size_bytes;
|
||||
}
|
||||
if (any_none_dma) {
|
||||
auto download_map = runtime.DownloadStagingBuffer(total_size_bytes, true);
|
||||
for (const PendingDownload& download_info : download_ids) {
|
||||
if (download_info.is_swizzle) {
|
||||
Image& image = slot_images[download_info.object_id];
|
||||
const auto copies = FullDownloadCopies(image.info);
|
||||
image.DownloadMemory(download_map, copies);
|
||||
download_map.offset += Common::AlignUp(image.unswizzled_size_bytes, 64);
|
||||
}
|
||||
}
|
||||
uncommitted_async_buffers.emplace_back(download_map);
|
||||
auto download_map = runtime.DownloadStagingBuffer(total_size_bytes, true);
|
||||
for (const ImageId image_id : download_ids) {
|
||||
Image& image = slot_images[image_id];
|
||||
const auto copies = FullDownloadCopies(image.info);
|
||||
image.DownloadMemory(download_map, copies);
|
||||
download_map.offset += Common::AlignUp(image.unswizzled_size_bytes, 64);
|
||||
}
|
||||
async_buffers.emplace_back(std::move(uncommitted_async_buffers));
|
||||
uncommitted_async_buffers.clear();
|
||||
async_buffers.emplace_back(download_map);
|
||||
}
|
||||
committed_downloads.emplace_back(std::move(uncommitted_downloads));
|
||||
uncommitted_downloads.clear();
|
||||
@@ -708,57 +691,39 @@ void TextureCache<P>::PopAsyncFlushes() {
|
||||
return;
|
||||
}
|
||||
if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
|
||||
const auto& download_ids = committed_downloads.front();
|
||||
const std::span<const ImageId> download_ids = committed_downloads.front();
|
||||
if (download_ids.empty()) {
|
||||
committed_downloads.pop_front();
|
||||
async_buffers.pop_front();
|
||||
return;
|
||||
}
|
||||
auto download_map = std::move(async_buffers.front());
|
||||
auto download_map = *async_buffers.front();
|
||||
std::span<u8> download_span = download_map.mapped_span;
|
||||
for (size_t i = download_ids.size(); i > 0; i--) {
|
||||
auto& download_info = download_ids[i - 1];
|
||||
auto& download_buffer = download_map[download_info.async_buffer_id];
|
||||
if (download_info.is_swizzle) {
|
||||
const ImageBase& image = slot_images[download_info.object_id];
|
||||
const auto copies = FullDownloadCopies(image.info);
|
||||
download_buffer.offset -= Common::AlignUp(image.unswizzled_size_bytes, 64);
|
||||
std::span<u8> download_span =
|
||||
download_buffer.mapped_span.subspan(download_buffer.offset);
|
||||
SwizzleImage(*gpu_memory, image.gpu_addr, image.info, copies, download_span,
|
||||
swizzle_data_buffer);
|
||||
} else {
|
||||
const BufferDownload& buffer_info = slot_buffer_downloads[download_info.object_id];
|
||||
std::span<u8> download_span =
|
||||
download_buffer.mapped_span.subspan(download_buffer.offset);
|
||||
gpu_memory->WriteBlockUnsafe(buffer_info.address, download_span.data(),
|
||||
buffer_info.size);
|
||||
slot_buffer_downloads.erase(download_info.object_id);
|
||||
}
|
||||
}
|
||||
for (auto& download_buffer : download_map) {
|
||||
async_buffers_death_ring.emplace_back(download_buffer);
|
||||
const ImageBase& image = slot_images[download_ids[i - 1]];
|
||||
const auto copies = FullDownloadCopies(image.info);
|
||||
download_map.offset -= Common::AlignUp(image.unswizzled_size_bytes, 64);
|
||||
std::span<u8> download_span_alt = download_span.subspan(download_map.offset);
|
||||
SwizzleImage(*gpu_memory, image.gpu_addr, image.info, copies, download_span_alt,
|
||||
swizzle_data_buffer);
|
||||
}
|
||||
runtime.FreeDeferredStagingBuffer(download_map);
|
||||
committed_downloads.pop_front();
|
||||
async_buffers.pop_front();
|
||||
} else {
|
||||
const auto& download_ids = committed_downloads.front();
|
||||
const std::span<const ImageId> download_ids = committed_downloads.front();
|
||||
if (download_ids.empty()) {
|
||||
committed_downloads.pop_front();
|
||||
return;
|
||||
}
|
||||
size_t total_size_bytes = 0;
|
||||
for (const PendingDownload& download_info : download_ids) {
|
||||
if (download_info.is_swizzle) {
|
||||
total_size_bytes += slot_images[download_info.object_id].unswizzled_size_bytes;
|
||||
}
|
||||
for (const ImageId image_id : download_ids) {
|
||||
total_size_bytes += slot_images[image_id].unswizzled_size_bytes;
|
||||
}
|
||||
auto download_map = runtime.DownloadStagingBuffer(total_size_bytes);
|
||||
const size_t original_offset = download_map.offset;
|
||||
for (const PendingDownload& download_info : download_ids) {
|
||||
if (!download_info.is_swizzle) {
|
||||
continue;
|
||||
}
|
||||
Image& image = slot_images[download_info.object_id];
|
||||
for (const ImageId image_id : download_ids) {
|
||||
Image& image = slot_images[image_id];
|
||||
const auto copies = FullDownloadCopies(image.info);
|
||||
image.DownloadMemory(download_map, copies);
|
||||
download_map.offset += image.unswizzled_size_bytes;
|
||||
@@ -767,11 +732,8 @@ void TextureCache<P>::PopAsyncFlushes() {
|
||||
runtime.Finish();
|
||||
download_map.offset = original_offset;
|
||||
std::span<u8> download_span = download_map.mapped_span;
|
||||
for (const PendingDownload& download_info : download_ids) {
|
||||
if (!download_info.is_swizzle) {
|
||||
continue;
|
||||
}
|
||||
const ImageBase& image = slot_images[download_info.object_id];
|
||||
for (const ImageId image_id : download_ids) {
|
||||
const ImageBase& image = slot_images[image_id];
|
||||
const auto copies = FullDownloadCopies(image.info);
|
||||
SwizzleImage(*gpu_memory, image.gpu_addr, image.info, copies, download_span,
|
||||
swizzle_data_buffer);
|
||||
@@ -871,33 +833,6 @@ std::pair<typename TextureCache<P>::Image*, BufferImageCopy> TextureCache<P>::Dm
|
||||
return {image, copy};
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void TextureCache<P>::DownloadImageIntoBuffer(typename TextureCache<P>::Image* image,
|
||||
typename TextureCache<P>::BufferType buffer,
|
||||
size_t buffer_offset,
|
||||
std::span<const VideoCommon::BufferImageCopy> copies,
|
||||
GPUVAddr address, size_t size) {
|
||||
if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
|
||||
const BufferDownload new_buffer_download{address, size};
|
||||
auto slot = slot_buffer_downloads.insert(new_buffer_download);
|
||||
const PendingDownload new_download{false, uncommitted_async_buffers.size(), slot};
|
||||
uncommitted_downloads.emplace_back(new_download);
|
||||
auto download_map = runtime.DownloadStagingBuffer(size, true);
|
||||
uncommitted_async_buffers.emplace_back(download_map);
|
||||
std::array buffers{
|
||||
buffer,
|
||||
download_map.buffer,
|
||||
};
|
||||
std::array buffer_offsets{
|
||||
buffer_offset,
|
||||
download_map.offset,
|
||||
};
|
||||
image->DownloadMemory(buffers, buffer_offsets, copies);
|
||||
} else {
|
||||
image->DownloadMemory(buffer, buffer_offset, copies);
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void TextureCache<P>::RefreshContents(Image& image, ImageId image_id) {
|
||||
if (False(image.flags & ImageFlagBits::CpuModified)) {
|
||||
@@ -2274,8 +2209,7 @@ void TextureCache<P>::BindRenderTarget(ImageViewId* old_id, ImageViewId new_id)
|
||||
if (new_id) {
|
||||
const ImageViewBase& old_view = slot_image_views[new_id];
|
||||
if (True(old_view.flags & ImageViewFlagBits::PreemtiveDownload)) {
|
||||
const PendingDownload new_download{true, 0, old_view.image_id};
|
||||
uncommitted_downloads.emplace_back(new_download);
|
||||
uncommitted_downloads.push_back(old_view.image_id);
|
||||
}
|
||||
}
|
||||
*old_id = new_id;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
@@ -40,9 +40,14 @@ struct ChannelState;
|
||||
|
||||
namespace VideoCommon {
|
||||
|
||||
using Tegra::Texture::SwizzleSource;
|
||||
using Tegra::Texture::TICEntry;
|
||||
using Tegra::Texture::TSCEntry;
|
||||
using VideoCore::Surface::GetFormatType;
|
||||
using VideoCore::Surface::IsCopyCompatible;
|
||||
using VideoCore::Surface::PixelFormat;
|
||||
using VideoCore::Surface::PixelFormatFromDepthFormat;
|
||||
using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
|
||||
using namespace Common::Literals;
|
||||
|
||||
struct ImageViewInOut {
|
||||
@@ -114,7 +119,6 @@ class TextureCache : public VideoCommon::ChannelSetupCaches<TextureCacheChannelI
|
||||
using Sampler = typename P::Sampler;
|
||||
using Framebuffer = typename P::Framebuffer;
|
||||
using AsyncBuffer = typename P::AsyncBuffer;
|
||||
using BufferType = typename P::BufferType;
|
||||
|
||||
struct BlitImages {
|
||||
ImageId dst_id;
|
||||
@@ -211,10 +215,6 @@ public:
|
||||
const Tegra::DMA::ImageCopy& copy_info, const Tegra::DMA::BufferOperand& buffer_operand,
|
||||
const Tegra::DMA::ImageOperand& image_operand, ImageId image_id, bool modifies_image);
|
||||
|
||||
void DownloadImageIntoBuffer(Image* image, BufferType buffer, size_t buffer_offset,
|
||||
std::span<const VideoCommon::BufferImageCopy> copies,
|
||||
GPUVAddr address = 0, size_t size = 0);
|
||||
|
||||
/// Return true when a CPU region is modified from the GPU
|
||||
[[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size);
|
||||
|
||||
@@ -424,32 +424,17 @@ private:
|
||||
u64 critical_memory;
|
||||
size_t critical_gc;
|
||||
|
||||
struct BufferDownload {
|
||||
GPUVAddr address;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct PendingDownload {
|
||||
bool is_swizzle;
|
||||
size_t async_buffer_id;
|
||||
SlotId object_id;
|
||||
};
|
||||
|
||||
SlotVector<Image> slot_images;
|
||||
SlotVector<ImageMapView> slot_map_views;
|
||||
SlotVector<ImageView> slot_image_views;
|
||||
SlotVector<ImageAlloc> slot_image_allocs;
|
||||
SlotVector<Sampler> slot_samplers;
|
||||
SlotVector<Framebuffer> slot_framebuffers;
|
||||
SlotVector<BufferDownload> slot_buffer_downloads;
|
||||
|
||||
// TODO: This data structure is not optimal and it should be reworked
|
||||
|
||||
std::vector<PendingDownload> uncommitted_downloads;
|
||||
std::deque<std::vector<PendingDownload>> committed_downloads;
|
||||
std::vector<AsyncBuffer> uncommitted_async_buffers;
|
||||
std::deque<std::vector<AsyncBuffer>> async_buffers;
|
||||
std::deque<AsyncBuffer> async_buffers_death_ring;
|
||||
std::vector<ImageId> uncommitted_downloads;
|
||||
std::deque<std::vector<ImageId>> committed_downloads;
|
||||
std::deque<std::optional<AsyncBuffer>> async_buffers;
|
||||
|
||||
struct LRUItemParams {
|
||||
using ObjectType = ImageId;
|
||||
|
||||
Reference in New Issue
Block a user