Compare commits
34 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21742f0096 | ||
|
|
b720009dc0 | ||
|
|
36910e9020 | ||
|
|
0456ed6b4e | ||
|
|
5cb1c2ad84 | ||
|
|
928380ebf9 | ||
|
|
0ec5b9bff2 | ||
|
|
7ad17ae397 | ||
|
|
edbfbf2f2f | ||
|
|
fbefcf7280 | ||
|
|
16bf50e610 | ||
|
|
fc8aef7323 | ||
|
|
8ec32e9755 | ||
|
|
03186af6a1 | ||
|
|
d68eb751c5 | ||
|
|
694c078655 | ||
|
|
9484519ec3 | ||
|
|
064aa3de11 | ||
|
|
ade44ac2ea | ||
|
|
f785f73e92 | ||
|
|
09400e4f4e | ||
|
|
76d83ffbec | ||
|
|
72add82ee9 | ||
|
|
995e27e9b7 | ||
|
|
79e8f4abe8 | ||
|
|
404a94a199 | ||
|
|
330b31ae2e | ||
|
|
35ed051742 | ||
|
|
5bd0c1517f | ||
|
|
3d2d77eb3f | ||
|
|
e394e1ecc4 | ||
|
|
90a0506d56 | ||
|
|
ad58d7eae7 | ||
|
|
fea05a17ea |
@@ -46,13 +46,3 @@ using GPUVAddr = u64; ///< Represents a pointer in the GPU virtual address space
|
||||
|
||||
using u128 = std::array<std::uint64_t, 2>;
|
||||
static_assert(sizeof(u128) == 16, "u128 must be 128 bits wide");
|
||||
|
||||
// An inheritable class to disallow the copy constructor and operator= functions
|
||||
class NonCopyable {
|
||||
protected:
|
||||
constexpr NonCopyable() = default;
|
||||
~NonCopyable() = default;
|
||||
|
||||
NonCopyable(const NonCopyable&) = delete;
|
||||
NonCopyable& operator=(const NonCopyable&) = delete;
|
||||
};
|
||||
|
||||
@@ -209,6 +209,8 @@ enum class ButtonNames {
|
||||
Triangle,
|
||||
Share,
|
||||
Options,
|
||||
Home,
|
||||
Touch,
|
||||
|
||||
// Mouse buttons
|
||||
ButtonMouseWheel,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common::Telemetry {
|
||||
@@ -28,7 +29,7 @@ struct VisitorInterface;
|
||||
/**
|
||||
* Interface class for telemetry data fields.
|
||||
*/
|
||||
class FieldInterface : NonCopyable {
|
||||
class FieldInterface {
|
||||
public:
|
||||
virtual ~FieldInterface() = default;
|
||||
|
||||
@@ -52,14 +53,15 @@ public:
|
||||
template <typename T>
|
||||
class Field : public FieldInterface {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(Field);
|
||||
|
||||
Field(FieldType type_, std::string name_, T value_)
|
||||
: name(std::move(name_)), type(type_), value(std::move(value_)) {}
|
||||
|
||||
Field(const Field&) = default;
|
||||
Field& operator=(const Field&) = default;
|
||||
~Field() override = default;
|
||||
|
||||
Field(Field&&) = default;
|
||||
Field& operator=(Field&& other) = default;
|
||||
Field(Field&&) noexcept = default;
|
||||
Field& operator=(Field&& other) noexcept = default;
|
||||
|
||||
void Accept(VisitorInterface& visitor) const override;
|
||||
|
||||
@@ -98,9 +100,15 @@ private:
|
||||
/**
|
||||
* Collection of data fields that have been logged.
|
||||
*/
|
||||
class FieldCollection final : NonCopyable {
|
||||
class FieldCollection final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(FieldCollection);
|
||||
|
||||
FieldCollection() = default;
|
||||
~FieldCollection() = default;
|
||||
|
||||
FieldCollection(FieldCollection&&) noexcept = default;
|
||||
FieldCollection& operator=(FieldCollection&&) noexcept = default;
|
||||
|
||||
/**
|
||||
* Accept method for the visitor pattern, visits each field in the collection.
|
||||
@@ -133,7 +141,7 @@ private:
|
||||
* Telemetry fields visitor interface class. A backend to log to a web service should implement
|
||||
* this interface.
|
||||
*/
|
||||
struct VisitorInterface : NonCopyable {
|
||||
struct VisitorInterface {
|
||||
virtual ~VisitorInterface() = default;
|
||||
|
||||
virtual void Visit(const Field<bool>& field) = 0;
|
||||
@@ -160,8 +168,8 @@ struct VisitorInterface : NonCopyable {
|
||||
* Empty implementation of VisitorInterface that drops all fields. Used when a functional
|
||||
* backend implementation is not available.
|
||||
*/
|
||||
struct NullVisitor : public VisitorInterface {
|
||||
~NullVisitor() = default;
|
||||
struct NullVisitor final : public VisitorInterface {
|
||||
YUZU_NON_COPYABLE(NullVisitor);
|
||||
|
||||
void Visit(const Field<bool>& /*field*/) override {}
|
||||
void Visit(const Field<double>& /*field*/) override {}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hardware_properties.h"
|
||||
|
||||
@@ -24,8 +25,11 @@ class CPUInterruptHandler;
|
||||
using CPUInterrupts = std::array<CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>;
|
||||
|
||||
/// Generic ARMv8 CPU interface
|
||||
class ARM_Interface : NonCopyable {
|
||||
class ARM_Interface {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(ARM_Interface);
|
||||
YUZU_NON_MOVEABLE(ARM_Interface);
|
||||
|
||||
explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers_,
|
||||
bool uses_wall_clock_)
|
||||
: system{system_}, interrupt_handlers{interrupt_handlers_}, uses_wall_clock{
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
|
||||
@@ -29,8 +30,11 @@ enum class VfsEntryType {
|
||||
// A class representing an abstract filesystem. A default implementation given the root VirtualDir
|
||||
// is provided for convenience, but if the Vfs implementation has any additional state or
|
||||
// functionality, they will need to override.
|
||||
class VfsFilesystem : NonCopyable {
|
||||
class VfsFilesystem {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(VfsFilesystem);
|
||||
YUZU_NON_MOVEABLE(VfsFilesystem);
|
||||
|
||||
explicit VfsFilesystem(VirtualDir root);
|
||||
virtual ~VfsFilesystem();
|
||||
|
||||
@@ -77,8 +81,12 @@ protected:
|
||||
};
|
||||
|
||||
// A class representing a file in an abstract filesystem.
|
||||
class VfsFile : NonCopyable {
|
||||
class VfsFile {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(VfsFile);
|
||||
YUZU_NON_MOVEABLE(VfsFile);
|
||||
|
||||
VfsFile() = default;
|
||||
virtual ~VfsFile();
|
||||
|
||||
// Retrieves the file name.
|
||||
@@ -176,8 +184,12 @@ public:
|
||||
};
|
||||
|
||||
// A class representing a directory in an abstract filesystem.
|
||||
class VfsDirectory : NonCopyable {
|
||||
class VfsDirectory {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(VfsDirectory);
|
||||
YUZU_NON_MOVEABLE(VfsDirectory);
|
||||
|
||||
VfsDirectory() = default;
|
||||
virtual ~VfsDirectory();
|
||||
|
||||
// Retrives the file located at path as if the current directory was root. Returns nullptr if
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/input.h"
|
||||
#include "common/param_package.h"
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/input.h"
|
||||
#include "common/param_package.h"
|
||||
#include "common/point.h"
|
||||
#include "common/quaternion.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/vector_math.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
|
||||
namespace Core::HID {
|
||||
|
||||
@@ -28,7 +28,7 @@ Common::Input::BatteryStatus TransformToBattery(const Common::Input::CallbackSta
|
||||
if (value > 0.8f) {
|
||||
battery = Common::Input::BatteryLevel::Full;
|
||||
}
|
||||
if (value >= 1.0f) {
|
||||
if (value >= 0.95f) {
|
||||
battery = Common::Input::BatteryLevel::Charging;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -20,8 +20,6 @@ class KernelCore;
|
||||
class KProcess;
|
||||
|
||||
#define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \
|
||||
YUZU_NON_COPYABLE(CLASS); \
|
||||
YUZU_NON_MOVEABLE(CLASS); \
|
||||
\
|
||||
private: \
|
||||
friend class ::Kernel::KClassTokenGenerator; \
|
||||
@@ -32,6 +30,9 @@ private:
|
||||
} \
|
||||
\
|
||||
public: \
|
||||
YUZU_NON_COPYABLE(CLASS); \
|
||||
YUZU_NON_MOVEABLE(CLASS); \
|
||||
\
|
||||
using BaseClass = BASE_CLASS; \
|
||||
static constexpr TypeObj GetStaticTypeObj() { \
|
||||
constexpr ClassTokenType Token = ClassToken(); \
|
||||
@@ -224,9 +225,9 @@ private:
|
||||
|
||||
template <typename T>
|
||||
class KScopedAutoObject {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(KScopedAutoObject);
|
||||
|
||||
public:
|
||||
constexpr KScopedAutoObject() = default;
|
||||
|
||||
constexpr KScopedAutoObject(T* o) : m_obj(o) {
|
||||
|
||||
@@ -16,13 +16,12 @@ class KernelCore;
|
||||
class KProcess;
|
||||
|
||||
class KAutoObjectWithListContainer {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(KAutoObjectWithListContainer);
|
||||
YUZU_NON_MOVEABLE(KAutoObjectWithListContainer);
|
||||
|
||||
public:
|
||||
using ListType = boost::intrusive::rbtree<KAutoObjectWithList>;
|
||||
|
||||
public:
|
||||
class ListAccessor : public KScopedLightLock {
|
||||
public:
|
||||
explicit ListAccessor(KAutoObjectWithListContainer* container)
|
||||
@@ -48,7 +47,6 @@ public:
|
||||
|
||||
friend class ListAccessor;
|
||||
|
||||
public:
|
||||
KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {}
|
||||
|
||||
void Initialize() {}
|
||||
|
||||
@@ -22,13 +22,12 @@ namespace Kernel {
|
||||
class KernelCore;
|
||||
|
||||
class KHandleTable {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(KHandleTable);
|
||||
YUZU_NON_MOVEABLE(KHandleTable);
|
||||
|
||||
public:
|
||||
static constexpr size_t MaxTableSize = 1024;
|
||||
|
||||
public:
|
||||
explicit KHandleTable(KernelCore& kernel_);
|
||||
~KHandleTable();
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <mutex>
|
||||
#include <tuple>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/k_page_heap.h"
|
||||
#include "core/hle/result.h"
|
||||
@@ -20,8 +21,11 @@ namespace Kernel {
|
||||
|
||||
class KPageLinkedList;
|
||||
|
||||
class KMemoryManager final : NonCopyable {
|
||||
class KMemoryManager final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(KMemoryManager);
|
||||
YUZU_NON_MOVEABLE(KMemoryManager);
|
||||
|
||||
enum class Pool : u32 {
|
||||
Application = 0,
|
||||
Applet = 1,
|
||||
@@ -88,26 +92,13 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
class Impl final : NonCopyable {
|
||||
private:
|
||||
using RefCount = u16;
|
||||
|
||||
private:
|
||||
KPageHeap heap;
|
||||
Pool pool{};
|
||||
|
||||
class Impl final {
|
||||
public:
|
||||
static std::size_t CalculateManagementOverheadSize(std::size_t region_size);
|
||||
YUZU_NON_COPYABLE(Impl);
|
||||
YUZU_NON_MOVEABLE(Impl);
|
||||
|
||||
static constexpr std::size_t CalculateOptimizedProcessOverheadSize(
|
||||
std::size_t region_size) {
|
||||
return (Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
|
||||
Common::BitSize<u64>()) *
|
||||
sizeof(u64);
|
||||
}
|
||||
|
||||
public:
|
||||
Impl() = default;
|
||||
~Impl() = default;
|
||||
|
||||
std::size_t Initialize(Pool new_pool, u64 start_address, u64 end_address);
|
||||
|
||||
@@ -130,6 +121,21 @@ private:
|
||||
constexpr VAddr GetEndAddress() const {
|
||||
return heap.GetEndAddress();
|
||||
}
|
||||
|
||||
static std::size_t CalculateManagementOverheadSize(std::size_t region_size);
|
||||
|
||||
static constexpr std::size_t CalculateOptimizedProcessOverheadSize(
|
||||
std::size_t region_size) {
|
||||
return (Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
|
||||
Common::BitSize<u64>()) *
|
||||
sizeof(u64);
|
||||
}
|
||||
|
||||
private:
|
||||
using RefCount = u16;
|
||||
|
||||
KPageHeap heap;
|
||||
Pool pool{};
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/intrusive_red_black_tree.h"
|
||||
#include "core/hle/kernel/k_memory_region_type.h"
|
||||
@@ -13,11 +14,13 @@ namespace Kernel {
|
||||
|
||||
class KMemoryRegionAllocator;
|
||||
|
||||
class KMemoryRegion final : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryRegion>,
|
||||
NonCopyable {
|
||||
class KMemoryRegion final : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryRegion> {
|
||||
friend class KMemoryRegionTree;
|
||||
|
||||
public:
|
||||
YUZU_NON_COPYABLE(KMemoryRegion);
|
||||
YUZU_NON_MOVEABLE(KMemoryRegion);
|
||||
|
||||
constexpr KMemoryRegion() = default;
|
||||
constexpr KMemoryRegion(u64 address_, u64 last_address_)
|
||||
: address{address_}, last_address{last_address_} {}
|
||||
@@ -29,6 +32,8 @@ public:
|
||||
: KMemoryRegion(address_, last_address_, std::numeric_limits<u64>::max(), attributes_,
|
||||
type_id_) {}
|
||||
|
||||
~KMemoryRegion() = default;
|
||||
|
||||
static constexpr int Compare(const KMemoryRegion& lhs, const KMemoryRegion& rhs) {
|
||||
if (lhs.GetAddress() < rhs.GetAddress()) {
|
||||
return -1;
|
||||
@@ -39,16 +44,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr void Reset(u64 a, u64 la, u64 p, u32 r, u32 t) {
|
||||
address = a;
|
||||
pair_address = p;
|
||||
last_address = la;
|
||||
attributes = r;
|
||||
type_id = t;
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr u64 GetAddress() const {
|
||||
return address;
|
||||
}
|
||||
@@ -108,6 +103,14 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr void Reset(u64 a, u64 la, u64 p, u32 r, u32 t) {
|
||||
address = a;
|
||||
pair_address = p;
|
||||
last_address = la;
|
||||
attributes = r;
|
||||
type_id = t;
|
||||
}
|
||||
|
||||
u64 address{};
|
||||
u64 last_address{};
|
||||
u64 pair_address{};
|
||||
@@ -115,8 +118,25 @@ private:
|
||||
u32 type_id{};
|
||||
};
|
||||
|
||||
class KMemoryRegionTree final : NonCopyable {
|
||||
class KMemoryRegionTree final {
|
||||
private:
|
||||
using TreeType =
|
||||
Common::IntrusiveRedBlackTreeBaseTraits<KMemoryRegion>::TreeType<KMemoryRegion>;
|
||||
|
||||
public:
|
||||
YUZU_NON_COPYABLE(KMemoryRegionTree);
|
||||
YUZU_NON_MOVEABLE(KMemoryRegionTree);
|
||||
|
||||
using value_type = TreeType::value_type;
|
||||
using size_type = TreeType::size_type;
|
||||
using difference_type = TreeType::difference_type;
|
||||
using pointer = TreeType::pointer;
|
||||
using const_pointer = TreeType::const_pointer;
|
||||
using reference = TreeType::reference;
|
||||
using const_reference = TreeType::const_reference;
|
||||
using iterator = TreeType::iterator;
|
||||
using const_iterator = TreeType::const_iterator;
|
||||
|
||||
struct DerivedRegionExtents {
|
||||
const KMemoryRegion* first_region{};
|
||||
const KMemoryRegion* last_region{};
|
||||
@@ -140,29 +160,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
using TreeType =
|
||||
Common::IntrusiveRedBlackTreeBaseTraits<KMemoryRegion>::TreeType<KMemoryRegion>;
|
||||
|
||||
public:
|
||||
using value_type = TreeType::value_type;
|
||||
using size_type = TreeType::size_type;
|
||||
using difference_type = TreeType::difference_type;
|
||||
using pointer = TreeType::pointer;
|
||||
using const_pointer = TreeType::const_pointer;
|
||||
using reference = TreeType::reference;
|
||||
using const_reference = TreeType::const_reference;
|
||||
using iterator = TreeType::iterator;
|
||||
using const_iterator = TreeType::const_iterator;
|
||||
|
||||
private:
|
||||
TreeType m_tree{};
|
||||
KMemoryRegionAllocator& memory_region_allocator;
|
||||
|
||||
public:
|
||||
explicit KMemoryRegionTree(KMemoryRegionAllocator& memory_region_allocator_);
|
||||
~KMemoryRegionTree() = default;
|
||||
|
||||
public:
|
||||
KMemoryRegion* FindModifiable(u64 address) {
|
||||
if (auto it = this->find(KMemoryRegion(address, address, 0, 0)); it != this->end()) {
|
||||
return std::addressof(*it);
|
||||
@@ -241,7 +241,6 @@ public:
|
||||
return GetDerivedRegionExtents(static_cast<KMemoryRegionType>(type_id));
|
||||
}
|
||||
|
||||
public:
|
||||
void InsertDirectly(u64 address, u64 last_address, u32 attr = 0, u32 type_id = 0);
|
||||
bool Insert(u64 address, size_t size, u32 type_id, u32 new_attr = 0, u32 old_attr = 0);
|
||||
|
||||
@@ -252,7 +251,6 @@ public:
|
||||
return this->GetRandomAlignedRegion(size + 2 * guard_size, alignment, type_id) + guard_size;
|
||||
}
|
||||
|
||||
public:
|
||||
// Iterator accessors.
|
||||
iterator begin() {
|
||||
return m_tree.begin();
|
||||
@@ -322,13 +320,21 @@ public:
|
||||
iterator nfind(const_reference ref) const {
|
||||
return m_tree.nfind(ref);
|
||||
}
|
||||
|
||||
private:
|
||||
TreeType m_tree{};
|
||||
KMemoryRegionAllocator& memory_region_allocator;
|
||||
};
|
||||
|
||||
class KMemoryRegionAllocator final : NonCopyable {
|
||||
class KMemoryRegionAllocator final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(KMemoryRegionAllocator);
|
||||
YUZU_NON_MOVEABLE(KMemoryRegionAllocator);
|
||||
|
||||
static constexpr size_t MaxMemoryRegions = 200;
|
||||
|
||||
constexpr KMemoryRegionAllocator() = default;
|
||||
constexpr ~KMemoryRegionAllocator() = default;
|
||||
|
||||
template <typename... Args>
|
||||
KMemoryRegion* Allocate(Args&&... args) {
|
||||
|
||||
@@ -8,14 +8,44 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/k_page_bitmap.h"
|
||||
#include "core/hle/kernel/memory_types.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KPageHeap final : NonCopyable {
|
||||
class KPageHeap final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(KPageHeap);
|
||||
YUZU_NON_MOVEABLE(KPageHeap);
|
||||
|
||||
KPageHeap() = default;
|
||||
~KPageHeap() = default;
|
||||
|
||||
constexpr VAddr GetAddress() const {
|
||||
return heap_address;
|
||||
}
|
||||
constexpr std::size_t GetSize() const {
|
||||
return heap_size;
|
||||
}
|
||||
constexpr VAddr GetEndAddress() const {
|
||||
return GetAddress() + GetSize();
|
||||
}
|
||||
constexpr std::size_t GetPageOffset(VAddr block) const {
|
||||
return (block - GetAddress()) / PageSize;
|
||||
}
|
||||
|
||||
void Initialize(VAddr heap_address, std::size_t heap_size, std::size_t metadata_size);
|
||||
VAddr AllocateBlock(s32 index, bool random);
|
||||
void Free(VAddr addr, std::size_t num_pages);
|
||||
|
||||
void UpdateUsedSize() {
|
||||
used_size = heap_size - (GetNumFreePages() * PageSize);
|
||||
}
|
||||
|
||||
static std::size_t CalculateManagementOverheadSize(std::size_t region_size);
|
||||
|
||||
static constexpr s32 GetAlignedBlockIndex(std::size_t num_pages, std::size_t align_pages) {
|
||||
const auto target_pages{std::max(num_pages, align_pages)};
|
||||
for (std::size_t i = 0; i < NumMemoryBlockPageShifts; i++) {
|
||||
@@ -45,21 +75,13 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr std::size_t NumMemoryBlockPageShifts{7};
|
||||
static constexpr std::array<std::size_t, NumMemoryBlockPageShifts> MemoryBlockPageShifts{
|
||||
0xC, 0x10, 0x15, 0x16, 0x19, 0x1D, 0x1E,
|
||||
};
|
||||
|
||||
class Block final : NonCopyable {
|
||||
private:
|
||||
KPageBitmap bitmap;
|
||||
VAddr heap_address{};
|
||||
uintptr_t end_offset{};
|
||||
std::size_t block_shift{};
|
||||
std::size_t next_block_shift{};
|
||||
|
||||
class Block final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(Block);
|
||||
YUZU_NON_MOVEABLE(Block);
|
||||
|
||||
Block() = default;
|
||||
~Block() = default;
|
||||
|
||||
constexpr std::size_t GetShift() const {
|
||||
return block_shift;
|
||||
@@ -129,7 +151,6 @@ private:
|
||||
return heap_address + (offset << GetShift());
|
||||
}
|
||||
|
||||
public:
|
||||
static constexpr std::size_t CalculateManagementOverheadSize(std::size_t region_size,
|
||||
std::size_t cur_block_shift,
|
||||
std::size_t next_block_shift) {
|
||||
@@ -139,35 +160,15 @@ private:
|
||||
return KPageBitmap::CalculateManagementOverheadSize(
|
||||
(align * 2 + Common::AlignUp(region_size, align)) / cur_block_size);
|
||||
}
|
||||
|
||||
private:
|
||||
KPageBitmap bitmap;
|
||||
VAddr heap_address{};
|
||||
uintptr_t end_offset{};
|
||||
std::size_t block_shift{};
|
||||
std::size_t next_block_shift{};
|
||||
};
|
||||
|
||||
public:
|
||||
KPageHeap() = default;
|
||||
|
||||
constexpr VAddr GetAddress() const {
|
||||
return heap_address;
|
||||
}
|
||||
constexpr std::size_t GetSize() const {
|
||||
return heap_size;
|
||||
}
|
||||
constexpr VAddr GetEndAddress() const {
|
||||
return GetAddress() + GetSize();
|
||||
}
|
||||
constexpr std::size_t GetPageOffset(VAddr block) const {
|
||||
return (block - GetAddress()) / PageSize;
|
||||
}
|
||||
|
||||
void Initialize(VAddr heap_address, std::size_t heap_size, std::size_t metadata_size);
|
||||
VAddr AllocateBlock(s32 index, bool random);
|
||||
void Free(VAddr addr, std::size_t num_pages);
|
||||
|
||||
void UpdateUsedSize() {
|
||||
used_size = heap_size - (GetNumFreePages() * PageSize);
|
||||
}
|
||||
|
||||
static std::size_t CalculateManagementOverheadSize(std::size_t region_size);
|
||||
|
||||
private:
|
||||
constexpr std::size_t GetNumFreePages() const {
|
||||
std::size_t num_free{};
|
||||
|
||||
@@ -180,6 +181,11 @@ private:
|
||||
|
||||
void FreeBlock(VAddr block, s32 index);
|
||||
|
||||
static constexpr std::size_t NumMemoryBlockPageShifts{7};
|
||||
static constexpr std::array<std::size_t, NumMemoryBlockPageShifts> MemoryBlockPageShifts{
|
||||
0xC, 0x10, 0x15, 0x16, 0x19, 0x1D, 0x1E,
|
||||
};
|
||||
|
||||
VAddr heap_address{};
|
||||
std::size_t heap_size{};
|
||||
std::size_t used_size{};
|
||||
|
||||
@@ -61,7 +61,10 @@ constexpr std::size_t GetSizeInRange(const KMemoryInfo& info, VAddr start, VAddr
|
||||
|
||||
} // namespace
|
||||
|
||||
KPageTable::KPageTable(Core::System& system_) : system{system_} {}
|
||||
KPageTable::KPageTable(Core::System& system_)
|
||||
: general_lock{system_.Kernel()}, map_physical_memory_lock{system_.Kernel()}, system{system_} {}
|
||||
|
||||
KPageTable::~KPageTable() = default;
|
||||
|
||||
ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type,
|
||||
bool enable_aslr, VAddr code_addr,
|
||||
@@ -282,7 +285,7 @@ ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemory
|
||||
R_UNLESS(this->CanContain(addr, size, state), ResultInvalidCurrentMemory);
|
||||
|
||||
// Lock the table.
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
// Verify that the destination memory is unmapped.
|
||||
R_TRY(this->CheckMemoryState(addr, size, KMemoryState::All, KMemoryState::Free,
|
||||
@@ -300,7 +303,7 @@ ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemory
|
||||
}
|
||||
|
||||
ResultCode KPageTable::MapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
const std::size_t num_pages{size / PageSize};
|
||||
|
||||
@@ -337,7 +340,7 @@ ResultCode KPageTable::MapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnmapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
if (!size) {
|
||||
return ResultSuccess;
|
||||
@@ -371,7 +374,7 @@ ResultCode KPageTable::UnmapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size
|
||||
|
||||
ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size,
|
||||
KPageTable& src_page_table, VAddr src_addr) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
const std::size_t num_pages{size / PageSize};
|
||||
|
||||
@@ -399,10 +402,10 @@ ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size,
|
||||
|
||||
ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
|
||||
// Lock the physical memory lock.
|
||||
std::lock_guard phys_lk(map_physical_memory_lock);
|
||||
KScopedLightLock map_phys_mem_lk(map_physical_memory_lock);
|
||||
|
||||
// Lock the table.
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
std::size_t mapped_size{};
|
||||
const VAddr end_addr{addr + size};
|
||||
@@ -478,7 +481,11 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
// Lock the physical memory lock.
|
||||
KScopedLightLock map_phys_mem_lk(map_physical_memory_lock);
|
||||
|
||||
// Lock the table.
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
const VAddr end_addr{addr + size};
|
||||
ResultCode result{ResultSuccess};
|
||||
@@ -540,7 +547,7 @@ ResultCode KPageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
|
||||
}
|
||||
|
||||
ResultCode KPageTable::MapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
KMemoryState src_state{};
|
||||
CASCADE_CODE(CheckMemoryState(
|
||||
@@ -579,7 +586,7 @@ ResultCode KPageTable::MapMemory(VAddr dst_addr, VAddr src_addr, std::size_t siz
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnmapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
KMemoryState src_state{};
|
||||
CASCADE_CODE(CheckMemoryState(
|
||||
@@ -622,6 +629,8 @@ ResultCode KPageTable::UnmapMemory(VAddr dst_addr, VAddr src_addr, std::size_t s
|
||||
|
||||
ResultCode KPageTable::MapPages(VAddr addr, const KPageLinkedList& page_linked_list,
|
||||
KMemoryPermission perm) {
|
||||
ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
VAddr cur_addr{addr};
|
||||
|
||||
for (const auto& node : page_linked_list.Nodes()) {
|
||||
@@ -650,7 +659,7 @@ ResultCode KPageTable::MapPages(VAddr address, KPageLinkedList& page_linked_list
|
||||
R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory);
|
||||
|
||||
// Lock the table.
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
// Check the memory state.
|
||||
R_TRY(this->CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free,
|
||||
@@ -667,6 +676,8 @@ ResultCode KPageTable::MapPages(VAddr address, KPageLinkedList& page_linked_list
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list) {
|
||||
ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
VAddr cur_addr{addr};
|
||||
|
||||
for (const auto& node : page_linked_list.Nodes()) {
|
||||
@@ -691,7 +702,7 @@ ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list,
|
||||
R_UNLESS(this->Contains(addr, size), ResultInvalidCurrentMemory);
|
||||
|
||||
// Lock the table.
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
// Check the memory state.
|
||||
R_TRY(this->CheckMemoryState(addr, size, KMemoryState::All, state, KMemoryPermission::None,
|
||||
@@ -712,7 +723,7 @@ ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
|
||||
const size_t num_pages = size / PageSize;
|
||||
|
||||
// Lock the table.
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
// Verify we can change the memory permission.
|
||||
KMemoryState old_state;
|
||||
@@ -766,7 +777,7 @@ ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
|
||||
}
|
||||
|
||||
KMemoryInfo KPageTable::QueryInfoImpl(VAddr addr) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
return block_manager->FindBlock(addr).GetMemoryInfo();
|
||||
}
|
||||
@@ -781,7 +792,7 @@ KMemoryInfo KPageTable::QueryInfo(VAddr addr) {
|
||||
}
|
||||
|
||||
ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
KMemoryState state{};
|
||||
KMemoryAttribute attribute{};
|
||||
@@ -799,7 +810,7 @@ ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemo
|
||||
}
|
||||
|
||||
ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
KMemoryState state{};
|
||||
|
||||
@@ -818,7 +829,7 @@ ResultCode KPageTable::SetMemoryPermission(VAddr addr, std::size_t size,
|
||||
const size_t num_pages = size / PageSize;
|
||||
|
||||
// Lock the table.
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
// Verify we can change the memory permission.
|
||||
KMemoryState old_state;
|
||||
@@ -847,7 +858,7 @@ ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask
|
||||
KMemoryAttribute::SetMask);
|
||||
|
||||
// Lock the table.
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
// Verify we can change the memory attribute.
|
||||
KMemoryState old_state;
|
||||
@@ -878,7 +889,7 @@ ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask
|
||||
|
||||
ResultCode KPageTable::SetMaxHeapSize(std::size_t size) {
|
||||
// Lock the table.
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
// Only process page tables are allowed to set heap size.
|
||||
ASSERT(!this->IsKernel());
|
||||
@@ -889,15 +900,15 @@ ResultCode KPageTable::SetMaxHeapSize(std::size_t size) {
|
||||
}
|
||||
|
||||
ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) {
|
||||
// Lock the physical memory lock.
|
||||
std::lock_guard phys_lk(map_physical_memory_lock);
|
||||
// Lock the physical memory mutex.
|
||||
KScopedLightLock map_phys_mem_lk(map_physical_memory_lock);
|
||||
|
||||
// Try to perform a reduction in heap, instead of an extension.
|
||||
VAddr cur_address{};
|
||||
std::size_t allocation_size{};
|
||||
{
|
||||
// Lock the table.
|
||||
std::lock_guard lk(page_table_lock);
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
// Validate that setting heap size is possible at all.
|
||||
R_UNLESS(!is_kernel, ResultOutOfMemory);
|
||||
@@ -962,7 +973,7 @@ ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) {
|
||||
// Map the pages.
|
||||
{
|
||||
// Lock the table.
|
||||
std::lock_guard lk(page_table_lock);
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
// Ensure that the heap hasn't changed since we began executing.
|
||||
ASSERT(cur_address == current_heap_end);
|
||||
@@ -1004,7 +1015,7 @@ ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages,
|
||||
bool is_map_only, VAddr region_start,
|
||||
std::size_t region_num_pages, KMemoryState state,
|
||||
KMemoryPermission perm, PAddr map_addr) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
if (!CanContain(region_start, region_num_pages * PageSize, state)) {
|
||||
return ResultInvalidCurrentMemory;
|
||||
@@ -1035,7 +1046,7 @@ ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages,
|
||||
}
|
||||
|
||||
ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
KMemoryPermission perm{};
|
||||
if (const ResultCode result{CheckMemoryState(
|
||||
@@ -1058,7 +1069,7 @@ ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
KMemoryPermission perm{};
|
||||
if (const ResultCode result{CheckMemoryState(
|
||||
@@ -1081,7 +1092,7 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
|
||||
}
|
||||
|
||||
ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
KMemoryPermission new_perm = KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite;
|
||||
|
||||
@@ -1108,7 +1119,7 @@ ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) {
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
KScopedLightLock lk(general_lock);
|
||||
|
||||
KMemoryPermission new_perm = KMemoryPermission::UserReadWrite;
|
||||
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/page_table.h"
|
||||
#include "core/file_sys/program_metadata.h"
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/k_memory_block.h"
|
||||
#include "core/hle/kernel/k_memory_manager.h"
|
||||
#include "core/hle/result.h"
|
||||
@@ -22,9 +23,13 @@ namespace Kernel {
|
||||
|
||||
class KMemoryBlockManager;
|
||||
|
||||
class KPageTable final : NonCopyable {
|
||||
class KPageTable final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(KPageTable);
|
||||
YUZU_NON_MOVEABLE(KPageTable);
|
||||
|
||||
explicit KPageTable(Core::System& system_);
|
||||
~KPageTable();
|
||||
|
||||
ResultCode InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr,
|
||||
VAddr code_addr, std::size_t code_size,
|
||||
@@ -142,11 +147,12 @@ private:
|
||||
}
|
||||
|
||||
bool IsLockedByCurrentThread() const {
|
||||
return true;
|
||||
return general_lock.IsLockedByCurrentThread();
|
||||
}
|
||||
|
||||
std::recursive_mutex page_table_lock;
|
||||
std::mutex map_physical_memory_lock;
|
||||
mutable KLightLock general_lock;
|
||||
mutable KLightLock map_physical_memory_lock;
|
||||
|
||||
std::unique_ptr<KMemoryBlockManager> block_manager;
|
||||
|
||||
public:
|
||||
@@ -205,7 +211,7 @@ public:
|
||||
return alias_code_region_end - alias_code_region_start;
|
||||
}
|
||||
size_t GetNormalMemorySize() {
|
||||
std::lock_guard lk(page_table_lock);
|
||||
KScopedLightLock lk(general_lock);
|
||||
return GetHeapSize() + mapped_physical_memory_size;
|
||||
}
|
||||
constexpr std::size_t GetAddressSpaceWidth() const {
|
||||
@@ -247,7 +253,9 @@ public:
|
||||
constexpr bool IsInsideASLRRegion(VAddr address, std::size_t size) const {
|
||||
return !IsOutsideASLRRegion(address, size);
|
||||
}
|
||||
constexpr PAddr GetPhysicalAddr(VAddr addr) {
|
||||
|
||||
PAddr GetPhysicalAddr(VAddr addr) {
|
||||
ASSERT(IsLockedByCurrentThread());
|
||||
const auto backing_addr = page_table_impl.backing_addr[addr >> PageBits];
|
||||
ASSERT(backing_addr);
|
||||
return backing_addr + addr;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <atomic>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Kernel {
|
||||
@@ -15,13 +16,17 @@ class KernelCore;
|
||||
|
||||
namespace impl {
|
||||
|
||||
class KSlabHeapImpl final : NonCopyable {
|
||||
class KSlabHeapImpl final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(KSlabHeapImpl);
|
||||
YUZU_NON_MOVEABLE(KSlabHeapImpl);
|
||||
|
||||
struct Node {
|
||||
Node* next{};
|
||||
};
|
||||
|
||||
constexpr KSlabHeapImpl() = default;
|
||||
constexpr ~KSlabHeapImpl() = default;
|
||||
|
||||
void Initialize(std::size_t size) {
|
||||
ASSERT(head == nullptr);
|
||||
@@ -64,9 +69,13 @@ private:
|
||||
|
||||
} // namespace impl
|
||||
|
||||
class KSlabHeapBase : NonCopyable {
|
||||
class KSlabHeapBase {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(KSlabHeapBase);
|
||||
YUZU_NON_MOVEABLE(KSlabHeapBase);
|
||||
|
||||
constexpr KSlabHeapBase() = default;
|
||||
constexpr ~KSlabHeapBase() = default;
|
||||
|
||||
constexpr bool Contains(uintptr_t addr) const {
|
||||
return start <= addr && addr < end;
|
||||
|
||||
@@ -396,7 +396,7 @@ static ResultCode GetProcessId(Core::System& system, u64* out_process_id, Handle
|
||||
// Get the process id.
|
||||
*out_process_id = process->GetId();
|
||||
|
||||
return ResultInvalidHandle;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
static ResultCode GetProcessId32(Core::System& system, u32* out_process_id_low,
|
||||
|
||||
@@ -91,6 +91,8 @@ public:
|
||||
{4, &DebugMonitor::GetApplicationProcessId, "GetApplicationProcessId"},
|
||||
{5, nullptr, "HookToCreateApplicationProgress"},
|
||||
{6, nullptr, "ClearHook"},
|
||||
{65000, &DebugMonitor::AtmosphereGetProcessInfo, "AtmosphereGetProcessInfo"},
|
||||
{65001, nullptr, "AtmosphereGetCurrentLimitInfo"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -125,6 +127,49 @@ private:
|
||||
GetApplicationPidGeneric(ctx, kernel.GetProcessList());
|
||||
}
|
||||
|
||||
void AtmosphereGetProcessInfo(Kernel::HLERequestContext& ctx) {
|
||||
// https://github.com/Atmosphere-NX/Atmosphere/blob/master/stratosphere/pm/source/impl/pm_process_manager.cpp#L614
|
||||
// This implementation is incomplete; only a handle to the process is returned.
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto pid = rp.PopRaw<u64>();
|
||||
|
||||
LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid);
|
||||
|
||||
const auto process = SearchProcessList(kernel.GetProcessList(), [pid](const auto& proc) {
|
||||
return proc->GetProcessID() == pid;
|
||||
});
|
||||
|
||||
if (!process.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultProcessNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
struct ProgramLocation {
|
||||
u64 program_id;
|
||||
u8 storage_id;
|
||||
};
|
||||
static_assert(sizeof(ProgramLocation) == 0x10, "ProgramLocation has an invalid size");
|
||||
|
||||
struct OverrideStatus {
|
||||
u64 keys_held;
|
||||
u64 flags;
|
||||
};
|
||||
static_assert(sizeof(OverrideStatus) == 0x10, "OverrideStatus has an invalid size");
|
||||
|
||||
OverrideStatus override_status{};
|
||||
ProgramLocation program_location{
|
||||
.program_id = (*process)->GetProgramID(),
|
||||
.storage_id = 0,
|
||||
};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 10, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(*process);
|
||||
rb.PushRaw(program_location);
|
||||
rb.PushRaw(override_status);
|
||||
}
|
||||
|
||||
const Kernel::KernelCore& kernel;
|
||||
};
|
||||
|
||||
|
||||
@@ -28,10 +28,10 @@ class Layer;
|
||||
|
||||
/// Represents a single display type
|
||||
class Display {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(Display);
|
||||
YUZU_NON_MOVEABLE(Display);
|
||||
|
||||
public:
|
||||
/// Constructs a display with a given unique ID and name.
|
||||
///
|
||||
/// @param id The unique ID for this display.
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
@@ -139,8 +140,11 @@ std::string GetResultStatusString(ResultStatus status);
|
||||
std::ostream& operator<<(std::ostream& os, ResultStatus status);
|
||||
|
||||
/// Interface for loading an application
|
||||
class AppLoader : NonCopyable {
|
||||
class AppLoader {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(AppLoader);
|
||||
YUZU_NON_MOVEABLE(AppLoader);
|
||||
|
||||
struct LoadParameters {
|
||||
s32 main_thread_priority;
|
||||
u64 main_thread_stack_size;
|
||||
|
||||
@@ -175,23 +175,23 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
BatteryLevel GetBatteryLevel() {
|
||||
Common::Input::BatteryLevel GetBatteryLevel() {
|
||||
const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get());
|
||||
switch (level) {
|
||||
case SDL_JOYSTICK_POWER_EMPTY:
|
||||
return BatteryLevel::Empty;
|
||||
return Common::Input::BatteryLevel::Empty;
|
||||
case SDL_JOYSTICK_POWER_LOW:
|
||||
return BatteryLevel::Critical;
|
||||
return Common::Input::BatteryLevel::Low;
|
||||
case SDL_JOYSTICK_POWER_MEDIUM:
|
||||
return BatteryLevel::Low;
|
||||
return Common::Input::BatteryLevel::Medium;
|
||||
case SDL_JOYSTICK_POWER_FULL:
|
||||
return BatteryLevel::Medium;
|
||||
case SDL_JOYSTICK_POWER_MAX:
|
||||
return BatteryLevel::Full;
|
||||
case SDL_JOYSTICK_POWER_UNKNOWN:
|
||||
return Common::Input::BatteryLevel::Full;
|
||||
case SDL_JOYSTICK_POWER_WIRED:
|
||||
return Common::Input::BatteryLevel::Charging;
|
||||
case SDL_JOYSTICK_POWER_UNKNOWN:
|
||||
default:
|
||||
return BatteryLevel::Charging;
|
||||
return Common::Input::BatteryLevel::None;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,6 +352,8 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
|
||||
if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
|
||||
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||
SetButton(identifier, event.jbutton.button, true);
|
||||
// Battery doesn't trigger an event so just update every button press
|
||||
SetBattery(identifier, joystick->GetBatteryLevel());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -192,22 +192,22 @@ std::size_t UDPClient::GetClientNumber(std::string_view host, u16 port) const {
|
||||
return MAX_UDP_CLIENTS;
|
||||
}
|
||||
|
||||
BatteryLevel UDPClient::GetBatteryLevel(Response::Battery battery) const {
|
||||
Common::Input::BatteryLevel UDPClient::GetBatteryLevel(Response::Battery battery) const {
|
||||
switch (battery) {
|
||||
case Response::Battery::Dying:
|
||||
return BatteryLevel::Empty;
|
||||
return Common::Input::BatteryLevel::Empty;
|
||||
case Response::Battery::Low:
|
||||
return BatteryLevel::Critical;
|
||||
return Common::Input::BatteryLevel::Critical;
|
||||
case Response::Battery::Medium:
|
||||
return BatteryLevel::Low;
|
||||
return Common::Input::BatteryLevel::Low;
|
||||
case Response::Battery::High:
|
||||
return BatteryLevel::Medium;
|
||||
return Common::Input::BatteryLevel::Medium;
|
||||
case Response::Battery::Full:
|
||||
case Response::Battery::Charged:
|
||||
return BatteryLevel::Full;
|
||||
return Common::Input::BatteryLevel::Full;
|
||||
case Response::Battery::Charging:
|
||||
default:
|
||||
return BatteryLevel::Charging;
|
||||
return Common::Input::BatteryLevel::Charging;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) {
|
||||
const auto touch_axis_y_id =
|
||||
static_cast<int>(id == 0 ? PadAxes::Touch1Y : PadAxes::Touch2Y);
|
||||
const auto touch_button_id =
|
||||
static_cast<int>(id == 0 ? PadButton::Touch1 : PadButton::touch2);
|
||||
static_cast<int>(id == 0 ? PadButton::Touch1 : PadButton::Touch2);
|
||||
|
||||
// TODO: Use custom calibration per device
|
||||
const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
|
||||
@@ -319,6 +319,9 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) {
|
||||
SetButton(identifier, button, button_status);
|
||||
}
|
||||
|
||||
SetButton(identifier, static_cast<int>(PadButton::Home), data.home != 0);
|
||||
SetButton(identifier, static_cast<int>(PadButton::TouchHardPress), data.touch_hard_press != 0);
|
||||
|
||||
SetBattery(identifier, GetBatteryLevel(data.info.battery));
|
||||
}
|
||||
|
||||
@@ -393,7 +396,7 @@ std::vector<Common::ParamPackage> UDPClient::GetInputDevices() const {
|
||||
|
||||
ButtonMapping UDPClient::GetButtonMappingForDevice(const Common::ParamPackage& params) {
|
||||
// This list excludes any button that can't be really mapped
|
||||
static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 18>
|
||||
static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 20>
|
||||
switch_to_dsu_button = {
|
||||
std::pair{Settings::NativeButton::A, PadButton::Circle},
|
||||
{Settings::NativeButton::B, PadButton::Cross},
|
||||
@@ -413,6 +416,8 @@ ButtonMapping UDPClient::GetButtonMappingForDevice(const Common::ParamPackage& p
|
||||
{Settings::NativeButton::SR, PadButton::R2},
|
||||
{Settings::NativeButton::LStick, PadButton::L3},
|
||||
{Settings::NativeButton::RStick, PadButton::R3},
|
||||
{Settings::NativeButton::Home, PadButton::Home},
|
||||
{Settings::NativeButton::Screenshot, PadButton::TouchHardPress},
|
||||
};
|
||||
if (!params.Has("guid") || !params.Has("port") || !params.Has("pad")) {
|
||||
return {};
|
||||
@@ -517,6 +522,12 @@ Common::Input::ButtonNames UDPClient::GetUIButtonName(const Common::ParamPackage
|
||||
return Common::Input::ButtonNames::Share;
|
||||
case PadButton::Options:
|
||||
return Common::Input::ButtonNames::Options;
|
||||
case PadButton::Home:
|
||||
return Common::Input::ButtonNames::Home;
|
||||
case PadButton::Touch1:
|
||||
case PadButton::Touch2:
|
||||
case PadButton::TouchHardPress:
|
||||
return Common::Input::ButtonNames::Touch;
|
||||
default:
|
||||
return Common::Input::ButtonNames::Undefined;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,9 @@ private:
|
||||
Cross = 0x4000,
|
||||
Square = 0x8000,
|
||||
Touch1 = 0x10000,
|
||||
touch2 = 0x20000,
|
||||
Touch2 = 0x20000,
|
||||
Home = 0x40000,
|
||||
TouchHardPress = 0x80000,
|
||||
};
|
||||
|
||||
enum class PadAxes : u8 {
|
||||
@@ -139,7 +141,7 @@ private:
|
||||
std::size_t GetClientNumber(std::string_view host, u16 port) const;
|
||||
|
||||
// Translates UDP battery level to input engine battery level
|
||||
BatteryLevel GetBatteryLevel(Response::Battery battery) const;
|
||||
Common::Input::BatteryLevel GetBatteryLevel(Response::Battery battery) const;
|
||||
|
||||
void OnVersion(Response::Version);
|
||||
void OnPortInfo(Response::PortInfo);
|
||||
|
||||
@@ -167,12 +167,34 @@ public:
|
||||
}
|
||||
|
||||
void UpdateModButtonStatus(const Common::Input::CallbackStatus& button_callback) {
|
||||
modifier_status = button_callback.button_status.value;
|
||||
const auto& new_status = button_callback.button_status;
|
||||
const bool new_button_value = new_status.inverted ? !new_status.value : new_status.value;
|
||||
modifier_status.toggle = new_status.toggle;
|
||||
|
||||
// Update button status with current
|
||||
if (!modifier_status.toggle) {
|
||||
modifier_status.locked = false;
|
||||
if (modifier_status.value != new_button_value) {
|
||||
modifier_status.value = new_button_value;
|
||||
}
|
||||
} else {
|
||||
// Toggle button and lock status
|
||||
if (new_button_value && !modifier_status.locked) {
|
||||
modifier_status.locked = true;
|
||||
modifier_status.value = !modifier_status.value;
|
||||
}
|
||||
|
||||
// Unlock button ready for next press
|
||||
if (!new_button_value && modifier_status.locked) {
|
||||
modifier_status.locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
void UpdateStatus() {
|
||||
const float coef = modifier_status ? modifier_scale : 1.0f;
|
||||
const float coef = modifier_status.value ? modifier_scale : 1.0f;
|
||||
|
||||
bool r = right_status;
|
||||
bool l = left_status;
|
||||
@@ -266,7 +288,7 @@ public:
|
||||
if (down_status) {
|
||||
--y;
|
||||
}
|
||||
const float coef = modifier_status ? modifier_scale : 1.0f;
|
||||
const float coef = modifier_status.value ? modifier_scale : 1.0f;
|
||||
status.x.raw_value = static_cast<float>(x) * coef * (y == 0 ? 1.0f : SQRT_HALF);
|
||||
status.y.raw_value = static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF);
|
||||
return status;
|
||||
@@ -287,9 +309,9 @@ private:
|
||||
bool down_status{};
|
||||
bool left_status{};
|
||||
bool right_status{};
|
||||
bool modifier_status{};
|
||||
float last_x_axis_value{};
|
||||
float last_y_axis_value{};
|
||||
Common::Input::ButtonStatus modifier_status{};
|
||||
const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false};
|
||||
std::chrono::time_point<std::chrono::steady_clock> last_update;
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include "common/settings.h"
|
||||
#include "core/frontend/framebuffer_layout.h"
|
||||
#include "input_common/helpers/touch_from_buttons.h"
|
||||
|
||||
namespace InputCommon {
|
||||
|
||||
@@ -70,7 +70,7 @@ void InputEngine::SetAxis(const PadIdentifier& identifier, int axis, f32 value)
|
||||
TriggerOnAxisChange(identifier, axis, value);
|
||||
}
|
||||
|
||||
void InputEngine::SetBattery(const PadIdentifier& identifier, BatteryLevel value) {
|
||||
void InputEngine::SetBattery(const PadIdentifier& identifier, Common::Input::BatteryLevel value) {
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
ControllerData& controller = controller_list.at(identifier);
|
||||
@@ -143,13 +143,13 @@ f32 InputEngine::GetAxis(const PadIdentifier& identifier, int axis) const {
|
||||
return axis_iter->second;
|
||||
}
|
||||
|
||||
BatteryLevel InputEngine::GetBattery(const PadIdentifier& identifier) const {
|
||||
Common::Input::BatteryLevel InputEngine::GetBattery(const PadIdentifier& identifier) const {
|
||||
std::lock_guard lock{mutex};
|
||||
const auto controller_iter = controller_list.find(identifier);
|
||||
if (controller_iter == controller_list.cend()) {
|
||||
LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
|
||||
identifier.pad, identifier.port);
|
||||
return BatteryLevel::Charging;
|
||||
return Common::Input::BatteryLevel::Charging;
|
||||
}
|
||||
const ControllerData& controller = controller_iter->second;
|
||||
return controller.battery;
|
||||
@@ -270,7 +270,7 @@ void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis,
|
||||
}
|
||||
|
||||
void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,
|
||||
[[maybe_unused]] BatteryLevel value) {
|
||||
[[maybe_unused]] Common::Input::BatteryLevel value) {
|
||||
std::lock_guard lock{mutex_callback};
|
||||
for (const auto& poller_pair : callback_list) {
|
||||
const InputIdentifier& poller = poller_pair.second;
|
||||
|
||||
@@ -34,16 +34,6 @@ struct BasicMotion {
|
||||
u64 delta_timestamp{};
|
||||
};
|
||||
|
||||
// Stages of a battery charge
|
||||
enum class BatteryLevel {
|
||||
Empty,
|
||||
Critical,
|
||||
Low,
|
||||
Medium,
|
||||
Full,
|
||||
Charging,
|
||||
};
|
||||
|
||||
// Types of input that are stored in the engine
|
||||
enum class EngineInputType {
|
||||
None,
|
||||
@@ -178,7 +168,7 @@ public:
|
||||
bool GetButton(const PadIdentifier& identifier, int button) const;
|
||||
bool GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const;
|
||||
f32 GetAxis(const PadIdentifier& identifier, int axis) const;
|
||||
BatteryLevel GetBattery(const PadIdentifier& identifier) const;
|
||||
Common::Input::BatteryLevel GetBattery(const PadIdentifier& identifier) const;
|
||||
BasicMotion GetMotion(const PadIdentifier& identifier, int motion) const;
|
||||
|
||||
int SetCallback(InputIdentifier input_identifier);
|
||||
@@ -189,7 +179,7 @@ protected:
|
||||
void SetButton(const PadIdentifier& identifier, int button, bool value);
|
||||
void SetHatButton(const PadIdentifier& identifier, int button, u8 value);
|
||||
void SetAxis(const PadIdentifier& identifier, int axis, f32 value);
|
||||
void SetBattery(const PadIdentifier& identifier, BatteryLevel value);
|
||||
void SetBattery(const PadIdentifier& identifier, Common::Input::BatteryLevel value);
|
||||
void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value);
|
||||
|
||||
virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const {
|
||||
@@ -202,13 +192,13 @@ private:
|
||||
std::unordered_map<int, u8> hat_buttons;
|
||||
std::unordered_map<int, float> axes;
|
||||
std::unordered_map<int, BasicMotion> motions;
|
||||
BatteryLevel battery{};
|
||||
Common::Input::BatteryLevel battery{};
|
||||
};
|
||||
|
||||
void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value);
|
||||
void TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value);
|
||||
void TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value);
|
||||
void TriggerOnBatteryChange(const PadIdentifier& identifier, BatteryLevel value);
|
||||
void TriggerOnBatteryChange(const PadIdentifier& identifier, Common::Input::BatteryLevel value);
|
||||
void TriggerOnMotionChange(const PadIdentifier& identifier, int motion,
|
||||
const BasicMotion& value);
|
||||
|
||||
|
||||
@@ -470,7 +470,7 @@ public:
|
||||
}
|
||||
|
||||
Common::Input::BatteryStatus GetStatus() const {
|
||||
return static_cast<Common::Input::BatteryLevel>(input_engine->GetBattery(identifier));
|
||||
return input_engine->GetBattery(identifier);
|
||||
}
|
||||
|
||||
void ForceUpdate() override {
|
||||
|
||||
@@ -372,6 +372,8 @@ void EmitSharedAtomicExchange32(EmitContext& ctx, IR::Inst& inst, ScalarU32 poin
|
||||
ScalarU32 value);
|
||||
void EmitSharedAtomicExchange64(EmitContext& ctx, IR::Inst& inst, ScalarU32 pointer_offset,
|
||||
Register value);
|
||||
void EmitSharedAtomicExchange32x2(EmitContext& ctx, IR::Inst& inst, ScalarU32 pointer_offset,
|
||||
Register value);
|
||||
void EmitStorageAtomicIAdd32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
ScalarU32 offset, ScalarU32 value);
|
||||
void EmitStorageAtomicSMin32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
@@ -412,6 +414,24 @@ void EmitStorageAtomicXor64(EmitContext& ctx, IR::Inst& inst, const IR::Value& b
|
||||
ScalarU32 offset, Register value);
|
||||
void EmitStorageAtomicExchange64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
ScalarU32 offset, Register value);
|
||||
void EmitStorageAtomicIAdd32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
ScalarU32 offset, Register value);
|
||||
void EmitStorageAtomicSMin32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
ScalarU32 offset, Register value);
|
||||
void EmitStorageAtomicUMin32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
ScalarU32 offset, Register value);
|
||||
void EmitStorageAtomicSMax32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
ScalarU32 offset, Register value);
|
||||
void EmitStorageAtomicUMax32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
ScalarU32 offset, Register value);
|
||||
void EmitStorageAtomicAnd32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
ScalarU32 offset, Register value);
|
||||
void EmitStorageAtomicOr32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
ScalarU32 offset, Register value);
|
||||
void EmitStorageAtomicXor32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
ScalarU32 offset, Register value);
|
||||
void EmitStorageAtomicExchange32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
ScalarU32 offset, Register value);
|
||||
void EmitStorageAtomicAddF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
ScalarU32 offset, ScalarF32 value);
|
||||
void EmitStorageAtomicAddF16x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
@@ -448,6 +468,17 @@ void EmitGlobalAtomicAnd64(EmitContext& ctx);
|
||||
void EmitGlobalAtomicOr64(EmitContext& ctx);
|
||||
void EmitGlobalAtomicXor64(EmitContext& ctx);
|
||||
void EmitGlobalAtomicExchange64(EmitContext& ctx);
|
||||
void EmitGlobalAtomicIAdd32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicSMin32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicUMin32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicSMax32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicUMax32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicInc32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicDec32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicAnd32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicOr32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicXor32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicExchange32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicAddF32(EmitContext& ctx);
|
||||
void EmitGlobalAtomicAddF16x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicAddF32x2(EmitContext& ctx);
|
||||
|
||||
@@ -311,6 +311,13 @@ void EmitSharedAtomicExchange64(EmitContext& ctx, IR::Inst& inst, ScalarU32 poin
|
||||
ctx.LongAdd("ATOMS.EXCH.U64 {}.x,{},shared_mem[{}];", inst, value, pointer_offset);
|
||||
}
|
||||
|
||||
void EmitSharedAtomicExchange32x2([[maybe_unused]] EmitContext& ctx,
|
||||
[[maybe_unused]] IR::Inst& inst,
|
||||
[[maybe_unused]] ScalarU32 pointer_offset,
|
||||
[[maybe_unused]] Register value) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitStorageAtomicIAdd32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
ScalarU32 offset, ScalarU32 value) {
|
||||
Atom(ctx, inst, binding, offset, value, "ADD", "U32");
|
||||
@@ -411,6 +418,62 @@ void EmitStorageAtomicExchange64(EmitContext& ctx, IR::Inst& inst, const IR::Val
|
||||
Atom(ctx, inst, binding, offset, value, "EXCH", "U64");
|
||||
}
|
||||
|
||||
void EmitStorageAtomicIAdd32x2([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||
[[maybe_unused]] const IR::Value& binding,
|
||||
[[maybe_unused]] ScalarU32 offset, [[maybe_unused]] Register value) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitStorageAtomicSMin32x2([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||
[[maybe_unused]] const IR::Value& binding,
|
||||
[[maybe_unused]] ScalarU32 offset, [[maybe_unused]] Register value) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitStorageAtomicUMin32x2([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||
[[maybe_unused]] const IR::Value& binding,
|
||||
[[maybe_unused]] ScalarU32 offset, [[maybe_unused]] Register value) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitStorageAtomicSMax32x2([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||
[[maybe_unused]] const IR::Value& binding,
|
||||
[[maybe_unused]] ScalarU32 offset, [[maybe_unused]] Register value) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitStorageAtomicUMax32x2([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||
[[maybe_unused]] const IR::Value& binding,
|
||||
[[maybe_unused]] ScalarU32 offset, [[maybe_unused]] Register value) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitStorageAtomicAnd32x2([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||
[[maybe_unused]] const IR::Value& binding,
|
||||
[[maybe_unused]] ScalarU32 offset, [[maybe_unused]] Register value) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitStorageAtomicOr32x2([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||
[[maybe_unused]] const IR::Value& binding,
|
||||
[[maybe_unused]] ScalarU32 offset, [[maybe_unused]] Register value) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitStorageAtomicXor32x2([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||
[[maybe_unused]] const IR::Value& binding,
|
||||
[[maybe_unused]] ScalarU32 offset, [[maybe_unused]] Register value) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitStorageAtomicExchange32x2([[maybe_unused]] EmitContext& ctx,
|
||||
[[maybe_unused]] IR::Inst& inst,
|
||||
[[maybe_unused]] const IR::Value& binding,
|
||||
[[maybe_unused]] ScalarU32 offset,
|
||||
[[maybe_unused]] Register value) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitStorageAtomicAddF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
ScalarU32 offset, ScalarF32 value) {
|
||||
Atom(ctx, inst, binding, offset, value, "ADD", "F32");
|
||||
@@ -537,6 +600,50 @@ void EmitGlobalAtomicExchange64(EmitContext&) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicIAdd32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicSMin32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicUMin32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicSMax32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicUMax32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicInc32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicDec32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicAnd32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicOr32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicXor32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicExchange32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicAddF32(EmitContext&) {
|
||||
throw NotImplementedException("GLASM instruction");
|
||||
}
|
||||
|
||||
@@ -105,6 +105,13 @@ void EmitSharedAtomicExchange64(EmitContext& ctx, IR::Inst& inst, std::string_vi
|
||||
pointer_offset, value, pointer_offset, value);
|
||||
}
|
||||
|
||||
void EmitSharedAtomicExchange32x2(EmitContext& ctx, IR::Inst& inst, std::string_view pointer_offset,
|
||||
std::string_view value) {
|
||||
LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to non-atomic");
|
||||
ctx.AddU32x2("{}=uvec2(smem[{}>>2],smem[({}+4)>>2]);", inst, pointer_offset, pointer_offset);
|
||||
ctx.Add("smem[{}>>2]={}.x;smem[({}+4)>>2]={}.y;", pointer_offset, value, pointer_offset, value);
|
||||
}
|
||||
|
||||
void EmitStorageAtomicIAdd32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value) {
|
||||
ctx.AddU32("{}=atomicAdd({}_ssbo{}[{}>>2],{});", inst, ctx.stage_name, binding.U32(),
|
||||
@@ -265,6 +272,97 @@ void EmitStorageAtomicExchange64(EmitContext& ctx, IR::Inst& inst, const IR::Val
|
||||
ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value);
|
||||
}
|
||||
|
||||
void EmitStorageAtomicIAdd32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value) {
|
||||
LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to non-atomic");
|
||||
ctx.AddU32x2("{}=uvec2({}_ssbo{}[{}>>2],{}_ssbo{}[({}>>2)+1]);", inst, ctx.stage_name,
|
||||
binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name, binding.U32(),
|
||||
ctx.var_alloc.Consume(offset));
|
||||
ctx.Add("{}_ssbo{}[{}>>2]+={}.x;{}_ssbo{}[({}>>2)+1]+={}.y;", ctx.stage_name, binding.U32(),
|
||||
ctx.var_alloc.Consume(offset), value, ctx.stage_name, binding.U32(),
|
||||
ctx.var_alloc.Consume(offset), value);
|
||||
}
|
||||
|
||||
void EmitStorageAtomicSMin32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value) {
|
||||
LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to non-atomic");
|
||||
ctx.AddU32x2("{}=ivec2({}_ssbo{}[{}>>2],{}_ssbo{}[({}>>2)+1]);", inst, ctx.stage_name,
|
||||
binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name, binding.U32(),
|
||||
ctx.var_alloc.Consume(offset));
|
||||
ctx.Add("for(int "
|
||||
"i=0;i<2;++i){{{}_ssbo{}[({}>>2)+i]=uint(min(int({}_ssbo{}[({}>>2)+i]),int({}[i])));}}",
|
||||
ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name,
|
||||
binding.U32(), ctx.var_alloc.Consume(offset), value);
|
||||
}
|
||||
|
||||
void EmitStorageAtomicUMin32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value) {
|
||||
LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to non-atomic");
|
||||
ctx.AddU32x2("{}=uvec2({}_ssbo{}[{}>>2],{}_ssbo{}[({}>>2)+1]);", inst, ctx.stage_name,
|
||||
binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name, binding.U32(),
|
||||
ctx.var_alloc.Consume(offset));
|
||||
ctx.Add("for(int i=0;i<2;++i){{ "
|
||||
"{}_ssbo{}[({}>>2)+i]=min({}_ssbo{}[({}>>2)+i],{}[i]);}}",
|
||||
ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name,
|
||||
binding.U32(), ctx.var_alloc.Consume(offset), value);
|
||||
}
|
||||
|
||||
void EmitStorageAtomicSMax32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value) {
|
||||
LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to non-atomic");
|
||||
ctx.AddU32x2("{}=ivec2({}_ssbo{}[{}>>2],{}_ssbo{}[({}>>2)+1]);", inst, ctx.stage_name,
|
||||
binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name, binding.U32(),
|
||||
ctx.var_alloc.Consume(offset));
|
||||
ctx.Add("for(int "
|
||||
"i=0;i<2;++i){{{}_ssbo{}[({}>>2)+i]=uint(max(int({}_ssbo{}[({}>>2)+i]),int({}[i])));}}",
|
||||
ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name,
|
||||
binding.U32(), ctx.var_alloc.Consume(offset), value);
|
||||
}
|
||||
|
||||
void EmitStorageAtomicUMax32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value) {
|
||||
LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to non-atomic");
|
||||
ctx.AddU32x2("{}=uvec2({}_ssbo{}[{}>>2],{}_ssbo{}[({}>>2)+1]);", inst, ctx.stage_name,
|
||||
binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name, binding.U32(),
|
||||
ctx.var_alloc.Consume(offset));
|
||||
ctx.Add("for(int i=0;i<2;++i){{{}_ssbo{}[({}>>2)+i]=max({}_ssbo{}[({}>>2)+i],{}[i]);}}",
|
||||
ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name,
|
||||
binding.U32(), ctx.var_alloc.Consume(offset), value);
|
||||
}
|
||||
|
||||
void EmitStorageAtomicAnd32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value) {
|
||||
LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to 32x2");
|
||||
ctx.AddU32x2("{}=uvec2(atomicAnd({}_ssbo{}[{}>>2],{}.x),atomicAnd({}_ssbo{}[({}>>2)+1],{}.y));",
|
||||
inst, ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value,
|
||||
ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value);
|
||||
}
|
||||
|
||||
void EmitStorageAtomicOr32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value) {
|
||||
LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to 32x2");
|
||||
ctx.AddU32x2("{}=uvec2(atomicOr({}_ssbo{}[{}>>2],{}.x),atomicOr({}_ssbo{}[({}>>2)+1],{}.y));",
|
||||
inst, ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value,
|
||||
ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value);
|
||||
}
|
||||
|
||||
void EmitStorageAtomicXor32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value) {
|
||||
LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to 32x2");
|
||||
ctx.AddU32x2("{}=uvec2(atomicXor({}_ssbo{}[{}>>2],{}.x),atomicXor({}_ssbo{}[({}>>2)+1],{}.y));",
|
||||
inst, ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value,
|
||||
ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value);
|
||||
}
|
||||
|
||||
void EmitStorageAtomicExchange32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value) {
|
||||
LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to 32x2");
|
||||
ctx.AddU32x2("{}=uvec2(atomicExchange({}_ssbo{}[{}>>2],{}.x),atomicExchange({}_ssbo{}[({}>>2)+"
|
||||
"1],{}.y));",
|
||||
inst, ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value,
|
||||
ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value);
|
||||
}
|
||||
|
||||
void EmitStorageAtomicAddF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value) {
|
||||
SsboCasFunctionF32(ctx, inst, binding, offset, value, "CasFloatAdd");
|
||||
@@ -388,6 +486,50 @@ void EmitGlobalAtomicExchange64(EmitContext&) {
|
||||
throw NotImplementedException("GLSL Instrucion");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicIAdd32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLSL Instrucion");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicSMin32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLSL Instrucion");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicUMin32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLSL Instrucion");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicSMax32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLSL Instrucion");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicUMax32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLSL Instrucion");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicInc32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLSL Instrucion");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicDec32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLSL Instrucion");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicAnd32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLSL Instrucion");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicOr32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLSL Instrucion");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicXor32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLSL Instrucion");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicExchange32x2(EmitContext&) {
|
||||
throw NotImplementedException("GLSL Instrucion");
|
||||
}
|
||||
|
||||
void EmitGlobalAtomicAddF32(EmitContext&) {
|
||||
throw NotImplementedException("GLSL Instrucion");
|
||||
}
|
||||
|
||||
@@ -442,6 +442,8 @@ void EmitSharedAtomicExchange32(EmitContext& ctx, IR::Inst& inst, std::string_vi
|
||||
std::string_view value);
|
||||
void EmitSharedAtomicExchange64(EmitContext& ctx, IR::Inst& inst, std::string_view pointer_offset,
|
||||
std::string_view value);
|
||||
void EmitSharedAtomicExchange32x2(EmitContext& ctx, IR::Inst& inst, std::string_view pointer_offset,
|
||||
std::string_view value);
|
||||
void EmitStorageAtomicIAdd32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value);
|
||||
void EmitStorageAtomicSMin32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
@@ -482,6 +484,24 @@ void EmitStorageAtomicXor64(EmitContext& ctx, IR::Inst& inst, const IR::Value& b
|
||||
const IR::Value& offset, std::string_view value);
|
||||
void EmitStorageAtomicExchange64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value);
|
||||
void EmitStorageAtomicIAdd32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value);
|
||||
void EmitStorageAtomicSMin32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value);
|
||||
void EmitStorageAtomicUMin32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value);
|
||||
void EmitStorageAtomicSMax32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value);
|
||||
void EmitStorageAtomicUMax32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value);
|
||||
void EmitStorageAtomicAnd32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value);
|
||||
void EmitStorageAtomicOr32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value);
|
||||
void EmitStorageAtomicXor32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value);
|
||||
void EmitStorageAtomicExchange32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value);
|
||||
void EmitStorageAtomicAddF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
const IR::Value& offset, std::string_view value);
|
||||
void EmitStorageAtomicAddF16x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
@@ -518,6 +538,17 @@ void EmitGlobalAtomicAnd64(EmitContext& ctx);
|
||||
void EmitGlobalAtomicOr64(EmitContext& ctx);
|
||||
void EmitGlobalAtomicXor64(EmitContext& ctx);
|
||||
void EmitGlobalAtomicExchange64(EmitContext& ctx);
|
||||
void EmitGlobalAtomicIAdd32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicSMin32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicUMin32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicSMax32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicUMax32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicInc32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicDec32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicAnd32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicOr32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicXor32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicExchange32x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicAddF32(EmitContext& ctx);
|
||||
void EmitGlobalAtomicAddF16x2(EmitContext& ctx);
|
||||
void EmitGlobalAtomicAddF32x2(EmitContext& ctx);
|
||||
|
||||
@@ -82,6 +82,17 @@ Id StorageAtomicU64(EmitContext& ctx, const IR::Value& binding, const IR::Value&
|
||||
ctx.OpStore(pointer, ctx.OpBitcast(ctx.U32[2], result));
|
||||
return original_value;
|
||||
}
|
||||
|
||||
Id StorageAtomicU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value,
|
||||
Id (Sirit::Module::*non_atomic_func)(Id, Id, Id)) {
|
||||
LOG_WARNING(Shader_SPIRV, "Int64 atomics not supported, fallback to non-atomic");
|
||||
const Id pointer{StoragePointer(ctx, ctx.storage_types.U32x2, &StorageDefinitions::U32x2,
|
||||
binding, offset, sizeof(u32[2]))};
|
||||
const Id original_value{ctx.OpLoad(ctx.U32[2], pointer)};
|
||||
const Id result{(ctx.*non_atomic_func)(ctx.U32[2], value, original_value)};
|
||||
ctx.OpStore(pointer, result);
|
||||
return original_value;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
Id EmitSharedAtomicIAdd32(EmitContext& ctx, Id offset, Id value) {
|
||||
@@ -141,7 +152,7 @@ Id EmitSharedAtomicExchange64(EmitContext& ctx, Id offset, Id value) {
|
||||
const auto [scope, semantics]{AtomicArgs(ctx)};
|
||||
return ctx.OpAtomicExchange(ctx.U64, pointer, scope, semantics, value);
|
||||
}
|
||||
LOG_ERROR(Shader_SPIRV, "Int64 atomics not supported, fallback to non-atomic");
|
||||
LOG_WARNING(Shader_SPIRV, "Int64 atomics not supported, fallback to non-atomic");
|
||||
const Id pointer_1{SharedPointer(ctx, offset, 0)};
|
||||
const Id pointer_2{SharedPointer(ctx, offset, 1)};
|
||||
const Id value_1{ctx.OpLoad(ctx.U32[1], pointer_1)};
|
||||
@@ -152,6 +163,18 @@ Id EmitSharedAtomicExchange64(EmitContext& ctx, Id offset, Id value) {
|
||||
return ctx.OpBitcast(ctx.U64, ctx.OpCompositeConstruct(ctx.U32[2], value_1, value_2));
|
||||
}
|
||||
|
||||
Id EmitSharedAtomicExchange32x2(EmitContext& ctx, Id offset, Id value) {
|
||||
LOG_WARNING(Shader_SPIRV, "Int64 atomics not supported, fallback to non-atomic");
|
||||
const Id pointer_1{SharedPointer(ctx, offset, 0)};
|
||||
const Id pointer_2{SharedPointer(ctx, offset, 1)};
|
||||
const Id value_1{ctx.OpLoad(ctx.U32[1], pointer_1)};
|
||||
const Id value_2{ctx.OpLoad(ctx.U32[1], pointer_2)};
|
||||
const Id new_vector{ctx.OpBitcast(ctx.U32[2], value)};
|
||||
ctx.OpStore(pointer_1, ctx.OpCompositeExtract(ctx.U32[1], new_vector, 0U));
|
||||
ctx.OpStore(pointer_2, ctx.OpCompositeExtract(ctx.U32[1], new_vector, 1U));
|
||||
return ctx.OpCompositeConstruct(ctx.U32[2], value_1, value_2);
|
||||
}
|
||||
|
||||
Id EmitStorageAtomicIAdd32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value) {
|
||||
return StorageAtomicU32(ctx, binding, offset, value, &Sirit::Module::OpAtomicIAdd);
|
||||
@@ -275,6 +298,56 @@ Id EmitStorageAtomicExchange64(EmitContext& ctx, const IR::Value& binding, const
|
||||
return original;
|
||||
}
|
||||
|
||||
Id EmitStorageAtomicIAdd32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value) {
|
||||
return StorageAtomicU32x2(ctx, binding, offset, value, &Sirit::Module::OpIAdd);
|
||||
}
|
||||
|
||||
Id EmitStorageAtomicSMin32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value) {
|
||||
return StorageAtomicU32x2(ctx, binding, offset, value, &Sirit::Module::OpSMin);
|
||||
}
|
||||
|
||||
Id EmitStorageAtomicUMin32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value) {
|
||||
return StorageAtomicU32x2(ctx, binding, offset, value, &Sirit::Module::OpUMin);
|
||||
}
|
||||
|
||||
Id EmitStorageAtomicSMax32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value) {
|
||||
return StorageAtomicU32x2(ctx, binding, offset, value, &Sirit::Module::OpSMax);
|
||||
}
|
||||
|
||||
Id EmitStorageAtomicUMax32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value) {
|
||||
return StorageAtomicU32x2(ctx, binding, offset, value, &Sirit::Module::OpUMax);
|
||||
}
|
||||
|
||||
Id EmitStorageAtomicAnd32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value) {
|
||||
return StorageAtomicU32x2(ctx, binding, offset, value, &Sirit::Module::OpBitwiseAnd);
|
||||
}
|
||||
|
||||
Id EmitStorageAtomicOr32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value) {
|
||||
return StorageAtomicU32x2(ctx, binding, offset, value, &Sirit::Module::OpBitwiseOr);
|
||||
}
|
||||
|
||||
Id EmitStorageAtomicXor32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value) {
|
||||
return StorageAtomicU32x2(ctx, binding, offset, value, &Sirit::Module::OpBitwiseXor);
|
||||
}
|
||||
|
||||
Id EmitStorageAtomicExchange32x2(EmitContext& ctx, const IR::Value& binding,
|
||||
const IR::Value& offset, Id value) {
|
||||
LOG_WARNING(Shader_SPIRV, "Int64 atomics not supported, fallback to non-atomic");
|
||||
const Id pointer{StoragePointer(ctx, ctx.storage_types.U32x2, &StorageDefinitions::U32x2,
|
||||
binding, offset, sizeof(u32[2]))};
|
||||
const Id original{ctx.OpLoad(ctx.U32[2], pointer)};
|
||||
ctx.OpStore(pointer, value);
|
||||
return original;
|
||||
}
|
||||
|
||||
Id EmitStorageAtomicAddF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value) {
|
||||
const Id ssbo{ctx.ssbos[binding.U32()].U32};
|
||||
@@ -418,6 +491,50 @@ Id EmitGlobalAtomicExchange64(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitGlobalAtomicIAdd32x2(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitGlobalAtomicSMin32x2(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitGlobalAtomicUMin32x2(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitGlobalAtomicSMax32x2(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitGlobalAtomicUMax32x2(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitGlobalAtomicInc32x2(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitGlobalAtomicDec32x2(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitGlobalAtomicAnd32x2(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitGlobalAtomicOr32x2(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitGlobalAtomicXor32x2(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitGlobalAtomicExchange32x2(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitGlobalAtomicAddF32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
@@ -335,6 +335,7 @@ Id EmitSharedAtomicOr32(EmitContext& ctx, Id pointer_offset, Id value);
|
||||
Id EmitSharedAtomicXor32(EmitContext& ctx, Id pointer_offset, Id value);
|
||||
Id EmitSharedAtomicExchange32(EmitContext& ctx, Id pointer_offset, Id value);
|
||||
Id EmitSharedAtomicExchange64(EmitContext& ctx, Id pointer_offset, Id value);
|
||||
Id EmitSharedAtomicExchange32x2(EmitContext& ctx, Id pointer_offset, Id value);
|
||||
Id EmitStorageAtomicIAdd32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value);
|
||||
Id EmitStorageAtomicSMin32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
@@ -375,6 +376,24 @@ Id EmitStorageAtomicXor64(EmitContext& ctx, const IR::Value& binding, const IR::
|
||||
Id value);
|
||||
Id EmitStorageAtomicExchange64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value);
|
||||
Id EmitStorageAtomicIAdd32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value);
|
||||
Id EmitStorageAtomicSMin32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value);
|
||||
Id EmitStorageAtomicUMin32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value);
|
||||
Id EmitStorageAtomicSMax32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value);
|
||||
Id EmitStorageAtomicUMax32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value);
|
||||
Id EmitStorageAtomicAnd32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value);
|
||||
Id EmitStorageAtomicOr32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value);
|
||||
Id EmitStorageAtomicXor32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value);
|
||||
Id EmitStorageAtomicExchange32x2(EmitContext& ctx, const IR::Value& binding,
|
||||
const IR::Value& offset, Id value);
|
||||
Id EmitStorageAtomicAddF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value);
|
||||
Id EmitStorageAtomicAddF16x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
@@ -411,6 +430,17 @@ Id EmitGlobalAtomicAnd64(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicOr64(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicXor64(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicExchange64(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicIAdd32x2(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicSMin32x2(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicUMin32x2(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicSMax32x2(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicUMax32x2(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicInc32x2(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicDec32x2(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicAnd32x2(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicOr32x2(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicXor32x2(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicExchange32x2(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicAddF32(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicAddF16x2(EmitContext& ctx);
|
||||
Id EmitGlobalAtomicAddF32x2(EmitContext& ctx);
|
||||
|
||||
@@ -118,6 +118,7 @@ bool Inst::MayHaveSideEffects() const noexcept {
|
||||
case Opcode::SharedAtomicXor32:
|
||||
case Opcode::SharedAtomicExchange32:
|
||||
case Opcode::SharedAtomicExchange64:
|
||||
case Opcode::SharedAtomicExchange32x2:
|
||||
case Opcode::GlobalAtomicIAdd32:
|
||||
case Opcode::GlobalAtomicSMin32:
|
||||
case Opcode::GlobalAtomicUMin32:
|
||||
@@ -138,6 +139,15 @@ bool Inst::MayHaveSideEffects() const noexcept {
|
||||
case Opcode::GlobalAtomicOr64:
|
||||
case Opcode::GlobalAtomicXor64:
|
||||
case Opcode::GlobalAtomicExchange64:
|
||||
case Opcode::GlobalAtomicIAdd32x2:
|
||||
case Opcode::GlobalAtomicSMin32x2:
|
||||
case Opcode::GlobalAtomicUMin32x2:
|
||||
case Opcode::GlobalAtomicSMax32x2:
|
||||
case Opcode::GlobalAtomicUMax32x2:
|
||||
case Opcode::GlobalAtomicAnd32x2:
|
||||
case Opcode::GlobalAtomicOr32x2:
|
||||
case Opcode::GlobalAtomicXor32x2:
|
||||
case Opcode::GlobalAtomicExchange32x2:
|
||||
case Opcode::GlobalAtomicAddF32:
|
||||
case Opcode::GlobalAtomicAddF16x2:
|
||||
case Opcode::GlobalAtomicAddF32x2:
|
||||
@@ -165,6 +175,15 @@ bool Inst::MayHaveSideEffects() const noexcept {
|
||||
case Opcode::StorageAtomicOr64:
|
||||
case Opcode::StorageAtomicXor64:
|
||||
case Opcode::StorageAtomicExchange64:
|
||||
case Opcode::StorageAtomicIAdd32x2:
|
||||
case Opcode::StorageAtomicSMin32x2:
|
||||
case Opcode::StorageAtomicUMin32x2:
|
||||
case Opcode::StorageAtomicSMax32x2:
|
||||
case Opcode::StorageAtomicUMax32x2:
|
||||
case Opcode::StorageAtomicAnd32x2:
|
||||
case Opcode::StorageAtomicOr32x2:
|
||||
case Opcode::StorageAtomicXor32x2:
|
||||
case Opcode::StorageAtomicExchange32x2:
|
||||
case Opcode::StorageAtomicAddF32:
|
||||
case Opcode::StorageAtomicAddF16x2:
|
||||
case Opcode::StorageAtomicAddF32x2:
|
||||
|
||||
@@ -341,6 +341,7 @@ OPCODE(SharedAtomicOr32, U32, U32,
|
||||
OPCODE(SharedAtomicXor32, U32, U32, U32, )
|
||||
OPCODE(SharedAtomicExchange32, U32, U32, U32, )
|
||||
OPCODE(SharedAtomicExchange64, U64, U32, U64, )
|
||||
OPCODE(SharedAtomicExchange32x2, U32x2, U32, U32x2, )
|
||||
|
||||
OPCODE(GlobalAtomicIAdd32, U32, U64, U32, )
|
||||
OPCODE(GlobalAtomicSMin32, U32, U64, U32, )
|
||||
@@ -362,6 +363,15 @@ OPCODE(GlobalAtomicAnd64, U64, U64,
|
||||
OPCODE(GlobalAtomicOr64, U64, U64, U64, )
|
||||
OPCODE(GlobalAtomicXor64, U64, U64, U64, )
|
||||
OPCODE(GlobalAtomicExchange64, U64, U64, U64, )
|
||||
OPCODE(GlobalAtomicIAdd32x2, U32x2, U32x2, U32x2, )
|
||||
OPCODE(GlobalAtomicSMin32x2, U32x2, U32x2, U32x2, )
|
||||
OPCODE(GlobalAtomicUMin32x2, U32x2, U32x2, U32x2, )
|
||||
OPCODE(GlobalAtomicSMax32x2, U32x2, U32x2, U32x2, )
|
||||
OPCODE(GlobalAtomicUMax32x2, U32x2, U32x2, U32x2, )
|
||||
OPCODE(GlobalAtomicAnd32x2, U32x2, U32x2, U32x2, )
|
||||
OPCODE(GlobalAtomicOr32x2, U32x2, U32x2, U32x2, )
|
||||
OPCODE(GlobalAtomicXor32x2, U32x2, U32x2, U32x2, )
|
||||
OPCODE(GlobalAtomicExchange32x2, U32x2, U32x2, U32x2, )
|
||||
OPCODE(GlobalAtomicAddF32, F32, U64, F32, )
|
||||
OPCODE(GlobalAtomicAddF16x2, U32, U64, F16x2, )
|
||||
OPCODE(GlobalAtomicAddF32x2, U32, U64, F32x2, )
|
||||
@@ -390,6 +400,15 @@ OPCODE(StorageAtomicAnd64, U64, U32,
|
||||
OPCODE(StorageAtomicOr64, U64, U32, U32, U64, )
|
||||
OPCODE(StorageAtomicXor64, U64, U32, U32, U64, )
|
||||
OPCODE(StorageAtomicExchange64, U64, U32, U32, U64, )
|
||||
OPCODE(StorageAtomicIAdd32x2, U32x2, U32, U32, U32x2, )
|
||||
OPCODE(StorageAtomicSMin32x2, U32x2, U32, U32, U32x2, )
|
||||
OPCODE(StorageAtomicUMin32x2, U32x2, U32, U32, U32x2, )
|
||||
OPCODE(StorageAtomicSMax32x2, U32x2, U32, U32, U32x2, )
|
||||
OPCODE(StorageAtomicUMax32x2, U32x2, U32, U32, U32x2, )
|
||||
OPCODE(StorageAtomicAnd32x2, U32x2, U32, U32, U32x2, )
|
||||
OPCODE(StorageAtomicOr32x2, U32x2, U32, U32, U32x2, )
|
||||
OPCODE(StorageAtomicXor32x2, U32x2, U32, U32, U32x2, )
|
||||
OPCODE(StorageAtomicExchange32x2, U32x2, U32, U32, U32x2, )
|
||||
OPCODE(StorageAtomicAddF32, F32, U32, U32, F32, )
|
||||
OPCODE(StorageAtomicAddF16x2, U32, U32, U32, F16x2, )
|
||||
OPCODE(StorageAtomicAddF32x2, U32, U32, U32, F32x2, )
|
||||
|
||||
@@ -360,6 +360,15 @@ void VisitUsages(Info& info, IR::Inst& inst) {
|
||||
case IR::Opcode::GlobalAtomicOr64:
|
||||
case IR::Opcode::GlobalAtomicXor64:
|
||||
case IR::Opcode::GlobalAtomicExchange64:
|
||||
case IR::Opcode::GlobalAtomicIAdd32x2:
|
||||
case IR::Opcode::GlobalAtomicSMin32x2:
|
||||
case IR::Opcode::GlobalAtomicUMin32x2:
|
||||
case IR::Opcode::GlobalAtomicSMax32x2:
|
||||
case IR::Opcode::GlobalAtomicUMax32x2:
|
||||
case IR::Opcode::GlobalAtomicAnd32x2:
|
||||
case IR::Opcode::GlobalAtomicOr32x2:
|
||||
case IR::Opcode::GlobalAtomicXor32x2:
|
||||
case IR::Opcode::GlobalAtomicExchange32x2:
|
||||
case IR::Opcode::GlobalAtomicAddF32:
|
||||
case IR::Opcode::GlobalAtomicAddF16x2:
|
||||
case IR::Opcode::GlobalAtomicAddF32x2:
|
||||
@@ -597,6 +606,15 @@ void VisitUsages(Info& info, IR::Inst& inst) {
|
||||
break;
|
||||
case IR::Opcode::LoadStorage64:
|
||||
case IR::Opcode::WriteStorage64:
|
||||
case IR::Opcode::StorageAtomicIAdd32x2:
|
||||
case IR::Opcode::StorageAtomicSMin32x2:
|
||||
case IR::Opcode::StorageAtomicUMin32x2:
|
||||
case IR::Opcode::StorageAtomicSMax32x2:
|
||||
case IR::Opcode::StorageAtomicUMax32x2:
|
||||
case IR::Opcode::StorageAtomicAnd32x2:
|
||||
case IR::Opcode::StorageAtomicOr32x2:
|
||||
case IR::Opcode::StorageAtomicXor32x2:
|
||||
case IR::Opcode::StorageAtomicExchange32x2:
|
||||
info.used_storage_buffer_types |= IR::Type::U32x2;
|
||||
break;
|
||||
case IR::Opcode::LoadStorage128:
|
||||
|
||||
@@ -92,6 +92,15 @@ bool IsGlobalMemory(const IR::Inst& inst) {
|
||||
case IR::Opcode::GlobalAtomicOr64:
|
||||
case IR::Opcode::GlobalAtomicXor64:
|
||||
case IR::Opcode::GlobalAtomicExchange64:
|
||||
case IR::Opcode::GlobalAtomicIAdd32x2:
|
||||
case IR::Opcode::GlobalAtomicSMin32x2:
|
||||
case IR::Opcode::GlobalAtomicUMin32x2:
|
||||
case IR::Opcode::GlobalAtomicSMax32x2:
|
||||
case IR::Opcode::GlobalAtomicUMax32x2:
|
||||
case IR::Opcode::GlobalAtomicAnd32x2:
|
||||
case IR::Opcode::GlobalAtomicOr32x2:
|
||||
case IR::Opcode::GlobalAtomicXor32x2:
|
||||
case IR::Opcode::GlobalAtomicExchange32x2:
|
||||
case IR::Opcode::GlobalAtomicAddF32:
|
||||
case IR::Opcode::GlobalAtomicAddF16x2:
|
||||
case IR::Opcode::GlobalAtomicAddF32x2:
|
||||
@@ -135,6 +144,15 @@ bool IsGlobalMemoryWrite(const IR::Inst& inst) {
|
||||
case IR::Opcode::GlobalAtomicOr64:
|
||||
case IR::Opcode::GlobalAtomicXor64:
|
||||
case IR::Opcode::GlobalAtomicExchange64:
|
||||
case IR::Opcode::GlobalAtomicIAdd32x2:
|
||||
case IR::Opcode::GlobalAtomicSMin32x2:
|
||||
case IR::Opcode::GlobalAtomicUMin32x2:
|
||||
case IR::Opcode::GlobalAtomicSMax32x2:
|
||||
case IR::Opcode::GlobalAtomicUMax32x2:
|
||||
case IR::Opcode::GlobalAtomicAnd32x2:
|
||||
case IR::Opcode::GlobalAtomicOr32x2:
|
||||
case IR::Opcode::GlobalAtomicXor32x2:
|
||||
case IR::Opcode::GlobalAtomicExchange32x2:
|
||||
case IR::Opcode::GlobalAtomicAddF32:
|
||||
case IR::Opcode::GlobalAtomicAddF16x2:
|
||||
case IR::Opcode::GlobalAtomicAddF32x2:
|
||||
@@ -199,6 +217,8 @@ IR::Opcode GlobalToStorage(IR::Opcode opcode) {
|
||||
return IR::Opcode::StorageAtomicOr32;
|
||||
case IR::Opcode::GlobalAtomicXor32:
|
||||
return IR::Opcode::StorageAtomicXor32;
|
||||
case IR::Opcode::GlobalAtomicExchange32:
|
||||
return IR::Opcode::StorageAtomicExchange32;
|
||||
case IR::Opcode::GlobalAtomicIAdd64:
|
||||
return IR::Opcode::StorageAtomicIAdd64;
|
||||
case IR::Opcode::GlobalAtomicSMin64:
|
||||
@@ -215,10 +235,26 @@ IR::Opcode GlobalToStorage(IR::Opcode opcode) {
|
||||
return IR::Opcode::StorageAtomicOr64;
|
||||
case IR::Opcode::GlobalAtomicXor64:
|
||||
return IR::Opcode::StorageAtomicXor64;
|
||||
case IR::Opcode::GlobalAtomicExchange32:
|
||||
return IR::Opcode::StorageAtomicExchange32;
|
||||
case IR::Opcode::GlobalAtomicExchange64:
|
||||
return IR::Opcode::StorageAtomicExchange64;
|
||||
case IR::Opcode::GlobalAtomicIAdd32x2:
|
||||
return IR::Opcode::StorageAtomicIAdd32x2;
|
||||
case IR::Opcode::GlobalAtomicSMin32x2:
|
||||
return IR::Opcode::StorageAtomicSMin32x2;
|
||||
case IR::Opcode::GlobalAtomicUMin32x2:
|
||||
return IR::Opcode::StorageAtomicUMin32x2;
|
||||
case IR::Opcode::GlobalAtomicSMax32x2:
|
||||
return IR::Opcode::StorageAtomicSMax32x2;
|
||||
case IR::Opcode::GlobalAtomicUMax32x2:
|
||||
return IR::Opcode::StorageAtomicUMax32x2;
|
||||
case IR::Opcode::GlobalAtomicAnd32x2:
|
||||
return IR::Opcode::StorageAtomicAnd32x2;
|
||||
case IR::Opcode::GlobalAtomicOr32x2:
|
||||
return IR::Opcode::StorageAtomicOr32x2;
|
||||
case IR::Opcode::GlobalAtomicXor32x2:
|
||||
return IR::Opcode::StorageAtomicXor32x2;
|
||||
case IR::Opcode::GlobalAtomicExchange32x2:
|
||||
return IR::Opcode::StorageAtomicExchange32x2;
|
||||
case IR::Opcode::GlobalAtomicAddF32:
|
||||
return IR::Opcode::StorageAtomicAddF32;
|
||||
case IR::Opcode::GlobalAtomicAddF16x2:
|
||||
@@ -454,6 +490,15 @@ void Replace(IR::Block& block, IR::Inst& inst, const IR::U32& storage_index,
|
||||
case IR::Opcode::GlobalAtomicOr64:
|
||||
case IR::Opcode::GlobalAtomicXor64:
|
||||
case IR::Opcode::GlobalAtomicExchange64:
|
||||
case IR::Opcode::GlobalAtomicIAdd32x2:
|
||||
case IR::Opcode::GlobalAtomicSMin32x2:
|
||||
case IR::Opcode::GlobalAtomicUMin32x2:
|
||||
case IR::Opcode::GlobalAtomicSMax32x2:
|
||||
case IR::Opcode::GlobalAtomicUMax32x2:
|
||||
case IR::Opcode::GlobalAtomicAnd32x2:
|
||||
case IR::Opcode::GlobalAtomicOr32x2:
|
||||
case IR::Opcode::GlobalAtomicXor32x2:
|
||||
case IR::Opcode::GlobalAtomicExchange32x2:
|
||||
case IR::Opcode::GlobalAtomicAddF32:
|
||||
case IR::Opcode::GlobalAtomicAddF16x2:
|
||||
case IR::Opcode::GlobalAtomicAddF32x2:
|
||||
|
||||
@@ -199,6 +199,26 @@ void Lower(IR::Block& block, IR::Inst& inst) {
|
||||
return ShiftRightLogical64To32(block, inst);
|
||||
case IR::Opcode::ShiftRightArithmetic64:
|
||||
return ShiftRightArithmetic64To32(block, inst);
|
||||
case IR::Opcode::SharedAtomicExchange64:
|
||||
return inst.ReplaceOpcode(IR::Opcode::SharedAtomicExchange32x2);
|
||||
case IR::Opcode::GlobalAtomicIAdd64:
|
||||
return inst.ReplaceOpcode(IR::Opcode::GlobalAtomicIAdd32x2);
|
||||
case IR::Opcode::GlobalAtomicSMin64:
|
||||
return inst.ReplaceOpcode(IR::Opcode::GlobalAtomicSMin32x2);
|
||||
case IR::Opcode::GlobalAtomicUMin64:
|
||||
return inst.ReplaceOpcode(IR::Opcode::GlobalAtomicUMin32x2);
|
||||
case IR::Opcode::GlobalAtomicSMax64:
|
||||
return inst.ReplaceOpcode(IR::Opcode::GlobalAtomicSMax32x2);
|
||||
case IR::Opcode::GlobalAtomicUMax64:
|
||||
return inst.ReplaceOpcode(IR::Opcode::GlobalAtomicUMax32x2);
|
||||
case IR::Opcode::GlobalAtomicAnd64:
|
||||
return inst.ReplaceOpcode(IR::Opcode::GlobalAtomicAnd32x2);
|
||||
case IR::Opcode::GlobalAtomicOr64:
|
||||
return inst.ReplaceOpcode(IR::Opcode::GlobalAtomicOr32x2);
|
||||
case IR::Opcode::GlobalAtomicXor64:
|
||||
return inst.ReplaceOpcode(IR::Opcode::GlobalAtomicXor32x2);
|
||||
case IR::Opcode::GlobalAtomicExchange64:
|
||||
return inst.ReplaceOpcode(IR::Opcode::GlobalAtomicExchange32x2);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "video_core/gpu.h"
|
||||
@@ -28,8 +29,11 @@ struct RendererSettings {
|
||||
Layout::FramebufferLayout screenshot_framebuffer_layout;
|
||||
};
|
||||
|
||||
class RendererBase : NonCopyable {
|
||||
class RendererBase {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(RendererBase);
|
||||
YUZU_NON_MOVEABLE(RendererBase);
|
||||
|
||||
explicit RendererBase(Core::Frontend::EmuWindow& window,
|
||||
std::unique_ptr<Core::Frontend::GraphicsContext> context);
|
||||
virtual ~RendererBase();
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <glad/glad.h>
|
||||
#include "common/common_types.h"
|
||||
#include "common/common_funcs.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class OGLRenderbuffer : private NonCopyable {
|
||||
class OGLRenderbuffer final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(OGLRenderbuffer);
|
||||
|
||||
OGLRenderbuffer() = default;
|
||||
|
||||
OGLRenderbuffer(OGLRenderbuffer&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
||||
@@ -36,8 +38,10 @@ public:
|
||||
GLuint handle = 0;
|
||||
};
|
||||
|
||||
class OGLTexture : private NonCopyable {
|
||||
class OGLTexture final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(OGLTexture);
|
||||
|
||||
OGLTexture() = default;
|
||||
|
||||
OGLTexture(OGLTexture&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
||||
@@ -61,8 +65,10 @@ public:
|
||||
GLuint handle = 0;
|
||||
};
|
||||
|
||||
class OGLTextureView : private NonCopyable {
|
||||
class OGLTextureView final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(OGLTextureView);
|
||||
|
||||
OGLTextureView() = default;
|
||||
|
||||
OGLTextureView(OGLTextureView&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
||||
@@ -86,8 +92,10 @@ public:
|
||||
GLuint handle = 0;
|
||||
};
|
||||
|
||||
class OGLSampler : private NonCopyable {
|
||||
class OGLSampler final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(OGLSampler);
|
||||
|
||||
OGLSampler() = default;
|
||||
|
||||
OGLSampler(OGLSampler&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
||||
@@ -111,8 +119,10 @@ public:
|
||||
GLuint handle = 0;
|
||||
};
|
||||
|
||||
class OGLShader : private NonCopyable {
|
||||
class OGLShader final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(OGLShader);
|
||||
|
||||
OGLShader() = default;
|
||||
|
||||
OGLShader(OGLShader&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
||||
@@ -132,8 +142,10 @@ public:
|
||||
GLuint handle = 0;
|
||||
};
|
||||
|
||||
class OGLProgram : private NonCopyable {
|
||||
class OGLProgram final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(OGLProgram);
|
||||
|
||||
OGLProgram() = default;
|
||||
|
||||
OGLProgram(OGLProgram&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
||||
@@ -154,8 +166,10 @@ public:
|
||||
GLuint handle = 0;
|
||||
};
|
||||
|
||||
class OGLAssemblyProgram : private NonCopyable {
|
||||
class OGLAssemblyProgram final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(OGLAssemblyProgram);
|
||||
|
||||
OGLAssemblyProgram() = default;
|
||||
|
||||
OGLAssemblyProgram(OGLAssemblyProgram&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
||||
@@ -176,8 +190,10 @@ public:
|
||||
GLuint handle = 0;
|
||||
};
|
||||
|
||||
class OGLPipeline : private NonCopyable {
|
||||
class OGLPipeline final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(OGLPipeline);
|
||||
|
||||
OGLPipeline() = default;
|
||||
OGLPipeline(OGLPipeline&& o) noexcept : handle{std::exchange<GLuint>(o.handle, 0)} {}
|
||||
|
||||
@@ -198,8 +214,10 @@ public:
|
||||
GLuint handle = 0;
|
||||
};
|
||||
|
||||
class OGLBuffer : private NonCopyable {
|
||||
class OGLBuffer final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(OGLBuffer);
|
||||
|
||||
OGLBuffer() = default;
|
||||
|
||||
OGLBuffer(OGLBuffer&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
||||
@@ -223,8 +241,10 @@ public:
|
||||
GLuint handle = 0;
|
||||
};
|
||||
|
||||
class OGLSync : private NonCopyable {
|
||||
class OGLSync final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(OGLSync);
|
||||
|
||||
OGLSync() = default;
|
||||
|
||||
OGLSync(OGLSync&& o) noexcept : handle(std::exchange(o.handle, nullptr)) {}
|
||||
@@ -247,8 +267,10 @@ public:
|
||||
GLsync handle = 0;
|
||||
};
|
||||
|
||||
class OGLFramebuffer : private NonCopyable {
|
||||
class OGLFramebuffer final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(OGLFramebuffer);
|
||||
|
||||
OGLFramebuffer() = default;
|
||||
|
||||
OGLFramebuffer(OGLFramebuffer&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
||||
@@ -272,8 +294,10 @@ public:
|
||||
GLuint handle = 0;
|
||||
};
|
||||
|
||||
class OGLQuery : private NonCopyable {
|
||||
class OGLQuery final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(OGLQuery);
|
||||
|
||||
OGLQuery() = default;
|
||||
|
||||
OGLQuery(OGLQuery&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
||||
|
||||
@@ -140,12 +140,12 @@ bool VKScheduler::UpdateRescaling(bool is_rescaling) {
|
||||
void VKScheduler::WorkerThread(std::stop_token stop_token) {
|
||||
Common::SetCurrentThreadName("yuzu:VulkanWorker");
|
||||
do {
|
||||
if (work_queue.empty()) {
|
||||
wait_cv.notify_all();
|
||||
}
|
||||
std::unique_ptr<CommandChunk> work;
|
||||
{
|
||||
std::unique_lock lock{work_mutex};
|
||||
if (work_queue.empty()) {
|
||||
wait_cv.notify_all();
|
||||
}
|
||||
work_cv.wait(lock, stop_token, [this] { return !work_queue.empty(); });
|
||||
if (stop_token.stop_requested()) {
|
||||
continue;
|
||||
|
||||
@@ -146,6 +146,7 @@ private:
|
||||
using FuncType = TypedCommand<T>;
|
||||
static_assert(sizeof(FuncType) < sizeof(data), "Lambda is too large");
|
||||
|
||||
recorded_counts++;
|
||||
command_offset = Common::AlignUp(command_offset, alignof(FuncType));
|
||||
if (command_offset > sizeof(data) - sizeof(FuncType)) {
|
||||
return false;
|
||||
@@ -167,7 +168,7 @@ private:
|
||||
}
|
||||
|
||||
bool Empty() const {
|
||||
return command_offset == 0;
|
||||
return recorded_counts == 0;
|
||||
}
|
||||
|
||||
bool HasSubmit() const {
|
||||
@@ -178,6 +179,7 @@ private:
|
||||
Command* first = nullptr;
|
||||
Command* last = nullptr;
|
||||
|
||||
size_t recorded_counts = 0;
|
||||
size_t command_offset = 0;
|
||||
bool submit = false;
|
||||
alignas(std::max_align_t) std::array<u8, 0x8000> data{};
|
||||
|
||||
@@ -257,7 +257,7 @@ void QtControllerSelectorDialog::LoadConfiguration() {
|
||||
}
|
||||
|
||||
void QtControllerSelectorDialog::CallConfigureVibrationDialog() {
|
||||
ConfigureVibration dialog(this);
|
||||
ConfigureVibration dialog(this, system.HIDCore());
|
||||
|
||||
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
|
||||
Qt::WindowSystemMenuHint);
|
||||
|
||||
@@ -178,52 +178,52 @@ void ConfigureHotkeys::SetPollingResult(Core::HID::NpadButton button, const bool
|
||||
QString ConfigureHotkeys::GetButtonName(Core::HID::NpadButton button) const {
|
||||
Core::HID::NpadButtonState state{button};
|
||||
if (state.a) {
|
||||
return tr("A");
|
||||
return QStringLiteral("A");
|
||||
}
|
||||
if (state.b) {
|
||||
return tr("B");
|
||||
return QStringLiteral("B");
|
||||
}
|
||||
if (state.x) {
|
||||
return tr("X");
|
||||
return QStringLiteral("X");
|
||||
}
|
||||
if (state.y) {
|
||||
return tr("Y");
|
||||
return QStringLiteral("Y");
|
||||
}
|
||||
if (state.l || state.right_sl || state.left_sl) {
|
||||
return tr("L");
|
||||
return QStringLiteral("L");
|
||||
}
|
||||
if (state.r || state.right_sr || state.left_sr) {
|
||||
return tr("R");
|
||||
return QStringLiteral("R");
|
||||
}
|
||||
if (state.zl) {
|
||||
return tr("ZL");
|
||||
return QStringLiteral("ZL");
|
||||
}
|
||||
if (state.zr) {
|
||||
return tr("ZR");
|
||||
return QStringLiteral("ZR");
|
||||
}
|
||||
if (state.left) {
|
||||
return tr("Dpad_Left");
|
||||
return QStringLiteral("Dpad_Left");
|
||||
}
|
||||
if (state.right) {
|
||||
return tr("Dpad_Right");
|
||||
return QStringLiteral("Dpad_Right");
|
||||
}
|
||||
if (state.up) {
|
||||
return tr("Dpad_Up");
|
||||
return QStringLiteral("Dpad_Up");
|
||||
}
|
||||
if (state.down) {
|
||||
return tr("Dpad_Down");
|
||||
return QStringLiteral("Dpad_Down");
|
||||
}
|
||||
if (state.stick_l) {
|
||||
return tr("Left_Stick");
|
||||
return QStringLiteral("Left_Stick");
|
||||
}
|
||||
if (state.stick_r) {
|
||||
return tr("Right_Stick");
|
||||
return QStringLiteral("Right_Stick");
|
||||
}
|
||||
if (state.minus) {
|
||||
return tr("Minus");
|
||||
return QStringLiteral("Minus");
|
||||
}
|
||||
if (state.plus) {
|
||||
return tr("Plus");
|
||||
return QStringLiteral("Plus");
|
||||
}
|
||||
return tr("Invalid");
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
|
||||
});
|
||||
|
||||
connect(ui->vibrationButton, &QPushButton::clicked,
|
||||
[this] { CallConfigureDialog<ConfigureVibration>(*this); });
|
||||
[this, &hid_core] { CallConfigureDialog<ConfigureVibration>(*this, hid_core); });
|
||||
|
||||
connect(ui->motionButton, &QPushButton::clicked, [this, input_subsystem] {
|
||||
CallConfigureDialog<ConfigureMotionTouch>(*this, input_subsystem);
|
||||
|
||||
@@ -102,6 +102,10 @@ QString GetButtonName(Common::Input::ButtonNames button_name) {
|
||||
return QObject::tr("Share");
|
||||
case Common::Input::ButtonNames::Options:
|
||||
return QObject::tr("Options");
|
||||
case Common::Input::ButtonNames::Home:
|
||||
return QObject::tr("Home");
|
||||
case Common::Input::ButtonNames::Touch:
|
||||
return QObject::tr("Touch");
|
||||
case Common::Input::ButtonNames::ButtonMouseWheel:
|
||||
return QObject::tr("Wheel", "Indicates the mouse wheel");
|
||||
case Common::Input::ButtonNames::ButtonBackward:
|
||||
|
||||
@@ -70,7 +70,6 @@ void PlayerControlPreview::UpdateColors() {
|
||||
colors.slider_arrow = QColor(14, 15, 18);
|
||||
colors.font2 = QColor(255, 255, 255);
|
||||
colors.indicator = QColor(170, 238, 255);
|
||||
colors.indicator2 = QColor(100, 255, 100);
|
||||
colors.deadzone = QColor(204, 136, 136);
|
||||
colors.slider_button = colors.button;
|
||||
}
|
||||
@@ -88,7 +87,6 @@ void PlayerControlPreview::UpdateColors() {
|
||||
colors.slider_arrow = QColor(65, 68, 73);
|
||||
colors.font2 = QColor(0, 0, 0);
|
||||
colors.indicator = QColor(0, 0, 200);
|
||||
colors.indicator2 = QColor(0, 150, 0);
|
||||
colors.deadzone = QColor(170, 0, 0);
|
||||
colors.slider_button = QColor(153, 149, 149);
|
||||
}
|
||||
@@ -101,6 +99,8 @@ void PlayerControlPreview::UpdateColors() {
|
||||
colors.font = QColor(255, 255, 255);
|
||||
colors.led_on = QColor(255, 255, 0);
|
||||
colors.led_off = QColor(170, 238, 255);
|
||||
colors.indicator2 = QColor(59, 165, 93);
|
||||
colors.charging = QColor(250, 168, 26);
|
||||
|
||||
colors.left = colors.primary;
|
||||
colors.right = colors.primary;
|
||||
@@ -357,7 +357,7 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center)
|
||||
DrawCircle(p, center + QPoint(26, 71), 5);
|
||||
|
||||
// Draw battery
|
||||
DrawBattery(p, center + QPoint(-170, -140),
|
||||
DrawBattery(p, center + QPoint(-160, -140),
|
||||
battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]);
|
||||
}
|
||||
|
||||
@@ -484,7 +484,7 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
|
||||
DrawSymbol(p, center + QPoint(-26, 66), Symbol::House, 5);
|
||||
|
||||
// Draw battery
|
||||
DrawBattery(p, center + QPoint(110, -140),
|
||||
DrawBattery(p, center + QPoint(120, -140),
|
||||
battery_values[Core::HID::EmulatedDeviceIndex::RightIndex]);
|
||||
}
|
||||
|
||||
@@ -621,9 +621,9 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
|
||||
DrawSymbol(p, center + QPoint(50, 60), Symbol::House, 4.2f);
|
||||
|
||||
// Draw battery
|
||||
DrawBattery(p, center + QPoint(-100, -160),
|
||||
DrawBattery(p, center + QPoint(-200, -10),
|
||||
battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]);
|
||||
DrawBattery(p, center + QPoint(40, -160),
|
||||
DrawBattery(p, center + QPoint(160, -10),
|
||||
battery_values[Core::HID::EmulatedDeviceIndex::RightIndex]);
|
||||
}
|
||||
|
||||
@@ -694,12 +694,12 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
|
||||
|
||||
// ZL and ZR buttons
|
||||
p.setPen(colors.outline);
|
||||
DrawTriggerButton(p, center + QPoint(-210, -130), Direction::Left, button_values[ZL]);
|
||||
DrawTriggerButton(p, center + QPoint(210, -130), Direction::Right, button_values[ZR]);
|
||||
DrawTriggerButton(p, center + QPoint(-210, -120), Direction::Left, button_values[ZL]);
|
||||
DrawTriggerButton(p, center + QPoint(210, -120), Direction::Right, button_values[ZR]);
|
||||
p.setPen(colors.transparent);
|
||||
p.setBrush(colors.font);
|
||||
DrawSymbol(p, center + QPoint(-210, -130), Symbol::ZL, 1.5f);
|
||||
DrawSymbol(p, center + QPoint(210, -130), Symbol::ZR, 1.5f);
|
||||
DrawSymbol(p, center + QPoint(-210, -120), Symbol::ZL, 1.5f);
|
||||
DrawSymbol(p, center + QPoint(210, -120), Symbol::ZR, 1.5f);
|
||||
|
||||
// Minus and Plus button
|
||||
p.setPen(colors.outline);
|
||||
@@ -725,9 +725,9 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
|
||||
DrawSymbol(p, center + QPoint(161, 37), Symbol::House, 2.75f);
|
||||
|
||||
// Draw battery
|
||||
DrawBattery(p, center + QPoint(-200, 110),
|
||||
DrawBattery(p, center + QPoint(-188, 95),
|
||||
battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]);
|
||||
DrawBattery(p, center + QPoint(130, 110),
|
||||
DrawBattery(p, center + QPoint(150, 95),
|
||||
battery_values[Core::HID::EmulatedDeviceIndex::RightIndex]);
|
||||
}
|
||||
|
||||
@@ -781,12 +781,12 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
|
||||
|
||||
// ZL and ZR buttons
|
||||
p.setPen(colors.outline);
|
||||
DrawTriggerButton(p, center + QPoint(-210, -130), Direction::Left, button_values[ZL]);
|
||||
DrawTriggerButton(p, center + QPoint(210, -130), Direction::Right, button_values[ZR]);
|
||||
DrawTriggerButton(p, center + QPoint(-210, -120), Direction::Left, button_values[ZL]);
|
||||
DrawTriggerButton(p, center + QPoint(210, -120), Direction::Right, button_values[ZR]);
|
||||
p.setPen(colors.transparent);
|
||||
p.setBrush(colors.font);
|
||||
DrawSymbol(p, center + QPoint(-210, -130), Symbol::ZL, 1.5f);
|
||||
DrawSymbol(p, center + QPoint(210, -130), Symbol::ZR, 1.5f);
|
||||
DrawSymbol(p, center + QPoint(-210, -120), Symbol::ZL, 1.5f);
|
||||
DrawSymbol(p, center + QPoint(210, -120), Symbol::ZR, 1.5f);
|
||||
|
||||
// Minus and Plus buttons
|
||||
p.setPen(colors.outline);
|
||||
@@ -818,7 +818,7 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
|
||||
DrawSymbol(p, center + QPoint(29, -56), Symbol::House, 3.9f);
|
||||
|
||||
// Draw battery
|
||||
DrawBattery(p, center + QPoint(-30, -160),
|
||||
DrawBattery(p, center + QPoint(-20, -160),
|
||||
battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]);
|
||||
}
|
||||
|
||||
@@ -875,7 +875,7 @@ void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) {
|
||||
DrawCircleButton(p, center + QPoint(0, -44), button_values[Plus], 8);
|
||||
|
||||
// Draw battery
|
||||
DrawBattery(p, center + QPoint(-30, -165),
|
||||
DrawBattery(p, center + QPoint(-20, 110),
|
||||
battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]);
|
||||
}
|
||||
|
||||
@@ -1030,6 +1030,10 @@ constexpr std::array<float, 30 * 2> symbol_c = {
|
||||
-2.37f, 5.64f, -0.65f, 6.44f, 1.25f, 6.47f, 3.06f, 5.89f, 4.63f, 4.92f, 4.63f, 6.83f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 6 * 2> symbol_charging = {
|
||||
6.5f, -1.0f, 1.0f, -1.0f, 1.0f, -3.0f, -6.5f, 1.0f, -1.0f, 1.0f, -1.0f, 3.0f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 12 * 2> house = {
|
||||
-1.3f, 0.0f, -0.93f, 0.0f, -0.93f, 1.15f, 0.93f, 1.15f, 0.93f, 0.0f, 1.3f, 0.0f,
|
||||
0.0f, -1.2f, -1.3f, 0.0f, -0.43f, 0.0f, -0.43f, .73f, 0.43f, .73f, 0.43f, 0.0f,
|
||||
@@ -2674,36 +2678,43 @@ void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center,
|
||||
if (battery == Common::Input::BatteryLevel::None) {
|
||||
return;
|
||||
}
|
||||
p.setPen(colors.outline);
|
||||
// Draw outline
|
||||
p.setPen(QPen(colors.button, 5));
|
||||
p.setBrush(colors.transparent);
|
||||
p.drawRect(center.x(), center.y(), 56, 20);
|
||||
p.drawRect(center.x() + 56, center.y() + 6, 3, 8);
|
||||
p.setBrush(colors.deadzone);
|
||||
p.drawRoundedRect(center.x(), center.y(), 34, 16, 2, 2);
|
||||
|
||||
p.setPen(QPen(colors.button, 3));
|
||||
p.drawRect(center.x() + 35, center.y() + 4.5f, 4, 7);
|
||||
|
||||
// Draw Battery shape
|
||||
p.setPen(QPen(colors.indicator2, 3));
|
||||
p.setBrush(colors.transparent);
|
||||
p.drawRoundedRect(center.x(), center.y(), 34, 16, 2, 2);
|
||||
|
||||
p.setPen(QPen(colors.indicator2, 1));
|
||||
p.setBrush(colors.indicator2);
|
||||
p.drawRect(center.x() + 35, center.y() + 4.5f, 4, 7);
|
||||
switch (battery) {
|
||||
case Common::Input::BatteryLevel::Charging:
|
||||
p.setBrush(colors.indicator2);
|
||||
p.drawText(center + QPoint(2, 14), tr("Charging"));
|
||||
p.drawRect(center.x(), center.y(), 34, 16);
|
||||
p.setPen(colors.slider);
|
||||
p.setBrush(colors.charging);
|
||||
DrawSymbol(p, center + QPointF(17.0f, 8.0f), Symbol::Charging, 2.1f);
|
||||
break;
|
||||
case Common::Input::BatteryLevel::Full:
|
||||
p.drawRect(center.x() + 42, center.y(), 14, 20);
|
||||
p.drawRect(center.x() + 28, center.y(), 14, 20);
|
||||
p.drawRect(center.x() + 14, center.y(), 14, 20);
|
||||
p.drawRect(center.x(), center.y(), 14, 20);
|
||||
p.drawRect(center.x(), center.y(), 34, 16);
|
||||
break;
|
||||
case Common::Input::BatteryLevel::Medium:
|
||||
p.drawRect(center.x() + 28, center.y(), 14, 20);
|
||||
p.drawRect(center.x() + 14, center.y(), 14, 20);
|
||||
p.drawRect(center.x(), center.y(), 14, 20);
|
||||
p.drawRect(center.x(), center.y(), 25, 16);
|
||||
break;
|
||||
case Common::Input::BatteryLevel::Low:
|
||||
p.drawRect(center.x() + 14, center.y(), 14, 20);
|
||||
p.drawRect(center.x(), center.y(), 14, 20);
|
||||
p.drawRect(center.x(), center.y(), 17, 16);
|
||||
break;
|
||||
case Common::Input::BatteryLevel::Critical:
|
||||
p.drawRect(center.x(), center.y(), 14, 20);
|
||||
p.drawRect(center.x(), center.y(), 6, 16);
|
||||
break;
|
||||
case Common::Input::BatteryLevel::Empty:
|
||||
p.drawRect(center.x(), center.y(), 5, 20);
|
||||
p.drawRect(center.x(), center.y(), 3, 16);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -2724,6 +2735,7 @@ void PlayerControlPreview::DrawSymbol(QPainter& p, const QPointF center, Symbol
|
||||
std::array<QPointF, symbol_sl.size() / 2> sl_icon;
|
||||
std::array<QPointF, symbol_zr.size() / 2> zr_icon;
|
||||
std::array<QPointF, symbol_sr.size() / 2> sr_icon;
|
||||
std::array<QPointF, symbol_charging.size() / 2> charging_icon;
|
||||
switch (symbol) {
|
||||
case Symbol::House:
|
||||
for (std::size_t point = 0; point < house.size() / 2; ++point) {
|
||||
@@ -2809,6 +2821,13 @@ void PlayerControlPreview::DrawSymbol(QPainter& p, const QPointF center, Symbol
|
||||
}
|
||||
p.drawPolygon(sr_icon.data(), static_cast<int>(sr_icon.size()));
|
||||
break;
|
||||
case Symbol::Charging:
|
||||
for (std::size_t point = 0; point < symbol_charging.size() / 2; ++point) {
|
||||
charging_icon[point] = center + QPointF(symbol_charging[point * 2] * icon_size,
|
||||
symbol_charging[point * 2 + 1] * icon_size);
|
||||
}
|
||||
p.drawPolygon(charging_icon.data(), static_cast<int>(charging_icon.size()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ private:
|
||||
ZL,
|
||||
ZR,
|
||||
SR,
|
||||
Charging,
|
||||
};
|
||||
|
||||
struct ColorMapping {
|
||||
@@ -94,6 +95,7 @@ private:
|
||||
QColor slider_button{};
|
||||
QColor slider_arrow{};
|
||||
QColor deadzone{};
|
||||
QColor charging{};
|
||||
};
|
||||
|
||||
void UpdateColors();
|
||||
|
||||
@@ -9,11 +9,14 @@
|
||||
|
||||
#include "common/param_package.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "ui_configure_vibration.h"
|
||||
#include "yuzu/configuration/configure_vibration.h"
|
||||
|
||||
ConfigureVibration::ConfigureVibration(QWidget* parent)
|
||||
: QDialog(parent), ui(std::make_unique<Ui::ConfigureVibration>()) {
|
||||
ConfigureVibration::ConfigureVibration(QWidget* parent, Core::HID::HIDCore& hid_core_)
|
||||
: QDialog(parent), ui(std::make_unique<Ui::ConfigureVibration>()), hid_core{hid_core_} {
|
||||
ui->setupUi(this);
|
||||
|
||||
vibration_groupboxes = {
|
||||
@@ -31,6 +34,13 @@ ConfigureVibration::ConfigureVibration(QWidget* parent)
|
||||
const auto& players = Settings::values.players.GetValue();
|
||||
|
||||
for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
|
||||
auto controller = hid_core.GetEmulatedControllerByIndex(i);
|
||||
Core::HID::ControllerUpdateCallback engine_callback{
|
||||
.on_change = [this,
|
||||
i](Core::HID::ControllerTriggerType type) { VibrateController(type, i); },
|
||||
.is_npad_service = false,
|
||||
};
|
||||
controller_callback_key[i] = controller->SetCallback(engine_callback);
|
||||
vibration_groupboxes[i]->setChecked(players[i].vibration_enabled);
|
||||
vibration_spinboxes[i]->setValue(players[i].vibration_strength);
|
||||
}
|
||||
@@ -45,7 +55,14 @@ ConfigureVibration::ConfigureVibration(QWidget* parent)
|
||||
RetranslateUI();
|
||||
}
|
||||
|
||||
ConfigureVibration::~ConfigureVibration() = default;
|
||||
ConfigureVibration::~ConfigureVibration() {
|
||||
StopVibrations();
|
||||
|
||||
for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
|
||||
auto controller = hid_core.GetEmulatedControllerByIndex(i);
|
||||
controller->DeleteCallback(controller_callback_key[i]);
|
||||
}
|
||||
};
|
||||
|
||||
void ConfigureVibration::ApplyConfiguration() {
|
||||
auto& players = Settings::values.players.GetValue();
|
||||
@@ -70,3 +87,54 @@ void ConfigureVibration::changeEvent(QEvent* event) {
|
||||
void ConfigureVibration::RetranslateUI() {
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
|
||||
void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type,
|
||||
std::size_t player_index) {
|
||||
if (type != Core::HID::ControllerTriggerType::Button) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& player = Settings::values.players.GetValue()[player_index];
|
||||
auto controller = hid_core.GetEmulatedControllerByIndex(player_index);
|
||||
const int vibration_strenght = vibration_spinboxes[player_index]->value();
|
||||
const auto& buttons = controller->GetButtonsValues();
|
||||
|
||||
bool button_is_pressed = false;
|
||||
for (std::size_t i = 0; i < buttons.size(); ++i) {
|
||||
if (buttons[i].value) {
|
||||
button_is_pressed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!button_is_pressed) {
|
||||
StopVibrations();
|
||||
return;
|
||||
}
|
||||
|
||||
const int old_vibration_enabled = player.vibration_enabled;
|
||||
const bool old_vibration_strenght = player.vibration_strength;
|
||||
player.vibration_enabled = true;
|
||||
player.vibration_strength = vibration_strenght;
|
||||
|
||||
const Core::HID::VibrationValue vibration{
|
||||
.low_amplitude = 1.0f,
|
||||
.low_frequency = 160.0f,
|
||||
.high_amplitude = 1.0f,
|
||||
.high_frequency = 320.0f,
|
||||
};
|
||||
controller->SetVibration(0, vibration);
|
||||
controller->SetVibration(1, vibration);
|
||||
|
||||
// Restore previous values
|
||||
player.vibration_enabled = old_vibration_enabled;
|
||||
player.vibration_strength = old_vibration_strenght;
|
||||
}
|
||||
|
||||
void ConfigureVibration::StopVibrations() {
|
||||
for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
|
||||
auto controller = hid_core.GetEmulatedControllerByIndex(i);
|
||||
controller->SetVibration(0, Core::HID::DEFAULT_VIBRATION_VALUE);
|
||||
controller->SetVibration(1, Core::HID::DEFAULT_VIBRATION_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,16 @@ namespace Ui {
|
||||
class ConfigureVibration;
|
||||
}
|
||||
|
||||
namespace Core::HID {
|
||||
enum class ControllerTriggerType;
|
||||
class HIDCore;
|
||||
} // namespace Core::HID
|
||||
|
||||
class ConfigureVibration : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConfigureVibration(QWidget* parent);
|
||||
explicit ConfigureVibration(QWidget* parent, Core::HID::HIDCore& hid_core_);
|
||||
~ConfigureVibration() override;
|
||||
|
||||
void ApplyConfiguration();
|
||||
@@ -27,14 +32,21 @@ public:
|
||||
private:
|
||||
void changeEvent(QEvent* event) override;
|
||||
void RetranslateUI();
|
||||
void VibrateController(Core::HID::ControllerTriggerType type, std::size_t player_index);
|
||||
void StopVibrations();
|
||||
|
||||
std::unique_ptr<Ui::ConfigureVibration> ui;
|
||||
|
||||
static constexpr std::size_t NUM_PLAYERS = 8;
|
||||
|
||||
// Groupboxes encapsulating the vibration strength spinbox.
|
||||
/// Groupboxes encapsulating the vibration strength spinbox.
|
||||
std::array<QGroupBox*, NUM_PLAYERS> vibration_groupboxes;
|
||||
|
||||
// Spinboxes representing the vibration strength percentage.
|
||||
/// Spinboxes representing the vibration strength percentage.
|
||||
std::array<QSpinBox*, NUM_PLAYERS> vibration_spinboxes;
|
||||
|
||||
/// Callback index to stop the controllers events
|
||||
std::array<int, NUM_PLAYERS> controller_callback_key;
|
||||
|
||||
Core::HID::HIDCore& hid_core;
|
||||
};
|
||||
|
||||
@@ -17,6 +17,13 @@
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label_1">
|
||||
<property name="text">
|
||||
<string>Press any controller button to vibrate the controller.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="vibrationStrengthGroup">
|
||||
<property name="title">
|
||||
|
||||
@@ -965,6 +965,7 @@ void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name
|
||||
static const QString main_window = QStringLiteral("Main Window");
|
||||
action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name));
|
||||
action->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, action_name));
|
||||
action->setAutoRepeat(false);
|
||||
|
||||
this->addAction(action);
|
||||
|
||||
@@ -1051,8 +1052,10 @@ void GMainWindow::SetDefaultUIGeometry() {
|
||||
}
|
||||
|
||||
void GMainWindow::RestoreUIState() {
|
||||
setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
|
||||
restoreGeometry(UISettings::values.geometry);
|
||||
restoreState(UISettings::values.state);
|
||||
render_window->setWindowFlags(render_window->windowFlags() & ~Qt::FramelessWindowHint);
|
||||
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
|
||||
#if MICROPROFILE_ENABLED
|
||||
microProfileDialog->restoreGeometry(UISettings::values.microprofile_geometry);
|
||||
|
||||
@@ -66,6 +66,11 @@ static const std::array<int, Settings::NativeButton::NumButtons> default_buttons
|
||||
SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_B,
|
||||
};
|
||||
|
||||
static const std::array<int, Settings::NativeMotion::NumMotions> default_motions = {
|
||||
SDL_SCANCODE_7,
|
||||
SDL_SCANCODE_8,
|
||||
};
|
||||
|
||||
static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs{{
|
||||
{
|
||||
SDL_SCANCODE_UP,
|
||||
@@ -102,27 +107,42 @@ void Config::ReadSetting(const std::string& group, Settings::BasicSetting<Type>&
|
||||
void Config::ReadValues() {
|
||||
// Controls
|
||||
for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
|
||||
auto& player = Settings::values.players.GetValue()[p];
|
||||
|
||||
const auto group = fmt::format("ControlsP{}", p);
|
||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||
std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||
Settings::values.players.GetValue()[p].buttons[i] =
|
||||
player.buttons[i] =
|
||||
sdl2_config->Get(group, Settings::NativeButton::mapping[i], default_param);
|
||||
if (Settings::values.players.GetValue()[p].buttons[i].empty())
|
||||
Settings::values.players.GetValue()[p].buttons[i] = default_param;
|
||||
if (player.buttons[i].empty()) {
|
||||
player.buttons[i] = default_param;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||
std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||
default_analogs[i][3], default_analogs[i][4], 0.5f);
|
||||
Settings::values.players.GetValue()[p].analogs[i] =
|
||||
player.analogs[i] =
|
||||
sdl2_config->Get(group, Settings::NativeAnalog::mapping[i], default_param);
|
||||
if (Settings::values.players.GetValue()[p].analogs[i].empty())
|
||||
Settings::values.players.GetValue()[p].analogs[i] = default_param;
|
||||
if (player.analogs[i].empty()) {
|
||||
player.analogs[i] = default_param;
|
||||
}
|
||||
}
|
||||
|
||||
Settings::values.players.GetValue()[p].connected =
|
||||
sdl2_config->GetBoolean(group, "connected", false);
|
||||
for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
|
||||
const std::string default_param =
|
||||
InputCommon::GenerateKeyboardParam(default_motions[i]);
|
||||
auto& player_motions = player.motions[i];
|
||||
|
||||
player_motions =
|
||||
sdl2_config->Get(group, Settings::NativeMotion::mapping[i], default_param);
|
||||
if (player_motions.empty()) {
|
||||
player_motions = default_param;
|
||||
}
|
||||
}
|
||||
|
||||
player.connected = sdl2_config->GetBoolean(group, "connected", false);
|
||||
}
|
||||
|
||||
ReadSetting("ControlsGeneral", Settings::values.mouse_enabled);
|
||||
|
||||
Reference in New Issue
Block a user