mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-28 09:41:36 +00:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 002cd922a3 | |||
| 2ffb812e2a | |||
| 3e17ff32d3 | |||
| 26e9a6e308 | |||
| 02d74e1372 | |||
| 9a4f67ff7e | |||
| c9f7905e55 | |||
| 683d54cc22 | |||
| a6630d5a1b | |||
| 076cee88df | |||
| 2c62ad44af | |||
| 9cc8dd40a3 | |||
| 208eae5d94 | |||
| 10eb1ef059 | |||
| ea9be2b91e | |||
| ddca87271a | |||
| 47e9709658 | |||
| cd0b66ecc5 | |||
| f7c40ac8db | |||
| 9caa3212fa | |||
| ea6e890ab9 | |||
| 794988cbca | |||
| 3a9a15e4cc | |||
| cfeb8959c0 | |||
| 6b5d29428d | |||
| 8ecb8cfe0c | |||
| a5f5712316 | |||
| f1a970cac9 | |||
| 031eaf8868 | |||
| 735c2fc23f | |||
| 5bb858d2ce | |||
| 966e975ed9 | |||
| 5979df41df | |||
| 11e8e1de63 |
@@ -69,6 +69,26 @@ if (YUZU_STATIC_ROOM)
|
|||||||
set(fmt_FORCE_BUNDLED ON)
|
set(fmt_FORCE_BUNDLED ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# my unity/jumbo build
|
||||||
|
option(ENABLE_UNITY_BUILD "Enable Unity/Jumbo build" OFF)
|
||||||
|
|
||||||
|
# 0 compiles all files in
|
||||||
|
# not ideal, but if you're going gung-ho with a unity build, expect failure
|
||||||
|
# MSVC physically can't compile that many files into one TU, so we limit it to 100.
|
||||||
|
if (MSVC)
|
||||||
|
set(_unity_default 100)
|
||||||
|
else()
|
||||||
|
set(_unity_default 0)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(UNITY_BATCH_SIZE ${_unity_default} CACHE STRING "Unity build batch size")
|
||||||
|
|
||||||
|
if(MSVC AND ENABLE_UNITY_BUILD)
|
||||||
|
message(STATUS "Unity build")
|
||||||
|
# Unity builds need big objects for MSVC...
|
||||||
|
add_compile_options(/bigobj)
|
||||||
|
endif()
|
||||||
|
|
||||||
# qt stuff
|
# qt stuff
|
||||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||||
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ These options control dependencies.
|
|||||||
- This option is subject for removal.
|
- This option is subject for removal.
|
||||||
- `YUZU_TESTS` (ON) Compile tests - requires Catch2
|
- `YUZU_TESTS` (ON) Compile tests - requires Catch2
|
||||||
- `ENABLE_LTO` (OFF) Enable link-time optimization
|
- `ENABLE_LTO` (OFF) Enable link-time optimization
|
||||||
|
- `ENABLE_UNITY_BUILD` (OFF) Enables "Unity/Jumbo" builds
|
||||||
- Not recommended on Windows
|
- Not recommended on Windows
|
||||||
- UNIX may be better off appending `-flto=thin` to compiler args
|
- UNIX may be better off appending `-flto=thin` to compiler args
|
||||||
- `USE_FASTER_LINKER` (OFF) Check if a faster linker is available
|
- `USE_FASTER_LINKER` (OFF) Check if a faster linker is available
|
||||||
|
|||||||
@@ -7,6 +7,11 @@
|
|||||||
# Enable modules to include each other's files
|
# Enable modules to include each other's files
|
||||||
include_directories(.)
|
include_directories(.)
|
||||||
|
|
||||||
|
if (ENABLE_UNITY_BUILD)
|
||||||
|
set(CMAKE_UNITY_BUILD ON)
|
||||||
|
set(CMAKE_UNITY_BUILD_BATCH_SIZE ${UNITY_BATCH_SIZE})
|
||||||
|
endif()
|
||||||
|
|
||||||
# Dynarmic
|
# Dynarmic
|
||||||
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64) AND NOT YUZU_STATIC_ROOM)
|
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64) AND NOT YUZU_STATIC_ROOM)
|
||||||
add_subdirectory(dynarmic)
|
add_subdirectory(dynarmic)
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -5,17 +8,11 @@
|
|||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
|
||||||
namespace AudioCore::ADSP::OpusDecoder {
|
namespace AudioCore::ADSP::OpusDecoder {
|
||||||
namespace {
|
|
||||||
bool IsValidChannelCount(u32 channel_count) {
|
|
||||||
return channel_count == 1 || channel_count == 2;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
u32 OpusDecodeObject::GetWorkBufferSize(u32 channel_count) {
|
u32 OpusDecodeObject::GetWorkBufferSize(u32 channel_count) {
|
||||||
if (!IsValidChannelCount(channel_count)) {
|
if (channel_count == 1 || channel_count == 2)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
return u32(sizeof(OpusDecodeObject)) + opus_decoder_get_size(channel_count);
|
||||||
return static_cast<u32>(sizeof(OpusDecodeObject)) + opus_decoder_get_size(channel_count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OpusDecodeObject& OpusDecodeObject::Initialize(u64 buffer, u64 buffer2) {
|
OpusDecodeObject& OpusDecodeObject::Initialize(u64 buffer, u64 buffer2) {
|
||||||
|
|||||||
@@ -22,10 +22,6 @@ namespace AudioCore::ADSP::OpusDecoder {
|
|||||||
namespace {
|
namespace {
|
||||||
constexpr size_t OpusStreamCountMax = 255;
|
constexpr size_t OpusStreamCountMax = 255;
|
||||||
|
|
||||||
bool IsValidChannelCount(u32 channel_count) {
|
|
||||||
return channel_count == 1 || channel_count == 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsValidMultiStreamChannelCount(u32 channel_count) {
|
bool IsValidMultiStreamChannelCount(u32 channel_count) {
|
||||||
return channel_count <= OpusStreamCountMax;
|
return channel_count <= OpusStreamCountMax;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -7,13 +10,10 @@
|
|||||||
namespace AudioCore::ADSP::OpusDecoder {
|
namespace AudioCore::ADSP::OpusDecoder {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
bool IsValidChannelCount(u32 channel_count) {
|
|
||||||
return channel_count == 1 || channel_count == 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) {
|
bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) {
|
||||||
return total_stream_count > 0 && static_cast<s32>(stereo_stream_count) >= 0 &&
|
return total_stream_count > 0 && s32(stereo_stream_count) >= 0
|
||||||
stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count);
|
&& stereo_stream_count <= total_stream_count
|
||||||
|
&& (total_stream_count == 1 || total_stream_count == 2);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|||||||
@@ -14,14 +14,16 @@
|
|||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/k_event.h"
|
#include "core/hle/kernel/k_event.h"
|
||||||
|
|
||||||
|
namespace AudioCore::AudioIn {
|
||||||
|
|
||||||
// See texture_cache/util.h
|
// See texture_cache/util.h
|
||||||
template<typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
#if BOOST_VERSION >= 108100 || __GNUC__ > 12
|
#if BOOST_VERSION >= 108100 || __GNUC__ > 12
|
||||||
[[nodiscard]] boost::container::static_vector<T, N> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
[[nodiscard]] static inline boost::container::static_vector<T, N> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
[[nodiscard]] std::vector<T> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
[[nodiscard]] static inline std::vector<T> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
||||||
std::vector<T> u;
|
std::vector<T> u;
|
||||||
for (auto const& e : v)
|
for (auto const& e : v)
|
||||||
u.push_back(e);
|
u.push_back(e);
|
||||||
@@ -29,8 +31,6 @@ template<typename T, size_t N>
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace AudioCore::AudioIn {
|
|
||||||
|
|
||||||
System::System(Core::System& system_, Kernel::KEvent* event_, const size_t session_id_)
|
System::System(Core::System& system_, Kernel::KEvent* event_, const size_t session_id_)
|
||||||
: system{system_}, buffer_event{event_},
|
: system{system_}, buffer_event{event_},
|
||||||
session_id{session_id_}, session{std::make_unique<DeviceSession>(system_)} {}
|
session_id{session_id_}, session{std::make_unique<DeviceSession>(system_)} {}
|
||||||
|
|||||||
@@ -14,14 +14,15 @@
|
|||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/k_event.h"
|
#include "core/hle/kernel/k_event.h"
|
||||||
|
|
||||||
|
namespace AudioCore::AudioOut {
|
||||||
// See texture_cache/util.h
|
// See texture_cache/util.h
|
||||||
template<typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
#if BOOST_VERSION >= 108100 || __GNUC__ > 12
|
#if BOOST_VERSION >= 108100 || __GNUC__ > 12
|
||||||
[[nodiscard]] boost::container::static_vector<T, N> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
[[nodiscard]] static inline boost::container::static_vector<T, N> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
[[nodiscard]] std::vector<T> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
[[nodiscard]] static inline std::vector<T> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
|
||||||
std::vector<T> u;
|
std::vector<T> u;
|
||||||
for (auto const& e : v)
|
for (auto const& e : v)
|
||||||
u.push_back(e);
|
u.push_back(e);
|
||||||
@@ -29,8 +30,6 @@ template<typename T, size_t N>
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace AudioCore::AudioOut {
|
|
||||||
|
|
||||||
System::System(Core::System& system_, Kernel::KEvent* event_, size_t session_id_)
|
System::System(Core::System& system_, Kernel::KEvent* event_, size_t session_id_)
|
||||||
: system{system_}, buffer_event{event_},
|
: system{system_}, buffer_event{event_},
|
||||||
session_id{session_id_}, session{std::make_unique<DeviceSession>(system_)} {}
|
session_id{session_id_}, session{std::make_unique<DeviceSession>(system_)} {}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
@@ -16,7 +16,7 @@ namespace AudioCore::Renderer {
|
|||||||
* @param memory - Core memory for writing.
|
* @param memory - Core memory for writing.
|
||||||
* @param aux_info - Memory address pointing to the AuxInfo to reset.
|
* @param aux_info - Memory address pointing to the AuxInfo to reset.
|
||||||
*/
|
*/
|
||||||
static void ResetAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr aux_info) {
|
static void CaptureResetAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr aux_info) {
|
||||||
if (aux_info == 0) {
|
if (aux_info == 0) {
|
||||||
LOG_ERROR(Service_Audio, "Aux info is 0!");
|
LOG_ERROR(Service_Audio, "Aux info is 0!");
|
||||||
return;
|
return;
|
||||||
@@ -134,7 +134,7 @@ void CaptureCommand::Process(const AudioRenderer::CommandListProcessor& processo
|
|||||||
WriteAuxBufferDsp(*processor.memory, send_buffer_info, send_buffer, count_max, input_buffer,
|
WriteAuxBufferDsp(*processor.memory, send_buffer_info, send_buffer, count_max, input_buffer,
|
||||||
processor.sample_count, write_offset, update_count);
|
processor.sample_count, write_offset, update_count);
|
||||||
} else {
|
} else {
|
||||||
ResetAuxBufferDsp(*processor.memory, send_buffer_info);
|
CaptureResetAuxBufferDsp(*processor.memory, send_buffer_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2011 Google, Inc.
|
// SPDX-FileCopyrightText: 2011 Google, Inc.
|
||||||
// SPDX-FileContributor: Geoff Pike
|
// SPDX-FileContributor: Geoff Pike
|
||||||
// SPDX-FileContributor: Jyrki Alakuijala
|
// SPDX-FileContributor: Jyrki Alakuijala
|
||||||
@@ -27,8 +30,6 @@
|
|||||||
#define WORDS_BIGENDIAN 1
|
#define WORDS_BIGENDIAN 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
static u64 unaligned_load64(const char* p) {
|
static u64 unaligned_load64(const char* p) {
|
||||||
@@ -135,18 +136,18 @@ static u64 HashLen17to32(const char* s, size_t len) {
|
|||||||
|
|
||||||
// Return a 16-byte hash for 48 bytes. Quick and dirty.
|
// Return a 16-byte hash for 48 bytes. Quick and dirty.
|
||||||
// Callers do best to use "random-looking" values for a and b.
|
// Callers do best to use "random-looking" values for a and b.
|
||||||
static pair<u64, u64> WeakHashLen32WithSeeds(u64 w, u64 x, u64 y, u64 z, u64 a, u64 b) {
|
static std::pair<u64, u64> WeakHashLen32WithSeeds(u64 w, u64 x, u64 y, u64 z, u64 a, u64 b) {
|
||||||
a += w;
|
a += w;
|
||||||
b = Rotate(b + a + z, 21);
|
b = Rotate(b + a + z, 21);
|
||||||
u64 c = a;
|
u64 c = a;
|
||||||
a += x;
|
a += x;
|
||||||
a += y;
|
a += y;
|
||||||
b += Rotate(a, 44);
|
b += Rotate(a, 44);
|
||||||
return make_pair(a + z, b + c);
|
return std::make_pair(a + z, b + c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
|
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
|
||||||
static pair<u64, u64> WeakHashLen32WithSeeds(const char* s, u64 a, u64 b) {
|
static std::pair<u64, u64> WeakHashLen32WithSeeds(const char* s, u64 a, u64 b) {
|
||||||
return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a,
|
return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a,
|
||||||
b);
|
b);
|
||||||
}
|
}
|
||||||
@@ -189,8 +190,8 @@ u64 CityHash64(const char* s, size_t len) {
|
|||||||
u64 x = Fetch64(s + len - 40);
|
u64 x = Fetch64(s + len - 40);
|
||||||
u64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
|
u64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
|
||||||
u64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
|
u64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
|
||||||
pair<u64, u64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
|
std::pair<u64, u64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
|
||||||
pair<u64, u64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
|
std::pair<u64, u64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
|
||||||
x = x * k1 + Fetch64(s);
|
x = x * k1 + Fetch64(s);
|
||||||
|
|
||||||
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
|
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
|
||||||
@@ -258,7 +259,7 @@ u128 CityHash128WithSeed(const char* s, size_t len, u128 seed) {
|
|||||||
|
|
||||||
// We expect len >= 128 to be the common case. Keep 56 bytes of state:
|
// We expect len >= 128 to be the common case. Keep 56 bytes of state:
|
||||||
// v, w, x, y, and z.
|
// v, w, x, y, and z.
|
||||||
pair<u64, u64> v, w;
|
std::pair<u64, u64> v, w;
|
||||||
u64 x = seed[0];
|
u64 x = seed[0];
|
||||||
u64 y = seed[1];
|
u64 y = seed[1];
|
||||||
u64 z = len * k1;
|
u64 z = len * k1;
|
||||||
|
|||||||
@@ -16,3 +16,5 @@
|
|||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#undef INVALID_SOCKET
|
||||||
|
|||||||
@@ -7,19 +7,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <dynarmic/interface/halt_reason.h>
|
#include <dynarmic/interface/halt_reason.h>
|
||||||
|
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
constexpr Dynarmic::HaltReason StepThread = Dynarmic::HaltReason::Step;
|
inline constexpr Dynarmic::HaltReason StepThread = Dynarmic::HaltReason::Step;
|
||||||
constexpr Dynarmic::HaltReason DataAbort = Dynarmic::HaltReason::MemoryAbort;
|
inline constexpr Dynarmic::HaltReason DataAbort = Dynarmic::HaltReason::MemoryAbort;
|
||||||
constexpr Dynarmic::HaltReason BreakLoop = Dynarmic::HaltReason::UserDefined2;
|
inline constexpr Dynarmic::HaltReason BreakLoop = Dynarmic::HaltReason::UserDefined2;
|
||||||
constexpr Dynarmic::HaltReason SupervisorCall = Dynarmic::HaltReason::UserDefined3;
|
inline constexpr Dynarmic::HaltReason SupervisorCall = Dynarmic::HaltReason::UserDefined3;
|
||||||
constexpr Dynarmic::HaltReason InstructionBreakpoint = Dynarmic::HaltReason::UserDefined4;
|
inline constexpr Dynarmic::HaltReason InstructionBreakpoint = Dynarmic::HaltReason::UserDefined4;
|
||||||
constexpr Dynarmic::HaltReason PrefetchAbort = Dynarmic::HaltReason::UserDefined6;
|
inline constexpr Dynarmic::HaltReason PrefetchAbort = Dynarmic::HaltReason::UserDefined6;
|
||||||
|
|
||||||
constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
|
[[nodiscard]] inline constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
|
||||||
static_assert(u64(HaltReason::StepThread) == u64(StepThread));
|
static_assert(u64(HaltReason::StepThread) == u64(StepThread));
|
||||||
static_assert(u64(HaltReason::DataAbort) == u64(DataAbort));
|
static_assert(u64(HaltReason::DataAbort) == u64(DataAbort));
|
||||||
static_assert(u64(HaltReason::BreakLoop) == u64(BreakLoop));
|
static_assert(u64(HaltReason::BreakLoop) == u64(BreakLoop));
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ namespace Core::Timing {
|
|||||||
|
|
||||||
constexpr s64 MAX_SLICE_LENGTH = 10000;
|
constexpr s64 MAX_SLICE_LENGTH = 10000;
|
||||||
|
|
||||||
|
#undef CreateEvent
|
||||||
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
|
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
|
||||||
return std::make_shared<EventType>(std::move(callback), std::move(name));
|
return std::make_shared<EventType>(std::move(callback), std::move(name));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -185,13 +185,13 @@ static_assert(sizeof(SaveDataFilter) == 0x48, "SaveDataFilter has invalid size."
|
|||||||
static_assert(std::is_trivially_copyable_v<SaveDataFilter>,
|
static_assert(std::is_trivially_copyable_v<SaveDataFilter>,
|
||||||
"Data type must be trivially copyable.");
|
"Data type must be trivially copyable.");
|
||||||
|
|
||||||
struct HashSalt {
|
struct SaveDataHashSalt {
|
||||||
static constexpr size_t Size = 32;
|
static constexpr size_t Size = 32;
|
||||||
|
|
||||||
std::array<u8, Size> value;
|
std::array<u8, Size> value;
|
||||||
};
|
};
|
||||||
static_assert(std::is_trivially_copyable_v<HashSalt>, "Data type must be trivially copyable.");
|
static_assert(std::is_trivially_copyable_v<SaveDataHashSalt>, "Data type must be trivially copyable.");
|
||||||
static_assert(sizeof(HashSalt) == HashSalt::Size);
|
static_assert(sizeof(SaveDataHashSalt) == SaveDataHashSalt::Size);
|
||||||
|
|
||||||
struct SaveDataCreationInfo2 {
|
struct SaveDataCreationInfo2 {
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ struct SaveDataCreationInfo2 {
|
|||||||
u8 reserved1;
|
u8 reserved1;
|
||||||
bool is_hash_salt_enabled;
|
bool is_hash_salt_enabled;
|
||||||
u8 reserved2;
|
u8 reserved2;
|
||||||
HashSalt hash_salt;
|
SaveDataHashSalt hash_salt;
|
||||||
SaveDataMetaType meta_type;
|
SaveDataMetaType meta_type;
|
||||||
u8 reserved3;
|
u8 reserved3;
|
||||||
s32 meta_size;
|
s32 meta_size;
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -11,7 +14,7 @@
|
|||||||
#include "core/file_sys/vfs/vfs.h"
|
#include "core/file_sys/vfs/vfs.h"
|
||||||
#include "core/file_sys/vfs/vfs_vector.h"
|
#include "core/file_sys/vfs/vfs_vector.h"
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys::RomFSBuilder {
|
||||||
|
|
||||||
constexpr u64 FS_MAX_PATH = 0x301;
|
constexpr u64 FS_MAX_PATH = 0x301;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -9,7 +12,7 @@
|
|||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/file_sys/vfs/vfs.h"
|
#include "core/file_sys/vfs/vfs.h"
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys::RomFSBuilder {
|
||||||
|
|
||||||
struct RomFSBuildDirectoryContext;
|
struct RomFSBuildDirectoryContext;
|
||||||
struct RomFSBuildFileContext;
|
struct RomFSBuildFileContext;
|
||||||
|
|||||||
+10
-10
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
@@ -38,7 +38,7 @@ struct RomFSHeader {
|
|||||||
};
|
};
|
||||||
static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size.");
|
static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size.");
|
||||||
|
|
||||||
struct DirectoryEntry {
|
struct RomFSDirectoryEntry {
|
||||||
u32_le parent;
|
u32_le parent;
|
||||||
u32_le sibling;
|
u32_le sibling;
|
||||||
u32_le child_dir;
|
u32_le child_dir;
|
||||||
@@ -46,9 +46,9 @@ struct DirectoryEntry {
|
|||||||
u32_le hash;
|
u32_le hash;
|
||||||
u32_le name_length;
|
u32_le name_length;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(DirectoryEntry) == 0x18, "DirectoryEntry has incorrect size.");
|
static_assert(sizeof(RomFSDirectoryEntry) == 0x18, "RomFSDirectoryEntry has incorrect size.");
|
||||||
|
|
||||||
struct FileEntry {
|
struct RomFSFileEntry {
|
||||||
u32_le parent;
|
u32_le parent;
|
||||||
u32_le sibling;
|
u32_le sibling;
|
||||||
u64_le offset;
|
u64_le offset;
|
||||||
@@ -56,7 +56,7 @@ struct FileEntry {
|
|||||||
u32_le hash;
|
u32_le hash;
|
||||||
u32_le name_length;
|
u32_le name_length;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size.");
|
static_assert(sizeof(RomFSFileEntry) == 0x20, "RomFSFileEntry has incorrect size.");
|
||||||
|
|
||||||
struct RomFSTraversalContext {
|
struct RomFSTraversalContext {
|
||||||
RomFSHeader header;
|
RomFSHeader header;
|
||||||
@@ -84,14 +84,14 @@ std::pair<EntryType, std::string> GetEntry(const RomFSTraversalContext& ctx, siz
|
|||||||
return {entry, std::move(name)};
|
return {entry, std::move(name)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<DirectoryEntry, std::string> GetDirectoryEntry(const RomFSTraversalContext& ctx,
|
std::pair<RomFSDirectoryEntry, std::string> GetDirectoryEntry(const RomFSTraversalContext& ctx,
|
||||||
size_t directory_offset) {
|
size_t directory_offset) {
|
||||||
return GetEntry<DirectoryEntry, &RomFSTraversalContext::directory_meta>(ctx, directory_offset);
|
return GetEntry<RomFSDirectoryEntry, &RomFSTraversalContext::directory_meta>(ctx, directory_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<FileEntry, std::string> GetFileEntry(const RomFSTraversalContext& ctx,
|
std::pair<RomFSFileEntry, std::string> GetFileEntry(const RomFSTraversalContext& ctx,
|
||||||
size_t file_offset) {
|
size_t file_offset) {
|
||||||
return GetEntry<FileEntry, &RomFSTraversalContext::file_meta>(ctx, file_offset);
|
return GetEntry<RomFSFileEntry, &RomFSTraversalContext::file_meta>(ctx, file_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessFile(const RomFSTraversalContext& ctx, u32 this_file_offset,
|
void ProcessFile(const RomFSTraversalContext& ctx, u32 this_file_offset,
|
||||||
@@ -163,7 +163,7 @@ VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) {
|
|||||||
if (dir == nullptr)
|
if (dir == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
RomFSBuildContext ctx{dir, ext};
|
RomFSBuilder::RomFSBuildContext ctx{dir, ext};
|
||||||
return ConcatenatedVfsFile::MakeConcatenatedFile(0, dir->GetName(), ctx.Build());
|
return ConcatenatedVfsFile::MakeConcatenatedFile(0, dir->GetName(), ctx.Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
@@ -10,6 +10,12 @@
|
|||||||
#include "common/fs/path_util.h"
|
#include "common/fs/path_util.h"
|
||||||
#include "core/file_sys/vfs/vfs.h"
|
#include "core/file_sys/vfs/vfs.h"
|
||||||
|
|
||||||
|
#undef CreateFile
|
||||||
|
#undef DeleteFile
|
||||||
|
#undef CreateDirectory
|
||||||
|
#undef CopyFile
|
||||||
|
#undef MoveFile
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|
||||||
VfsFilesystem::VfsFilesystem(VirtualDir root_) : root(std::move(root_)) {}
|
VfsFilesystem::VfsFilesystem(VirtualDir root_) : root(std::move(root_)) {}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
@@ -99,6 +99,10 @@ private:
|
|||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#undef CreateFile
|
||||||
|
#undef DeleteFile
|
||||||
|
#undef CreateDirectory
|
||||||
|
|
||||||
// An implementation of VfsDirectory that maintains two vectors for subdirectories and files.
|
// An implementation of VfsDirectory that maintains two vectors for subdirectories and files.
|
||||||
// Vector data is supplied upon construction.
|
// Vector data is supplied upon construction.
|
||||||
class VectorVfsDirectory : public VfsDirectory {
|
class VectorVfsDirectory : public VfsDirectory {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-late
|
// SPDX-License-Identifier: GPL-2.0-or-late
|
||||||
@@ -13,6 +13,10 @@
|
|||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
#include "core/hle/kernel/svc.h"
|
#include "core/hle/kernel/svc.h"
|
||||||
|
|
||||||
|
#undef OutputDebugString
|
||||||
|
#undef GetObject
|
||||||
|
#undef CreateProcess
|
||||||
|
|
||||||
namespace Kernel::Svc {
|
namespace Kernel::Svc {
|
||||||
|
|
||||||
static uint32_t GetArg32(std::span<uint64_t, 8> args, int n) {
|
static uint32_t GetArg32(std::span<uint64_t, 8> args, int n) {
|
||||||
|
|||||||
@@ -11,7 +11,11 @@
|
|||||||
namespace Kernel::Svc {
|
namespace Kernel::Svc {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) {
|
[[nodiscard]] inline constexpr bool IsValidSetAddressRange(u64 address, u64 size) {
|
||||||
|
return address + size > address;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) {
|
||||||
switch (perm) {
|
switch (perm) {
|
||||||
case MemoryPermission::None:
|
case MemoryPermission::None:
|
||||||
case MemoryPermission::Read:
|
case MemoryPermission::Read:
|
||||||
@@ -22,13 +26,6 @@ constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if address + size is greater than the given address
|
|
||||||
// This can return false if the size causes an overflow of a 64-bit type
|
|
||||||
// or if the given size is zero.
|
|
||||||
constexpr bool IsValidAddressRange(u64 address, u64 size) {
|
|
||||||
return address + size > address;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function that performs the common sanity checks for svcMapMemory
|
// Helper function that performs the common sanity checks for svcMapMemory
|
||||||
// and svcUnmapMemory. This is doable, as both functions perform their sanitizing
|
// and svcUnmapMemory. This is doable, as both functions perform their sanitizing
|
||||||
// in the same order.
|
// in the same order.
|
||||||
@@ -53,14 +50,17 @@ Result MapUnmapMemorySanityChecks(const KProcessPageTable& manager, u64 dst_addr
|
|||||||
R_THROW(ResultInvalidSize);
|
R_THROW(ResultInvalidSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsValidAddressRange(dst_addr, size)) {
|
// Checks if address + size is greater than the given address
|
||||||
|
// This can return false if the size causes an overflow of a 64-bit type
|
||||||
|
// or if the given size is zero.
|
||||||
|
if (!IsValidSetAddressRange(dst_addr, size)) {
|
||||||
LOG_ERROR(Kernel_SVC,
|
LOG_ERROR(Kernel_SVC,
|
||||||
"Destination is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
|
"Destination is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
|
||||||
dst_addr, size);
|
dst_addr, size);
|
||||||
R_THROW(ResultInvalidCurrentMemory);
|
R_THROW(ResultInvalidCurrentMemory);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsValidAddressRange(src_addr, size)) {
|
if (!IsValidSetAddressRange(src_addr, size)) {
|
||||||
LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
|
LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
|
||||||
src_addr, size);
|
src_addr, size);
|
||||||
R_THROW(ResultInvalidCurrentMemory);
|
R_THROW(ResultInvalidCurrentMemory);
|
||||||
|
|||||||
@@ -11,11 +11,11 @@
|
|||||||
namespace Kernel::Svc {
|
namespace Kernel::Svc {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr bool IsValidAddressRange(u64 address, u64 size) {
|
[[nodiscard]] inline constexpr bool IsValidAddressRange(u64 address, u64 size) {
|
||||||
return address + size > address;
|
return address + size > address;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
|
[[nodiscard]] inline constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
|
||||||
switch (perm) {
|
switch (perm) {
|
||||||
case Svc::MemoryPermission::None:
|
case Svc::MemoryPermission::None:
|
||||||
case Svc::MemoryPermission::Read:
|
case Svc::MemoryPermission::Read:
|
||||||
|
|||||||
@@ -9,13 +9,12 @@
|
|||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
|
|
||||||
namespace Service::Audio {
|
namespace Service::Audio {
|
||||||
using namespace AudioCore::AudioIn;
|
|
||||||
|
|
||||||
IAudioIn::IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
|
IAudioIn::IAudioIn(Core::System& system_, AudioCore::AudioIn::Manager& manager, size_t session_id,
|
||||||
const std::string& device_name, const AudioInParameter& in_params,
|
const std::string& device_name, const AudioCore::AudioIn::AudioInParameter& in_params,
|
||||||
Kernel::KProcess* handle, u64 applet_resource_user_id)
|
Kernel::KProcess* handle, u64 applet_resource_user_id)
|
||||||
: ServiceFramework{system_, "IAudioIn"}, process{handle}, service_context{system_, "IAudioIn"},
|
: ServiceFramework{system_, "IAudioIn"}, process{handle}, service_context{system_, "IAudioIn"},
|
||||||
event{service_context.CreateEvent("AudioInEvent")}, impl{std::make_shared<In>(system_,
|
event{service_context.CreateEvent("AudioInEvent")}, impl{std::make_shared<AudioCore::AudioIn::In>(system_,
|
||||||
manager, event,
|
manager, event,
|
||||||
session_id)} {
|
session_id)} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@@ -71,12 +70,12 @@ Result IAudioIn::Stop() {
|
|||||||
R_RETURN(impl->StopSystem());
|
R_RETURN(impl->StopSystem());
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioIn::AppendAudioInBuffer(InArray<AudioInBuffer, BufferAttr_HipcMapAlias> buffer,
|
Result IAudioIn::AppendAudioInBuffer(InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcMapAlias> buffer,
|
||||||
u64 buffer_client_ptr) {
|
u64 buffer_client_ptr) {
|
||||||
R_RETURN(this->AppendAudioInBufferAuto(buffer, buffer_client_ptr));
|
R_RETURN(this->AppendAudioInBufferAuto(buffer, buffer_client_ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioIn::AppendAudioInBufferAuto(InArray<AudioInBuffer, BufferAttr_HipcAutoSelect> buffer,
|
Result IAudioIn::AppendAudioInBufferAuto(InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcAutoSelect> buffer,
|
||||||
u64 buffer_client_ptr) {
|
u64 buffer_client_ptr) {
|
||||||
if (buffer.empty()) {
|
if (buffer.empty()) {
|
||||||
LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
|
LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -7,7 +10,6 @@
|
|||||||
#include "core/hle/service/cmif_serialization.h"
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
|
|
||||||
namespace Service::Audio {
|
namespace Service::Audio {
|
||||||
using namespace AudioCore::AudioIn;
|
|
||||||
|
|
||||||
IAudioInManager::IAudioInManager(Core::System& system_)
|
IAudioInManager::IAudioInManager(Core::System& system_)
|
||||||
: ServiceFramework{system_, "audin:u"}, impl{std::make_unique<AudioCore::AudioIn::Manager>(
|
: ServiceFramework{system_, "audin:u"}, impl{std::make_unique<AudioCore::AudioIn::Manager>(
|
||||||
@@ -34,11 +36,11 @@ Result IAudioInManager::ListAudioIns(
|
|||||||
R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count));
|
R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioInManager::OpenAudioIn(Out<AudioInParameterInternal> out_parameter_internal,
|
Result IAudioInManager::OpenAudioIn(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
|
||||||
Out<SharedPointer<IAudioIn>> out_audio_in,
|
Out<SharedPointer<IAudioIn>> out_audio_in,
|
||||||
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
|
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
|
||||||
InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
|
InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
|
||||||
AudioInParameter parameter,
|
AudioCore::AudioIn::AudioInParameter parameter,
|
||||||
InCopyHandle<Kernel::KProcess> process_handle,
|
InCopyHandle<Kernel::KProcess> process_handle,
|
||||||
ClientAppletResourceUserId aruid) {
|
ClientAppletResourceUserId aruid) {
|
||||||
LOG_DEBUG(Service_Audio, "called");
|
LOG_DEBUG(Service_Audio, "called");
|
||||||
@@ -53,9 +55,9 @@ Result IAudioInManager::ListAudioInsAuto(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioInManager::OpenAudioInAuto(
|
Result IAudioInManager::OpenAudioInAuto(
|
||||||
Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
|
Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
|
||||||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
|
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
|
||||||
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioInParameter parameter,
|
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioCore::AudioIn::AudioInParameter parameter,
|
||||||
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
|
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
|
||||||
LOG_DEBUG(Service_Audio, "called");
|
LOG_DEBUG(Service_Audio, "called");
|
||||||
R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name,
|
R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name,
|
||||||
@@ -70,10 +72,10 @@ Result IAudioInManager::ListAudioInsAutoFiltered(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioInManager::OpenAudioInProtocolSpecified(
|
Result IAudioInManager::OpenAudioInProtocolSpecified(
|
||||||
Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
|
Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
|
||||||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
|
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
|
||||||
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol,
|
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol,
|
||||||
AudioInParameter parameter, InCopyHandle<Kernel::KProcess> process_handle,
|
AudioCore::AudioIn::AudioInParameter parameter, InCopyHandle<Kernel::KProcess> process_handle,
|
||||||
ClientAppletResourceUserId aruid) {
|
ClientAppletResourceUserId aruid) {
|
||||||
LOG_DEBUG(Service_Audio, "called");
|
LOG_DEBUG(Service_Audio, "called");
|
||||||
|
|
||||||
@@ -104,7 +106,7 @@ Result IAudioInManager::OpenAudioInProtocolSpecified(
|
|||||||
|
|
||||||
auto& out_system = impl->sessions[new_session_id]->GetSystem();
|
auto& out_system = impl->sessions[new_session_id]->GetSystem();
|
||||||
*out_parameter_internal =
|
*out_parameter_internal =
|
||||||
AudioInParameterInternal{.sample_rate = out_system.GetSampleRate(),
|
AudioCore::AudioIn::AudioInParameterInternal{.sample_rate = out_system.GetSampleRate(),
|
||||||
.channel_count = out_system.GetChannelCount(),
|
.channel_count = out_system.GetChannelCount(),
|
||||||
.sample_format = static_cast<u32>(out_system.GetSampleFormat()),
|
.sample_format = static_cast<u32>(out_system.GetSampleFormat()),
|
||||||
.state = static_cast<u32>(out_system.GetState())};
|
.state = static_cast<u32>(out_system.GetState())};
|
||||||
|
|||||||
@@ -13,10 +13,9 @@
|
|||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Service::Audio {
|
namespace Service::Audio {
|
||||||
using namespace AudioCore::AudioOut;
|
|
||||||
|
|
||||||
IAudioOut::IAudioOut(Core::System& system_, Manager& manager, size_t session_id,
|
IAudioOut::IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, size_t session_id,
|
||||||
const std::string& device_name, const AudioOutParameter& in_params,
|
const std::string& device_name, const AudioCore::AudioOut::AudioOutParameter& in_params,
|
||||||
Kernel::KProcess* handle, u64 applet_resource_user_id)
|
Kernel::KProcess* handle, u64 applet_resource_user_id)
|
||||||
: ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
|
: ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
|
||||||
event{service_context.CreateEvent("AudioOutEvent")}, process{handle},
|
event{service_context.CreateEvent("AudioOutEvent")}, process{handle},
|
||||||
@@ -68,12 +67,12 @@ Result IAudioOut::Stop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioOut::AppendAudioOutBuffer(
|
Result IAudioOut::AppendAudioOutBuffer(
|
||||||
InArray<AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer, u64 buffer_client_ptr) {
|
InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer, u64 buffer_client_ptr) {
|
||||||
R_RETURN(this->AppendAudioOutBufferAuto(audio_out_buffer, buffer_client_ptr));
|
R_RETURN(this->AppendAudioOutBufferAuto(audio_out_buffer, buffer_client_ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioOut::AppendAudioOutBufferAuto(
|
Result IAudioOut::AppendAudioOutBufferAuto(
|
||||||
InArray<AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer, u64 buffer_client_ptr) {
|
InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer, u64 buffer_client_ptr) {
|
||||||
if (audio_out_buffer.empty()) {
|
if (audio_out_buffer.empty()) {
|
||||||
LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!");
|
LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!");
|
||||||
R_THROW(Audio::ResultInsufficientBuffer);
|
R_THROW(Audio::ResultInsufficientBuffer);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
namespace Service::Audio {
|
namespace Service::Audio {
|
||||||
using namespace AudioCore::AudioOut;
|
|
||||||
|
|
||||||
IAudioOutManager::IAudioOutManager(Core::System& system_)
|
IAudioOutManager::IAudioOutManager(Core::System& system_)
|
||||||
: ServiceFramework{system_, "audout:u"}
|
: ServiceFramework{system_, "audout:u"}
|
||||||
@@ -36,11 +35,11 @@ Result IAudioOutManager::ListAudioOuts(
|
|||||||
R_RETURN(this->ListAudioOutsAuto(out_audio_outs, out_count));
|
R_RETURN(this->ListAudioOutsAuto(out_audio_outs, out_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioOutManager::OpenAudioOut(Out<AudioOutParameterInternal> out_parameter_internal,
|
Result IAudioOutManager::OpenAudioOut(Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
|
||||||
Out<SharedPointer<IAudioOut>> out_audio_out,
|
Out<SharedPointer<IAudioOut>> out_audio_out,
|
||||||
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
|
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
|
||||||
InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
|
InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
|
||||||
AudioOutParameter parameter,
|
AudioCore::AudioOut::AudioOutParameter parameter,
|
||||||
InCopyHandle<Kernel::KProcess> process_handle,
|
InCopyHandle<Kernel::KProcess> process_handle,
|
||||||
ClientAppletResourceUserId aruid) {
|
ClientAppletResourceUserId aruid) {
|
||||||
R_RETURN(this->OpenAudioOutAuto(out_parameter_internal, out_audio_out, out_name, name,
|
R_RETURN(this->OpenAudioOutAuto(out_parameter_internal, out_audio_out, out_name, name,
|
||||||
@@ -62,10 +61,10 @@ Result IAudioOutManager::ListAudioOutsAuto(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result IAudioOutManager::OpenAudioOutAuto(
|
Result IAudioOutManager::OpenAudioOutAuto(
|
||||||
Out<AudioOutParameterInternal> out_parameter_internal,
|
Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
|
||||||
Out<SharedPointer<IAudioOut>> out_audio_out,
|
Out<SharedPointer<IAudioOut>> out_audio_out,
|
||||||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
|
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
|
||||||
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioOutParameter parameter,
|
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioCore::AudioOut::AudioOutParameter parameter,
|
||||||
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
|
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
|
||||||
if (!process_handle) {
|
if (!process_handle) {
|
||||||
LOG_ERROR(Service_Audio, "Failed to get process handle");
|
LOG_ERROR(Service_Audio, "Failed to get process handle");
|
||||||
@@ -95,7 +94,7 @@ Result IAudioOutManager::OpenAudioOutAuto(
|
|||||||
|
|
||||||
auto& out_system = impl->sessions[new_session_id]->GetSystem();
|
auto& out_system = impl->sessions[new_session_id]->GetSystem();
|
||||||
*out_parameter_internal =
|
*out_parameter_internal =
|
||||||
AudioOutParameterInternal{.sample_rate = out_system.GetSampleRate(),
|
AudioCore::AudioOut::AudioOutParameterInternal{.sample_rate = out_system.GetSampleRate(),
|
||||||
.channel_count = out_system.GetChannelCount(),
|
.channel_count = out_system.GetChannelCount(),
|
||||||
.sample_format = static_cast<u32>(out_system.GetSampleFormat()),
|
.sample_format = static_cast<u32>(out_system.GetSampleFormat()),
|
||||||
.state = static_cast<u32>(out_system.GetState())};
|
.state = static_cast<u32>(out_system.GetState())};
|
||||||
|
|||||||
@@ -4,21 +4,20 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "audio_core/renderer/audio_renderer.h"
|
||||||
#include "core/hle/service/audio/audio_renderer.h"
|
#include "core/hle/service/audio/audio_renderer.h"
|
||||||
#include "core/hle/service/cmif_serialization.h"
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
|
|
||||||
namespace Service::Audio {
|
namespace Service::Audio {
|
||||||
using namespace AudioCore::Renderer;
|
|
||||||
|
|
||||||
IAudioRenderer::IAudioRenderer(Core::System& system_, Manager& manager_,
|
IAudioRenderer::IAudioRenderer(Core::System& system_, AudioCore::Renderer::Manager& manager_,
|
||||||
AudioCore::AudioRendererParameterInternal& params,
|
AudioCore::AudioRendererParameterInternal& params,
|
||||||
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
|
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
|
||||||
Kernel::KProcess* process_handle_, u64 applet_resource_user_id,
|
Kernel::KProcess* process_handle_, u64 applet_resource_user_id,
|
||||||
s32 session_id)
|
s32 session_id)
|
||||||
: ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
|
: ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
|
||||||
rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
|
rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
|
||||||
impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process_handle{
|
impl{std::make_unique<AudioCore::Renderer::Renderer>(system_, manager, rendered_event)}, process_handle{process_handle_} {
|
||||||
process_handle_} {
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, D<&IAudioRenderer::GetSampleRate>, "GetSampleRate"},
|
{0, D<&IAudioRenderer::GetSampleRate>, "GetSampleRate"},
|
||||||
|
|||||||
@@ -14,16 +14,13 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
namespace Service::News {
|
namespace Service::News {
|
||||||
namespace {
|
|
||||||
|
|
||||||
std::string_view ToStringView(std::span<const char> buf) {
|
[[nodiscard]] inline std::string_view ToStringViewNDS(std::span<const char> buf) {
|
||||||
const std::string_view sv{buf.data(), buf.size()};
|
const std::string_view sv{buf.data(), buf.size()};
|
||||||
const auto nul = sv.find('\0');
|
const auto nul = sv.find('\0');
|
||||||
return nul == std::string_view::npos ? sv : sv.substr(0, nul);
|
return nul == std::string_view::npos ? sv : sv.substr(0, nul);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
INewsDataService::INewsDataService(Core::System& system_)
|
INewsDataService::INewsDataService(Core::System& system_)
|
||||||
: ServiceFramework{system_, "INewsDataService"} {
|
: ServiceFramework{system_, "INewsDataService"} {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
@@ -55,7 +52,7 @@ bool INewsDataService::TryOpen(std::string_view key, std::string_view user) {
|
|||||||
|
|
||||||
const auto list = NewsStorage::Instance().ListAll();
|
const auto list = NewsStorage::Instance().ListAll();
|
||||||
if (!list.empty()) {
|
if (!list.empty()) {
|
||||||
if (auto found = NewsStorage::Instance().FindByNewsId(ToStringView(list.front().news_id))) {
|
if (auto found = NewsStorage::Instance().FindByNewsId(ToStringViewNDS(list.front().news_id))) {
|
||||||
opened_payload = std::move(found->payload);
|
opened_payload = std::move(found->payload);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -67,7 +64,7 @@ bool INewsDataService::TryOpen(std::string_view key, std::string_view user) {
|
|||||||
Result INewsDataService::Open(InBuffer<BufferAttr_HipcMapAlias> name) {
|
Result INewsDataService::Open(InBuffer<BufferAttr_HipcMapAlias> name) {
|
||||||
EnsureBuiltinNewsLoaded();
|
EnsureBuiltinNewsLoaded();
|
||||||
|
|
||||||
const auto key = ToStringView({reinterpret_cast<const char*>(name.data()), name.size()});
|
const auto key = ToStringViewNDS({reinterpret_cast<const char*>(name.data()), name.size()});
|
||||||
|
|
||||||
if (TryOpen(key, {})) {
|
if (TryOpen(key, {})) {
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
@@ -79,8 +76,8 @@ Result INewsDataService::Open(InBuffer<BufferAttr_HipcMapAlias> name) {
|
|||||||
Result INewsDataService::OpenWithNewsRecordV1(NewsRecordV1 record) {
|
Result INewsDataService::OpenWithNewsRecordV1(NewsRecordV1 record) {
|
||||||
EnsureBuiltinNewsLoaded();
|
EnsureBuiltinNewsLoaded();
|
||||||
|
|
||||||
const auto key = ToStringView(record.news_id);
|
const auto key = ToStringViewNDS(record.news_id);
|
||||||
const auto user = ToStringView(record.user_id);
|
const auto user = ToStringViewNDS(record.user_id);
|
||||||
|
|
||||||
if (TryOpen(key, user)) {
|
if (TryOpen(key, user)) {
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
@@ -92,8 +89,8 @@ Result INewsDataService::OpenWithNewsRecordV1(NewsRecordV1 record) {
|
|||||||
Result INewsDataService::OpenWithNewsRecord(NewsRecord record) {
|
Result INewsDataService::OpenWithNewsRecord(NewsRecord record) {
|
||||||
EnsureBuiltinNewsLoaded();
|
EnsureBuiltinNewsLoaded();
|
||||||
|
|
||||||
const auto key = ToStringView(record.news_id);
|
const auto key = ToStringViewNDS(record.news_id);
|
||||||
const auto user = ToStringView(record.user_id);
|
const auto user = ToStringViewNDS(record.user_id);
|
||||||
|
|
||||||
if (TryOpen(key, user)) {
|
if (TryOpen(key, user)) {
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -15,13 +15,13 @@
|
|||||||
namespace Service::News {
|
namespace Service::News {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::string_view ToStringView(std::span<const u8> buf) {
|
[[nodiscard]] inline std::string_view ToStringView(std::span<const u8> buf) {
|
||||||
if (buf.empty()) return {};
|
if (buf.empty()) return {};
|
||||||
auto data = reinterpret_cast<const char*>(buf.data());
|
auto data = reinterpret_cast<const char*>(buf.data());
|
||||||
return {data, strnlen(data, buf.size())};
|
return {data, strnlen(data, buf.size())};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view ToStringView(std::span<const char> buf) {
|
[[nodiscard]] inline std::string_view ToStringView(std::span<const char> buf) {
|
||||||
if (buf.empty()) return {};
|
if (buf.empty()) return {};
|
||||||
return {buf.data(), strnlen(buf.data(), buf.size())};
|
return {buf.data(), strnlen(buf.data(), buf.size())};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
@@ -6,6 +9,8 @@
|
|||||||
|
|
||||||
namespace Service::News {
|
namespace Service::News {
|
||||||
|
|
||||||
|
#undef CreateEvent
|
||||||
|
|
||||||
IOverwriteEventHolder::IOverwriteEventHolder(Core::System& system_)
|
IOverwriteEventHolder::IOverwriteEventHolder(Core::System& system_)
|
||||||
: ServiceFramework{system_, "IOverwriteEventHolder"}, service_context{system_,
|
: ServiceFramework{system_, "IOverwriteEventHolder"}, service_context{system_,
|
||||||
"IOverwriteEventHolder"} {
|
"IOverwriteEventHolder"} {
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
#include "core/hle/service/sm/sm.h"
|
#include "core/hle/service/sm/sm.h"
|
||||||
|
|
||||||
|
#undef GetCurrentTime
|
||||||
|
|
||||||
namespace Service::Capture {
|
namespace Service::Capture {
|
||||||
|
|
||||||
AlbumManager::AlbumManager(Core::System& system_) : system{system_} {}
|
AlbumManager::AlbumManager(Core::System& system_) : system{system_} {}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
#include "core/hle/service/server_manager.h"
|
#include "core/hle/service/server_manager.h"
|
||||||
#include "core/reporter.h"
|
#include "core/reporter.h"
|
||||||
|
|
||||||
|
#undef far
|
||||||
|
|
||||||
namespace Service::Fatal {
|
namespace Service::Fatal {
|
||||||
|
|
||||||
Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
|
Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
|
||||||
|
|||||||
@@ -32,6 +32,10 @@
|
|||||||
#include "core/hle/service/server_manager.h"
|
#include "core/hle/service/server_manager.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
|
|
||||||
|
#undef CreateFile
|
||||||
|
#undef DeleteFile
|
||||||
|
#undef CreateDirectory
|
||||||
|
|
||||||
namespace Service::FileSystem {
|
namespace Service::FileSystem {
|
||||||
|
|
||||||
static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
|
static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
|
#undef SendMessage
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
|
|
||||||
SessionRequestHandler::SessionRequestHandler(Kernel::KernelCore& kernel_, const char* service_name_)
|
SessionRequestHandler::SessionRequestHandler(Kernel::KernelCore& kernel_, const char* service_name_)
|
||||||
|
|||||||
@@ -212,8 +212,9 @@ struct NifmNetworkProfileData {
|
|||||||
NifmWirelessSettingData wireless_setting_data{};
|
NifmWirelessSettingData wireless_setting_data{};
|
||||||
IpSettingData ip_setting_data{};
|
IpSettingData ip_setting_data{};
|
||||||
};
|
};
|
||||||
|
static_assert(sizeof(NifmNetworkProfileData) == 0x18E,
|
||||||
|
"NifmNetworkProfileData has incorrect size.");
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
static_assert(sizeof(NifmNetworkProfileData) == 0x18E, "NifmNetworkProfileData has incorrect size.");
|
|
||||||
|
|
||||||
struct PendingProfile {
|
struct PendingProfile {
|
||||||
std::array<char, 0x21> ssid{};
|
std::array<char, 0x21> ssid{};
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -10,6 +13,8 @@
|
|||||||
namespace Service::PSC::Time {
|
namespace Service::PSC::Time {
|
||||||
class ContextWriter;
|
class ContextWriter;
|
||||||
|
|
||||||
|
#undef GetCurrentTime
|
||||||
|
|
||||||
class SystemClockCore {
|
class SystemClockCore {
|
||||||
public:
|
public:
|
||||||
explicit SystemClockCore(SteadyClockCore& steady_clock) : m_steady_clock{steady_clock} {}
|
explicit SystemClockCore(SteadyClockCore& steady_clock) : m_steady_clock{steady_clock} {}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ class System;
|
|||||||
|
|
||||||
namespace Service::PSC::Time {
|
namespace Service::PSC::Time {
|
||||||
|
|
||||||
|
#undef GetCurrentTime
|
||||||
|
|
||||||
class SystemClock final : public ServiceFramework<SystemClock> {
|
class SystemClock final : public ServiceFramework<SystemClock> {
|
||||||
public:
|
public:
|
||||||
explicit SystemClock(Core::System& system, SystemClockCore& system_clock_core, bool can_write_clock, bool can_write_uninitialized_clock);
|
explicit SystemClock(Core::System& system, SystemClockCore& system_clock_core, bool can_write_clock, bool can_write_uninitialized_clock);
|
||||||
|
|||||||
@@ -54,11 +54,11 @@ void PutValue(std::span<u8> buffer, const T& t) {
|
|||||||
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
void BSD::PollWork::Execute(BSD* bsd) {
|
void NetworkBSD::PollWork::Execute(NetworkBSD* bsd) {
|
||||||
std::tie(ret, bsd_errno) = bsd->PollImpl(write_buffer, read_buffer, nfds, timeout);
|
std::tie(ret, bsd_errno) = bsd->PollImpl(write_buffer, read_buffer, nfds, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::PollWork::Response(HLERequestContext& ctx) {
|
void NetworkBSD::PollWork::Response(HLERequestContext& ctx) {
|
||||||
if (write_buffer.size() > 0) {
|
if (write_buffer.size() > 0) {
|
||||||
ctx.WriteBuffer(write_buffer);
|
ctx.WriteBuffer(write_buffer);
|
||||||
}
|
}
|
||||||
@@ -69,11 +69,11 @@ void BSD::PollWork::Response(HLERequestContext& ctx) {
|
|||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::AcceptWork::Execute(BSD* bsd) {
|
void NetworkBSD::AcceptWork::Execute(NetworkBSD* bsd) {
|
||||||
std::tie(ret, bsd_errno) = bsd->AcceptImpl(fd, write_buffer);
|
std::tie(ret, bsd_errno) = bsd->AcceptImpl(fd, write_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::AcceptWork::Response(HLERequestContext& ctx) {
|
void NetworkBSD::AcceptWork::Response(HLERequestContext& ctx) {
|
||||||
if (write_buffer.size() > 0) {
|
if (write_buffer.size() > 0) {
|
||||||
ctx.WriteBuffer(write_buffer);
|
ctx.WriteBuffer(write_buffer);
|
||||||
}
|
}
|
||||||
@@ -85,22 +85,22 @@ void BSD::AcceptWork::Response(HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::ConnectWork::Execute(BSD* bsd) {
|
void NetworkBSD::ConnectWork::Execute(NetworkBSD* bsd) {
|
||||||
bsd_errno = bsd->ConnectImpl(fd, addr);
|
bsd_errno = bsd->ConnectImpl(fd, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::ConnectWork::Response(HLERequestContext& ctx) {
|
void NetworkBSD::ConnectWork::Response(HLERequestContext& ctx) {
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
|
rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
|
||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::RecvWork::Execute(BSD* bsd) {
|
void NetworkBSD::RecvWork::Execute(NetworkBSD* bsd) {
|
||||||
std::tie(ret, bsd_errno) = bsd->RecvImpl(fd, flags, message);
|
std::tie(ret, bsd_errno) = bsd->RecvImpl(fd, flags, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::RecvWork::Response(HLERequestContext& ctx) {
|
void NetworkBSD::RecvWork::Response(HLERequestContext& ctx) {
|
||||||
ctx.WriteBuffer(message);
|
ctx.WriteBuffer(message);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
@@ -109,11 +109,11 @@ void BSD::RecvWork::Response(HLERequestContext& ctx) {
|
|||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::RecvFromWork::Execute(BSD* bsd) {
|
void NetworkBSD::RecvFromWork::Execute(NetworkBSD* bsd) {
|
||||||
std::tie(ret, bsd_errno) = bsd->RecvFromImpl(fd, flags, message, addr);
|
std::tie(ret, bsd_errno) = bsd->RecvFromImpl(fd, flags, message, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::RecvFromWork::Response(HLERequestContext& ctx) {
|
void NetworkBSD::RecvFromWork::Response(HLERequestContext& ctx) {
|
||||||
ctx.WriteBuffer(message, 0);
|
ctx.WriteBuffer(message, 0);
|
||||||
if (!addr.empty()) {
|
if (!addr.empty()) {
|
||||||
ctx.WriteBuffer(addr, 1);
|
ctx.WriteBuffer(addr, 1);
|
||||||
@@ -126,29 +126,29 @@ void BSD::RecvFromWork::Response(HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(static_cast<u32>(addr.size()));
|
rb.Push<u32>(static_cast<u32>(addr.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::SendWork::Execute(BSD* bsd) {
|
void NetworkBSD::SendWork::Execute(NetworkBSD* bsd) {
|
||||||
std::tie(ret, bsd_errno) = bsd->SendImpl(fd, flags, message);
|
std::tie(ret, bsd_errno) = bsd->SendImpl(fd, flags, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::SendWork::Response(HLERequestContext& ctx) {
|
void NetworkBSD::SendWork::Response(HLERequestContext& ctx) {
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push<s32>(ret);
|
rb.Push<s32>(ret);
|
||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::SendToWork::Execute(BSD* bsd) {
|
void NetworkBSD::SendToWork::Execute(NetworkBSD* bsd) {
|
||||||
std::tie(ret, bsd_errno) = bsd->SendToImpl(fd, flags, message, addr);
|
std::tie(ret, bsd_errno) = bsd->SendToImpl(fd, flags, message, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::SendToWork::Response(HLERequestContext& ctx) {
|
void NetworkBSD::SendToWork::Response(HLERequestContext& ctx) {
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push<s32>(ret);
|
rb.Push<s32>(ret);
|
||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::RegisterClient(HLERequestContext& ctx) {
|
void NetworkBSD::RegisterClient(HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service, "(STUBBED) called");
|
LOG_WARNING(Service, "(STUBBED) called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
@@ -157,7 +157,7 @@ void BSD::RegisterClient(HLERequestContext& ctx) {
|
|||||||
rb.Push<s32>(0); // bsd errno
|
rb.Push<s32>(0); // bsd errno
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::StartMonitoring(HLERequestContext& ctx) {
|
void NetworkBSD::StartMonitoring(HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service, "(STUBBED) called");
|
LOG_WARNING(Service, "(STUBBED) called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
@@ -165,7 +165,7 @@ void BSD::StartMonitoring(HLERequestContext& ctx) {
|
|||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Socket(HLERequestContext& ctx) {
|
void NetworkBSD::Socket(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const u32 domain = rp.Pop<u32>();
|
const u32 domain = rp.Pop<u32>();
|
||||||
const u32 type = rp.Pop<u32>();
|
const u32 type = rp.Pop<u32>();
|
||||||
@@ -182,7 +182,7 @@ void BSD::Socket(HLERequestContext& ctx) {
|
|||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Select(HLERequestContext& ctx) {
|
void NetworkBSD::Select(HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service, "(STUBBED) called");
|
LOG_DEBUG(Service, "(STUBBED) called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
@@ -192,7 +192,7 @@ void BSD::Select(HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(0); // bsd errno
|
rb.Push<u32>(0); // bsd errno
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Poll(HLERequestContext& ctx) {
|
void NetworkBSD::Poll(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 nfds = rp.Pop<s32>();
|
const s32 nfds = rp.Pop<s32>();
|
||||||
const s32 timeout = rp.Pop<s32>();
|
const s32 timeout = rp.Pop<s32>();
|
||||||
@@ -207,7 +207,7 @@ void BSD::Poll(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Accept(HLERequestContext& ctx) {
|
void NetworkBSD::Accept(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -219,7 +219,7 @@ void BSD::Accept(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Bind(HLERequestContext& ctx) {
|
void NetworkBSD::Bind(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@ void BSD::Bind(HLERequestContext& ctx) {
|
|||||||
BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer()));
|
BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Connect(HLERequestContext& ctx) {
|
void NetworkBSD::Connect(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -239,7 +239,7 @@ void BSD::Connect(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::GetPeerName(HLERequestContext& ctx) {
|
void NetworkBSD::GetPeerName(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -257,7 +257,7 @@ void BSD::GetPeerName(HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::GetSockName(HLERequestContext& ctx) {
|
void NetworkBSD::GetSockName(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -275,7 +275,7 @@ void BSD::GetSockName(HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::GetSockOpt(HLERequestContext& ctx) {
|
void NetworkBSD::GetSockOpt(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
const u32 level = rp.Pop<u32>();
|
const u32 level = rp.Pop<u32>();
|
||||||
@@ -297,7 +297,7 @@ void BSD::GetSockOpt(HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(static_cast<u32>(optval.size()));
|
rb.Push<u32>(static_cast<u32>(optval.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Listen(HLERequestContext& ctx) {
|
void NetworkBSD::Listen(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
const s32 backlog = rp.Pop<s32>();
|
const s32 backlog = rp.Pop<s32>();
|
||||||
@@ -307,7 +307,7 @@ void BSD::Listen(HLERequestContext& ctx) {
|
|||||||
BuildErrnoResponse(ctx, ListenImpl(fd, backlog));
|
BuildErrnoResponse(ctx, ListenImpl(fd, backlog));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Fcntl(HLERequestContext& ctx) {
|
void NetworkBSD::Fcntl(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
const s32 cmd = rp.Pop<s32>();
|
const s32 cmd = rp.Pop<s32>();
|
||||||
@@ -323,7 +323,7 @@ void BSD::Fcntl(HLERequestContext& ctx) {
|
|||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::SetSockOpt(HLERequestContext& ctx) {
|
void NetworkBSD::SetSockOpt(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
@@ -337,7 +337,7 @@ void BSD::SetSockOpt(HLERequestContext& ctx) {
|
|||||||
BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval));
|
BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Shutdown(HLERequestContext& ctx) {
|
void NetworkBSD::Shutdown(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
@@ -348,7 +348,7 @@ void BSD::Shutdown(HLERequestContext& ctx) {
|
|||||||
BuildErrnoResponse(ctx, ShutdownImpl(fd, how));
|
BuildErrnoResponse(ctx, ShutdownImpl(fd, how));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Recv(HLERequestContext& ctx) {
|
void NetworkBSD::Recv(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
@@ -363,7 +363,7 @@ void BSD::Recv(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::RecvFrom(HLERequestContext& ctx) {
|
void NetworkBSD::RecvFrom(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
@@ -380,7 +380,7 @@ void BSD::RecvFrom(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Send(HLERequestContext& ctx) {
|
void NetworkBSD::Send(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
@@ -395,7 +395,7 @@ void BSD::Send(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::SendTo(HLERequestContext& ctx) {
|
void NetworkBSD::SendTo(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
const u32 flags = rp.Pop<u32>();
|
const u32 flags = rp.Pop<u32>();
|
||||||
@@ -411,7 +411,7 @@ void BSD::SendTo(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Write(HLERequestContext& ctx) {
|
void NetworkBSD::Write(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -424,7 +424,7 @@ void BSD::Write(HLERequestContext& ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Read(HLERequestContext& ctx) {
|
void NetworkBSD::Read(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -436,7 +436,7 @@ void BSD::Read(HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(0); // bsd errno
|
rb.Push<u32>(0); // bsd errno
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::Close(HLERequestContext& ctx) {
|
void NetworkBSD::Close(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const s32 fd = rp.Pop<s32>();
|
const s32 fd = rp.Pop<s32>();
|
||||||
|
|
||||||
@@ -445,7 +445,7 @@ void BSD::Close(HLERequestContext& ctx) {
|
|||||||
BuildErrnoResponse(ctx, CloseImpl(fd));
|
BuildErrnoResponse(ctx, CloseImpl(fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::DuplicateSocket(HLERequestContext& ctx) {
|
void NetworkBSD::DuplicateSocket(HLERequestContext& ctx) {
|
||||||
struct InputParameters {
|
struct InputParameters {
|
||||||
s32 fd;
|
s32 fd;
|
||||||
u64 reserved;
|
u64 reserved;
|
||||||
@@ -479,7 +479,7 @@ void BSD::DuplicateSocket(HLERequestContext& ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::EventFd(HLERequestContext& ctx) {
|
void NetworkBSD::EventFd(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const u64 initval = rp.Pop<u64>();
|
const u64 initval = rp.Pop<u64>();
|
||||||
const u32 flags = rp.Pop<u32>();
|
const u32 flags = rp.Pop<u32>();
|
||||||
@@ -490,12 +490,12 @@ void BSD::EventFd(HLERequestContext& ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Work>
|
template <typename Work>
|
||||||
void BSD::ExecuteWork(HLERequestContext& ctx, Work work) {
|
void NetworkBSD::ExecuteWork(HLERequestContext& ctx, Work work) {
|
||||||
work.Execute(this);
|
work.Execute(this);
|
||||||
work.Response(ctx);
|
work.Response(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protocol) {
|
std::pair<s32, Errno> NetworkBSD::SocketImpl(Domain domain, Type type, Protocol protocol) {
|
||||||
|
|
||||||
if (type == Type::SEQPACKET) {
|
if (type == Type::SEQPACKET) {
|
||||||
UNIMPLEMENTED_MSG("SOCK_SEQPACKET errno management");
|
UNIMPLEMENTED_MSG("SOCK_SEQPACKET errno management");
|
||||||
@@ -537,7 +537,7 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
|
|||||||
return {fd, Errno::SUCCESS};
|
return {fd, Errno::SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
|
std::pair<s32, Errno> NetworkBSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
|
||||||
s32 nfds, s32 timeout) {
|
s32 nfds, s32 timeout) {
|
||||||
if (nfds <= 0) {
|
if (nfds <= 0) {
|
||||||
// When no entries are provided, -1 is returned with errno zero
|
// When no entries are provided, -1 is returned with errno zero
|
||||||
@@ -604,7 +604,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con
|
|||||||
return Translate(result);
|
return Translate(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
|
std::pair<s32, Errno> NetworkBSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Errno::BADF};
|
||||||
}
|
}
|
||||||
@@ -632,7 +632,7 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
|
|||||||
return {new_fd, Errno::SUCCESS};
|
return {new_fd, Errno::SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) {
|
Errno NetworkBSD::BindImpl(s32 fd, std::span<const u8> addr) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -647,7 +647,7 @@ Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) {
|
|||||||
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
|
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
Errno NetworkBSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -670,7 +670,7 @@ Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
Errno NetworkBSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -692,7 +692,7 @@ Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
|||||||
return Translate(bsd_errno);
|
return Translate(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
Errno NetworkBSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -714,7 +714,7 @@ Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
|||||||
return Translate(bsd_errno);
|
return Translate(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::ListenImpl(s32 fd, s32 backlog) {
|
Errno NetworkBSD::ListenImpl(s32 fd, s32 backlog) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -725,7 +725,7 @@ Errno BSD::ListenImpl(s32 fd, s32 backlog) {
|
|||||||
return Translate(file_descriptors[fd]->socket->Listen(backlog));
|
return Translate(file_descriptors[fd]->socket->Listen(backlog));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
|
std::pair<s32, Errno> NetworkBSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Errno::BADF};
|
||||||
}
|
}
|
||||||
@@ -755,7 +755,7 @@ std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval) {
|
Errno NetworkBSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -790,7 +790,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& o
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) {
|
Errno NetworkBSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -844,7 +844,7 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::ShutdownImpl(s32 fd, s32 how) {
|
Errno NetworkBSD::ShutdownImpl(s32 fd, s32 how) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -856,7 +856,7 @@ Errno BSD::ShutdownImpl(s32 fd, s32 how) {
|
|||||||
return Translate(file_descriptors[fd]->socket->Shutdown(host_how));
|
return Translate(file_descriptors[fd]->socket->Shutdown(host_how));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
|
std::pair<s32, Errno> NetworkBSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Errno::BADF};
|
||||||
}
|
}
|
||||||
@@ -883,7 +883,7 @@ std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message)
|
|||||||
return {ret, bsd_errno};
|
return {ret, bsd_errno};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
std::pair<s32, Errno> NetworkBSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
||||||
std::vector<u8>& addr) {
|
std::vector<u8>& addr) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Errno::BADF};
|
||||||
@@ -930,7 +930,7 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
|
|||||||
return {ret, bsd_errno};
|
return {ret, bsd_errno};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
|
std::pair<s32, Errno> NetworkBSD::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Errno::BADF};
|
||||||
}
|
}
|
||||||
@@ -941,7 +941,7 @@ std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, std::span<const u8> messa
|
|||||||
return Translate(file_descriptors[fd]->socket->Send(message, flags));
|
return Translate(file_descriptors[fd]->socket->Send(message, flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
std::pair<s32, Errno> NetworkBSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
||||||
std::span<const u8> addr) {
|
std::span<const u8> addr) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return {-1, Errno::BADF};
|
return {-1, Errno::BADF};
|
||||||
@@ -963,7 +963,7 @@ std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> mes
|
|||||||
return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in));
|
return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in));
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno BSD::CloseImpl(s32 fd) {
|
Errno NetworkBSD::CloseImpl(s32 fd) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -983,7 +983,7 @@ Errno BSD::CloseImpl(s32 fd) {
|
|||||||
return bsd_errno;
|
return bsd_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::variant<s32, Errno> BSD::DuplicateSocketImpl(s32 fd) {
|
std::variant<s32, Errno> NetworkBSD::DuplicateSocketImpl(s32 fd) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
@@ -1002,7 +1002,7 @@ std::variant<s32, Errno> BSD::DuplicateSocketImpl(s32 fd) {
|
|||||||
return new_fd;
|
return new_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::shared_ptr<Network::SocketBase>> BSD::GetSocket(s32 fd) {
|
std::optional<std::shared_ptr<Network::SocketBase>> NetworkBSD::GetSocket(s32 fd) {
|
||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@@ -1013,7 +1013,7 @@ std::optional<std::shared_ptr<Network::SocketBase>> BSD::GetSocket(s32 fd) {
|
|||||||
return file_descriptors[fd]->socket;
|
return file_descriptors[fd]->socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 BSD::FindFreeFileDescriptorHandle() noexcept {
|
s32 NetworkBSD::FindFreeFileDescriptorHandle() noexcept {
|
||||||
for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
|
for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
|
||||||
if (!file_descriptors[fd]) {
|
if (!file_descriptors[fd]) {
|
||||||
return fd;
|
return fd;
|
||||||
@@ -1022,7 +1022,7 @@ s32 BSD::FindFreeFileDescriptorHandle() noexcept {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BSD::IsFileDescriptorValid(s32 fd) const noexcept {
|
bool NetworkBSD::IsFileDescriptorValid(s32 fd) const noexcept {
|
||||||
if (fd > static_cast<s32>(MAX_FD) || fd < 0) {
|
if (fd > static_cast<s32>(MAX_FD) || fd < 0) {
|
||||||
LOG_ERROR(Service, "Invalid file descriptor handle={}", fd);
|
LOG_ERROR(Service, "Invalid file descriptor handle={}", fd);
|
||||||
return false;
|
return false;
|
||||||
@@ -1034,7 +1034,7 @@ bool BSD::IsFileDescriptorValid(s32 fd) const noexcept {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept {
|
void NetworkBSD::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept {
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
|
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
@@ -1042,7 +1042,7 @@ void BSD::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noex
|
|||||||
rb.PushEnum(bsd_errno);
|
rb.PushEnum(bsd_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
|
void NetworkBSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
|
||||||
for (auto& optional_descriptor : file_descriptors) {
|
for (auto& optional_descriptor : file_descriptors) {
|
||||||
if (!optional_descriptor.has_value()) {
|
if (!optional_descriptor.has_value()) {
|
||||||
continue;
|
continue;
|
||||||
@@ -1052,42 +1052,42 @@ void BSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BSD::BSD(Core::System& system_, const char* name)
|
NetworkBSD::NetworkBSD(Core::System& system_, const char* name)
|
||||||
: ServiceFramework{system_, name} {
|
: ServiceFramework{system_, name} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &BSD::RegisterClient, "RegisterClient"},
|
{0, &NetworkBSD::RegisterClient, "RegisterClient"},
|
||||||
{1, &BSD::StartMonitoring, "StartMonitoring"},
|
{1, &NetworkBSD::StartMonitoring, "StartMonitoring"},
|
||||||
{2, &BSD::Socket, "Socket"},
|
{2, &NetworkBSD::Socket, "Socket"},
|
||||||
{3, nullptr, "SocketExempt"},
|
{3, nullptr, "SocketExempt"},
|
||||||
{4, nullptr, "Open"},
|
{4, nullptr, "Open"},
|
||||||
{5, &BSD::Select, "Select"},
|
{5, &NetworkBSD::Select, "Select"},
|
||||||
{6, &BSD::Poll, "Poll"},
|
{6, &NetworkBSD::Poll, "Poll"},
|
||||||
{7, nullptr, "Sysctl"},
|
{7, nullptr, "Sysctl"},
|
||||||
{8, &BSD::Recv, "Recv"},
|
{8, &NetworkBSD::Recv, "Recv"},
|
||||||
{9, &BSD::RecvFrom, "RecvFrom"},
|
{9, &NetworkBSD::RecvFrom, "RecvFrom"},
|
||||||
{10, &BSD::Send, "Send"},
|
{10, &NetworkBSD::Send, "Send"},
|
||||||
{11, &BSD::SendTo, "SendTo"},
|
{11, &NetworkBSD::SendTo, "SendTo"},
|
||||||
{12, &BSD::Accept, "Accept"},
|
{12, &NetworkBSD::Accept, "Accept"},
|
||||||
{13, &BSD::Bind, "Bind"},
|
{13, &NetworkBSD::Bind, "Bind"},
|
||||||
{14, &BSD::Connect, "Connect"},
|
{14, &NetworkBSD::Connect, "Connect"},
|
||||||
{15, &BSD::GetPeerName, "GetPeerName"},
|
{15, &NetworkBSD::GetPeerName, "GetPeerName"},
|
||||||
{16, &BSD::GetSockName, "GetSockName"},
|
{16, &NetworkBSD::GetSockName, "GetSockName"},
|
||||||
{17, &BSD::GetSockOpt, "GetSockOpt"},
|
{17, &NetworkBSD::GetSockOpt, "GetSockOpt"},
|
||||||
{18, &BSD::Listen, "Listen"},
|
{18, &NetworkBSD::Listen, "Listen"},
|
||||||
{19, nullptr, "Ioctl"},
|
{19, nullptr, "Ioctl"},
|
||||||
{20, &BSD::Fcntl, "Fcntl"},
|
{20, &NetworkBSD::Fcntl, "Fcntl"},
|
||||||
{21, &BSD::SetSockOpt, "SetSockOpt"},
|
{21, &NetworkBSD::SetSockOpt, "SetSockOpt"},
|
||||||
{22, &BSD::Shutdown, "Shutdown"},
|
{22, &NetworkBSD::Shutdown, "Shutdown"},
|
||||||
{23, nullptr, "ShutdownAllSockets"},
|
{23, nullptr, "ShutdownAllSockets"},
|
||||||
{24, &BSD::Write, "Write"},
|
{24, &NetworkBSD::Write, "Write"},
|
||||||
{25, &BSD::Read, "Read"},
|
{25, &NetworkBSD::Read, "Read"},
|
||||||
{26, &BSD::Close, "Close"},
|
{26, &NetworkBSD::Close, "Close"},
|
||||||
{27, &BSD::DuplicateSocket, "DuplicateSocket"},
|
{27, &NetworkBSD::DuplicateSocket, "DuplicateSocket"},
|
||||||
{28, nullptr, "GetResourceStatistics"},
|
{28, nullptr, "GetResourceStatistics"},
|
||||||
{29, nullptr, "RecvMMsg"}, //3.0.0+
|
{29, nullptr, "RecvMMsg"}, //3.0.0+
|
||||||
{30, nullptr, "SendMMsg"}, //3.0.0+
|
{30, nullptr, "SendMMsg"}, //3.0.0+
|
||||||
{31, &BSD::EventFd, "EventFd"}, //7.0.0+
|
{31, &NetworkBSD::EventFd, "EventFd"}, //7.0.0+
|
||||||
{32, nullptr, "RegisterResourceStatisticsName"}, //7.0.0+
|
{32, nullptr, "RegisterResourceStatisticsName"}, //7.0.0+
|
||||||
{33, nullptr, "RegisterClientShared"}, //10.0.0+
|
{33, nullptr, "RegisterClientShared"}, //10.0.0+
|
||||||
{34, nullptr, "GetSocketStatistics"}, //15.0.0+
|
{34, nullptr, "GetSocketStatistics"}, //15.0.0+
|
||||||
@@ -1115,13 +1115,13 @@ BSD::BSD(Core::System& system_, const char* name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BSD::~BSD() {
|
NetworkBSD::~NetworkBSD() {
|
||||||
if (auto room_member = Network::GetRoomMember().lock()) {
|
if (auto room_member = Network::GetRoomMember().lock()) {
|
||||||
room_member->Unbind(proxy_packet_received);
|
room_member->Unbind(proxy_packet_received);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_lock<std::mutex> BSD::LockService() noexcept {
|
std::unique_lock<std::mutex> NetworkBSD::LockService() noexcept {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ class Socket;
|
|||||||
|
|
||||||
namespace Service::Sockets {
|
namespace Service::Sockets {
|
||||||
|
|
||||||
class BSD final : public ServiceFramework<BSD> {
|
class NetworkBSD final : public ServiceFramework<NetworkBSD> {
|
||||||
public:
|
public:
|
||||||
explicit BSD(Core::System& system_, const char* name);
|
explicit NetworkBSD(Core::System& system_, const char* name);
|
||||||
~BSD() override;
|
~NetworkBSD() override;
|
||||||
|
|
||||||
// These methods are called from SSL; the first two are also called from
|
// These methods are called from SSL; the first two are also called from
|
||||||
// this class for the corresponding IPC methods.
|
// this class for the corresponding IPC methods.
|
||||||
@@ -50,7 +50,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct PollWork {
|
struct PollWork {
|
||||||
void Execute(BSD* bsd);
|
void Execute(NetworkBSD* bsd);
|
||||||
void Response(HLERequestContext& ctx);
|
void Response(HLERequestContext& ctx);
|
||||||
|
|
||||||
s32 nfds;
|
s32 nfds;
|
||||||
@@ -62,7 +62,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct AcceptWork {
|
struct AcceptWork {
|
||||||
void Execute(BSD* bsd);
|
void Execute(NetworkBSD* bsd);
|
||||||
void Response(HLERequestContext& ctx);
|
void Response(HLERequestContext& ctx);
|
||||||
|
|
||||||
s32 fd;
|
s32 fd;
|
||||||
@@ -72,7 +72,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ConnectWork {
|
struct ConnectWork {
|
||||||
void Execute(BSD* bsd);
|
void Execute(NetworkBSD* bsd);
|
||||||
void Response(HLERequestContext& ctx);
|
void Response(HLERequestContext& ctx);
|
||||||
|
|
||||||
s32 fd;
|
s32 fd;
|
||||||
@@ -81,7 +81,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct RecvWork {
|
struct RecvWork {
|
||||||
void Execute(BSD* bsd);
|
void Execute(NetworkBSD* bsd);
|
||||||
void Response(HLERequestContext& ctx);
|
void Response(HLERequestContext& ctx);
|
||||||
|
|
||||||
s32 fd;
|
s32 fd;
|
||||||
@@ -92,7 +92,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct RecvFromWork {
|
struct RecvFromWork {
|
||||||
void Execute(BSD* bsd);
|
void Execute(NetworkBSD* bsd);
|
||||||
void Response(HLERequestContext& ctx);
|
void Response(HLERequestContext& ctx);
|
||||||
|
|
||||||
s32 fd;
|
s32 fd;
|
||||||
@@ -104,7 +104,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct SendWork {
|
struct SendWork {
|
||||||
void Execute(BSD* bsd);
|
void Execute(NetworkBSD* bsd);
|
||||||
void Response(HLERequestContext& ctx);
|
void Response(HLERequestContext& ctx);
|
||||||
|
|
||||||
s32 fd;
|
s32 fd;
|
||||||
@@ -115,7 +115,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct SendToWork {
|
struct SendToWork {
|
||||||
void Execute(BSD* bsd);
|
void Execute(NetworkBSD* bsd);
|
||||||
void Response(HLERequestContext& ctx);
|
void Response(HLERequestContext& ctx);
|
||||||
|
|
||||||
s32 fd;
|
s32 fd;
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -12,8 +15,8 @@ namespace Service::Sockets {
|
|||||||
void LoopProcess(Core::System& system) {
|
void LoopProcess(Core::System& system) {
|
||||||
auto server_manager = std::make_unique<ServerManager>(system);
|
auto server_manager = std::make_unique<ServerManager>(system);
|
||||||
|
|
||||||
server_manager->RegisterNamedService("bsd:s", std::make_shared<BSD>(system, "bsd:s"));
|
server_manager->RegisterNamedService("bsd:s", std::make_shared<NetworkBSD>(system, "bsd:s"));
|
||||||
server_manager->RegisterNamedService("bsd:u", std::make_shared<BSD>(system, "bsd:u"));
|
server_manager->RegisterNamedService("bsd:u", std::make_shared<NetworkBSD>(system, "bsd:u"));
|
||||||
server_manager->RegisterNamedService("bsdcfg", std::make_shared<BSDCFG>(system));
|
server_manager->RegisterNamedService("bsdcfg", std::make_shared<BSDCFG>(system));
|
||||||
server_manager->RegisterNamedService("nsd:a", std::make_shared<NSD>(system, "nsd:a"));
|
server_manager->RegisterNamedService("nsd:a", std::make_shared<NSD>(system, "nsd:a"));
|
||||||
server_manager->RegisterNamedService("nsd:u", std::make_shared<NSD>(system, "nsd:u"));
|
server_manager->RegisterNamedService("nsd:u", std::make_shared<NSD>(system, "nsd:u"));
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ public:
|
|||||||
LOG_ERROR(Service_SSL,
|
LOG_ERROR(Service_SSL,
|
||||||
"do_not_close_socket was changed after setting socket; is this right?");
|
"do_not_close_socket was changed after setting socket; is this right?");
|
||||||
} else {
|
} else {
|
||||||
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
|
auto bsd = system.ServiceManager().GetService<Service::Sockets::NetworkBSD>("bsd:u");
|
||||||
if (bsd) {
|
if (bsd) {
|
||||||
auto err = bsd->CloseImpl(fd);
|
auto err = bsd->CloseImpl(fd);
|
||||||
if (err != Service::Sockets::Errno::SUCCESS) {
|
if (err != Service::Sockets::Errno::SUCCESS) {
|
||||||
@@ -157,7 +157,7 @@ private:
|
|||||||
Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) {
|
Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) {
|
||||||
LOG_DEBUG(Service_SSL, "called, fd={}", fd);
|
LOG_DEBUG(Service_SSL, "called, fd={}", fd);
|
||||||
ASSERT(!did_handshake);
|
ASSERT(!did_handshake);
|
||||||
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
|
auto bsd = system.ServiceManager().GetService<Service::Sockets::NetworkBSD>("bsd:u");
|
||||||
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
|
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
|
||||||
|
|
||||||
auto const res_v = bsd->DuplicateSocketImpl(fd);
|
auto const res_v = bsd->DuplicateSocketImpl(fd);
|
||||||
|
|||||||
@@ -17,11 +17,9 @@
|
|||||||
|
|
||||||
namespace Loader {
|
namespace Loader {
|
||||||
|
|
||||||
namespace {
|
[[nodiscard]] inline constexpr u32 PageAlignSizeKIP(u32 size) {
|
||||||
constexpr u32 PageAlignSize(u32 size) {
|
return u32((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
|
||||||
return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
|
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
|
||||||
|
|
||||||
AppLoader_KIP::AppLoader_KIP(FileSys::VirtualFile file_)
|
AppLoader_KIP::AppLoader_KIP(FileSys::VirtualFile file_)
|
||||||
: AppLoader(std::move(file_)), kip(std::make_unique<FileSys::KIP>(file)) {}
|
: AppLoader(std::move(file_)), kip(std::make_unique<FileSys::KIP>(file)) {}
|
||||||
@@ -76,11 +74,11 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
|
|||||||
kip->GetKernelCapabilities());
|
kip->GetKernelCapabilities());
|
||||||
|
|
||||||
Kernel::CodeSet codeset;
|
Kernel::CodeSet codeset;
|
||||||
codeset.memory.resize(PageAlignSize(kip->GetBSSOffset()) + kip->GetBSSSize());
|
codeset.memory.resize(PageAlignSizeKIP(kip->GetBSSOffset()) + kip->GetBSSSize());
|
||||||
const auto load_segment = [&codeset](Kernel::CodeSet::Segment& segment, std::span<const u8> data, u32 offset) {
|
const auto load_segment = [&codeset](Kernel::CodeSet::Segment& segment, std::span<const u8> data, u32 offset) {
|
||||||
segment.addr = offset;
|
segment.addr = offset;
|
||||||
segment.offset = offset;
|
segment.offset = offset;
|
||||||
segment.size = PageAlignSize(u32(data.size()));
|
segment.size = PageAlignSizeKIP(u32(data.size()));
|
||||||
std::memcpy(codeset.memory.data() + offset, data.data(), data.size());
|
std::memcpy(codeset.memory.data() + offset, data.data(), data.size());
|
||||||
};
|
};
|
||||||
load_segment(codeset.CodeSegment(), kip->GetTextSection(), kip->GetTextOffset());
|
load_segment(codeset.CodeSegment(), kip->GetTextSection(), kip->GetTextOffset());
|
||||||
|
|||||||
@@ -148,8 +148,8 @@ bool AppLoader_NRO::IsHomebrew() {
|
|||||||
nro_header.magic_ext2 == Common::MakeMagic('B', 'R', 'E', 'W');
|
nro_header.magic_ext2 == Common::MakeMagic('B', 'R', 'E', 'W');
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr u32 PageAlignSize(u32 size) {
|
[[nodiscard]] inline constexpr u32 PageAlignSizeNRO(u32 size) {
|
||||||
return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
|
return u32((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
|
static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
|
||||||
@@ -166,9 +166,9 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build program image
|
// Build program image
|
||||||
std::vector<u8> program_image(PageAlignSize(nro_header.file_size));
|
std::vector<u8> program_image(PageAlignSizeNRO(nro_header.file_size));
|
||||||
std::memcpy(program_image.data(), data.data(), program_image.size());
|
std::memcpy(program_image.data(), data.data(), program_image.size());
|
||||||
if (program_image.size() != PageAlignSize(nro_header.file_size)) {
|
if (program_image.size() != PageAlignSizeNRO(nro_header.file_size)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,11 +176,11 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
|
|||||||
for (std::size_t i = 0; i < nro_header.segments.size(); ++i) {
|
for (std::size_t i = 0; i < nro_header.segments.size(); ++i) {
|
||||||
codeset.segments[i].addr = nro_header.segments[i].offset;
|
codeset.segments[i].addr = nro_header.segments[i].offset;
|
||||||
codeset.segments[i].offset = nro_header.segments[i].offset;
|
codeset.segments[i].offset = nro_header.segments[i].offset;
|
||||||
codeset.segments[i].size = PageAlignSize(nro_header.segments[i].size);
|
codeset.segments[i].size = PageAlignSizeNRO(nro_header.segments[i].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default .bss to NRO header bss size if MOD0 section doesn't exist
|
// Default .bss to NRO header bss size if MOD0 section doesn't exist
|
||||||
u32 bss_size{PageAlignSize(nro_header.bss_size)};
|
u32 bss_size{PageAlignSizeNRO(nro_header.bss_size)};
|
||||||
|
|
||||||
// Read MOD header
|
// Read MOD header
|
||||||
ModHeader mod_header{};
|
ModHeader mod_header{};
|
||||||
@@ -190,7 +190,7 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
|
|||||||
const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')};
|
const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')};
|
||||||
if (has_mod_header) {
|
if (has_mod_header) {
|
||||||
// Resize program image to include .bss section and page align each section
|
// Resize program image to include .bss section and page align each section
|
||||||
bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset);
|
bss_size = PageAlignSizeNRO(mod_header.bss_end_offset - mod_header.bss_start_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
codeset.DataSegment().size += bss_size;
|
codeset.DataSegment().size += bss_size;
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ struct MODHeader {
|
|||||||
};
|
};
|
||||||
static_assert(sizeof(MODHeader) == 0x1c, "MODHeader has incorrect size.");
|
static_assert(sizeof(MODHeader) == 0x1c, "MODHeader has incorrect size.");
|
||||||
|
|
||||||
constexpr u32 PageAlignSize(u32 size) {
|
[[nodiscard]] inline constexpr u32 PageAlignSizeNSO(u32 size) {
|
||||||
return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
|
return u32((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
@@ -128,11 +128,11 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
|
|||||||
}
|
}
|
||||||
|
|
||||||
codeset.DataSegment().size += nso_header.segments[2].bss_size;
|
codeset.DataSegment().size += nso_header.segments[2].bss_size;
|
||||||
u32 image_size = PageAlignSize(u32(codeset.memory.size()) + nso_header.segments[2].bss_size);
|
u32 image_size = PageAlignSizeNSO(u32(codeset.memory.size()) + nso_header.segments[2].bss_size);
|
||||||
codeset.memory.resize(image_size);
|
codeset.memory.resize(image_size);
|
||||||
|
|
||||||
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
|
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
|
||||||
codeset.segments[i].size = PageAlignSize(codeset.segments[i].size);
|
codeset.segments[i].size = PageAlignSizeNSO(codeset.segments[i].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply patches if necessary
|
// Apply patches if necessary
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
#include "hid_core/resource_manager.h"
|
#include "hid_core/resource_manager.h"
|
||||||
#include "hid_core/resources/npad/npad.h"
|
#include "hid_core/resources/npad/npad.h"
|
||||||
|
|
||||||
|
#undef CreateEvent
|
||||||
|
|
||||||
namespace Core::Memory {
|
namespace Core::Memory {
|
||||||
namespace {
|
namespace {
|
||||||
constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12};
|
constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12};
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "core/reporter.h"
|
#include "core/reporter.h"
|
||||||
|
|
||||||
|
#undef far
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::filesystem::path GetPath(std::string_view type, u64 title_id, std::string_view timestamp) {
|
std::filesystem::path GetPath(std::string_view type, u64 title_id, std::string_view timestamp) {
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ void MemoryWriteWidth(Core::Memory::Memory& memory, u32 width, VAddr addr, u64 v
|
|||||||
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
#undef CreateEvent
|
||||||
|
|
||||||
Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_)
|
Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_)
|
||||||
: core_timing{core_timing_}, memory{memory_} {
|
: core_timing{core_timing_}, memory{memory_} {
|
||||||
event = Core::Timing::CreateEvent("MemoryFreezer::FrameCallback",
|
event = Core::Timing::CreateEvent("MemoryFreezer::FrameCallback",
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ using namespace oaknut::util;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool IsOrdered(IR::AccType acctype) {
|
[[nodiscard]] inline bool IsOrdered(IR::AccType acctype) {
|
||||||
return acctype == IR::AccType::ORDERED || acctype == IR::AccType::ORDEREDRW || acctype == IR::AccType::LIMITEDORDERED;
|
return acctype == IR::AccType::ORDERED || acctype == IR::AccType::ORDEREDRW || acctype == IR::AccType::LIMITEDORDERED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -6,7 +9,6 @@
|
|||||||
#include "hid_core/hidbus/starlink.h"
|
#include "hid_core/hidbus/starlink.h"
|
||||||
|
|
||||||
namespace Service::HID {
|
namespace Service::HID {
|
||||||
constexpr u8 DEVICE_ID = 0x28;
|
|
||||||
|
|
||||||
Starlink::Starlink(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
|
Starlink::Starlink(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
|
||||||
: HidbusBase(system_, service_context_) {}
|
: HidbusBase(system_, service_context_) {}
|
||||||
@@ -35,7 +37,7 @@ void Starlink::OnUpdate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u8 Starlink::GetDeviceId() const {
|
u8 Starlink::GetDeviceId() const {
|
||||||
return DEVICE_ID;
|
return 0x28;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 Starlink::GetReply(std::span<u8> out_data) const {
|
u64 Starlink::GetReply(std::span<u8> out_data) const {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -6,7 +9,6 @@
|
|||||||
#include "hid_core/hidbus/stubbed.h"
|
#include "hid_core/hidbus/stubbed.h"
|
||||||
|
|
||||||
namespace Service::HID {
|
namespace Service::HID {
|
||||||
constexpr u8 DEVICE_ID = 0xFF;
|
|
||||||
|
|
||||||
HidbusStubbed::HidbusStubbed(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
|
HidbusStubbed::HidbusStubbed(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
|
||||||
: HidbusBase(system_, service_context_) {}
|
: HidbusBase(system_, service_context_) {}
|
||||||
@@ -35,7 +37,7 @@ void HidbusStubbed::OnUpdate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u8 HidbusStubbed::GetDeviceId() const {
|
u8 HidbusStubbed::GetDeviceId() const {
|
||||||
return DEVICE_ID;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 HidbusStubbed::GetReply(std::span<u8> out_data) const {
|
u64 HidbusStubbed::GetReply(std::span<u8> out_data) const {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
@@ -8,9 +11,6 @@
|
|||||||
#include "hid_core/irsensor/moment_processor.h"
|
#include "hid_core/irsensor/moment_processor.h"
|
||||||
|
|
||||||
namespace Service::IRS {
|
namespace Service::IRS {
|
||||||
static constexpr auto format = Core::IrSensor::ImageTransferProcessorFormat::Size40x30;
|
|
||||||
static constexpr std::size_t ImageWidth = 40;
|
|
||||||
static constexpr std::size_t ImageHeight = 30;
|
|
||||||
|
|
||||||
MomentProcessor::MomentProcessor(Core::System& system_, Core::IrSensor::DeviceFormat& device_format,
|
MomentProcessor::MomentProcessor(Core::System& system_, Core::IrSensor::DeviceFormat& device_format,
|
||||||
std::size_t npad_index)
|
std::size_t npad_index)
|
||||||
@@ -80,9 +80,9 @@ void MomentProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
u8 MomentProcessor::GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const {
|
u8 MomentProcessor::GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const {
|
||||||
if ((y * ImageWidth) + x >= data.size()) {
|
constexpr std::size_t ImageWidth = 40;
|
||||||
|
if ((y * ImageWidth) + x >= data.size())
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
return data[(y * ImageWidth) + x];
|
return data[(y * ImageWidth) + x];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,9 +92,12 @@ MomentProcessor::MomentStatistic MomentProcessor::GetStatistic(const std::vector
|
|||||||
std::size_t width,
|
std::size_t width,
|
||||||
std::size_t height) const {
|
std::size_t height) const {
|
||||||
// The actual implementation is always 320x240
|
// The actual implementation is always 320x240
|
||||||
static constexpr std::size_t RealWidth = 320;
|
constexpr std::size_t RealWidth = 320;
|
||||||
static constexpr std::size_t RealHeight = 240;
|
constexpr std::size_t RealHeight = 240;
|
||||||
static constexpr std::size_t Threshold = 30;
|
constexpr std::size_t Threshold = 30;
|
||||||
|
constexpr std::size_t ImageWidth = 40;
|
||||||
|
constexpr std::size_t ImageHeight = 30;
|
||||||
|
|
||||||
MomentStatistic statistic{};
|
MomentStatistic statistic{};
|
||||||
std::size_t active_points{};
|
std::size_t active_points{};
|
||||||
|
|
||||||
@@ -143,7 +146,7 @@ void MomentProcessor::SetConfig(Core::IrSensor::PackedMomentProcessorConfig conf
|
|||||||
static_cast<Core::IrSensor::MomentProcessorPreprocess>(config.preprocess);
|
static_cast<Core::IrSensor::MomentProcessorPreprocess>(config.preprocess);
|
||||||
current_config.preprocess_intensity_threshold = config.preprocess_intensity_threshold;
|
current_config.preprocess_intensity_threshold = config.preprocess_intensity_threshold;
|
||||||
|
|
||||||
npad_device->SetCameraFormat(format);
|
npad_device->SetCameraFormat(Core::IrSensor::ImageTransferProcessorFormat::Size40x30);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::IRS
|
} // namespace Service::IRS
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -7,14 +10,14 @@
|
|||||||
#include "input_common/drivers/camera.h"
|
#include "input_common/drivers/camera.h"
|
||||||
|
|
||||||
namespace InputCommon {
|
namespace InputCommon {
|
||||||
constexpr PadIdentifier identifier = {
|
constexpr PadIdentifier camera_identifier = {
|
||||||
.guid = Common::UUID{},
|
.guid = Common::UUID{},
|
||||||
.port = 0,
|
.port = 0,
|
||||||
.pad = 0,
|
.pad = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
Camera::Camera(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
Camera::Camera(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
||||||
PreSetController(identifier);
|
PreSetController(camera_identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::SetCameraData(std::size_t width, std::size_t height, std::span<const u32> data) {
|
void Camera::SetCameraData(std::size_t width, std::size_t height, std::span<const u32> data) {
|
||||||
@@ -33,7 +36,7 @@ void Camera::SetCameraData(std::size_t width, std::size_t height, std::span<cons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetCamera(identifier, status);
|
SetCamera(camera_identifier, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t Camera::getImageWidth() const {
|
std::size_t Camera::getImageWidth() const {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -26,7 +26,7 @@ constexpr int mouse_axis_x = 0;
|
|||||||
constexpr int mouse_axis_y = 1;
|
constexpr int mouse_axis_y = 1;
|
||||||
constexpr int wheel_axis_x = 2;
|
constexpr int wheel_axis_x = 2;
|
||||||
constexpr int wheel_axis_y = 3;
|
constexpr int wheel_axis_y = 3;
|
||||||
constexpr PadIdentifier identifier = {
|
constexpr PadIdentifier mouse_identifier = {
|
||||||
.guid = Common::UUID{},
|
.guid = Common::UUID{},
|
||||||
.port = 0,
|
.port = 0,
|
||||||
.pad = 0,
|
.pad = 0,
|
||||||
@@ -51,16 +51,16 @@ constexpr PadIdentifier touch_identifier = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
||||||
PreSetController(identifier);
|
PreSetController(mouse_identifier);
|
||||||
PreSetController(real_mouse_identifier);
|
PreSetController(real_mouse_identifier);
|
||||||
PreSetController(touch_identifier);
|
PreSetController(touch_identifier);
|
||||||
PreSetController(motion_identifier);
|
PreSetController(motion_identifier);
|
||||||
|
|
||||||
// Initialize all mouse axis
|
// Initialize all mouse axis
|
||||||
PreSetAxis(identifier, mouse_axis_x);
|
PreSetAxis(mouse_identifier, mouse_axis_x);
|
||||||
PreSetAxis(identifier, mouse_axis_y);
|
PreSetAxis(mouse_identifier, mouse_axis_y);
|
||||||
PreSetAxis(identifier, wheel_axis_x);
|
PreSetAxis(mouse_identifier, wheel_axis_x);
|
||||||
PreSetAxis(identifier, wheel_axis_y);
|
PreSetAxis(mouse_identifier, wheel_axis_y);
|
||||||
PreSetAxis(real_mouse_identifier, mouse_axis_x);
|
PreSetAxis(real_mouse_identifier, mouse_axis_x);
|
||||||
PreSetAxis(real_mouse_identifier, mouse_axis_y);
|
PreSetAxis(real_mouse_identifier, mouse_axis_y);
|
||||||
PreSetAxis(touch_identifier, mouse_axis_x);
|
PreSetAxis(touch_identifier, mouse_axis_x);
|
||||||
@@ -97,8 +97,8 @@ void Mouse::UpdateStickInput() {
|
|||||||
last_mouse_change *= maximum_stick_range;
|
last_mouse_change *= maximum_stick_range;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetAxis(identifier, mouse_axis_x, last_mouse_change.x);
|
SetAxis(mouse_identifier, mouse_axis_x, last_mouse_change.x);
|
||||||
SetAxis(identifier, mouse_axis_y, -last_mouse_change.y);
|
SetAxis(mouse_identifier, mouse_axis_y, -last_mouse_change.y);
|
||||||
|
|
||||||
// Decay input over time
|
// Decay input over time
|
||||||
const float clamped_length = (std::min)(1.0f, length);
|
const float clamped_length = (std::min)(1.0f, length);
|
||||||
@@ -174,8 +174,8 @@ void Mouse::Move(int x, int y, int center_x, int center_y) {
|
|||||||
Settings::values.mouse_panning_x_sensitivity.GetValue() * default_stick_sensitivity;
|
Settings::values.mouse_panning_x_sensitivity.GetValue() * default_stick_sensitivity;
|
||||||
const float y_sensitivity =
|
const float y_sensitivity =
|
||||||
Settings::values.mouse_panning_y_sensitivity.GetValue() * default_stick_sensitivity;
|
Settings::values.mouse_panning_y_sensitivity.GetValue() * default_stick_sensitivity;
|
||||||
SetAxis(identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * x_sensitivity);
|
SetAxis(mouse_identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * x_sensitivity);
|
||||||
SetAxis(identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * y_sensitivity);
|
SetAxis(mouse_identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * y_sensitivity);
|
||||||
|
|
||||||
last_motion_change = {
|
last_motion_change = {
|
||||||
static_cast<float>(-mouse_move.y) * x_sensitivity,
|
static_cast<float>(-mouse_move.y) * x_sensitivity,
|
||||||
@@ -196,7 +196,7 @@ void Mouse::TouchMove(f32 touch_x, f32 touch_y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Mouse::PressButton(int x, int y, MouseButton button) {
|
void Mouse::PressButton(int x, int y, MouseButton button) {
|
||||||
SetButton(identifier, static_cast<int>(button), true);
|
SetButton(mouse_identifier, static_cast<int>(button), true);
|
||||||
|
|
||||||
// Set initial analog parameters
|
// Set initial analog parameters
|
||||||
mouse_origin = {x, y};
|
mouse_origin = {x, y};
|
||||||
@@ -215,13 +215,13 @@ void Mouse::PressTouchButton(f32 touch_x, f32 touch_y, MouseButton button) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Mouse::ReleaseButton(MouseButton button) {
|
void Mouse::ReleaseButton(MouseButton button) {
|
||||||
SetButton(identifier, static_cast<int>(button), false);
|
SetButton(mouse_identifier, static_cast<int>(button), false);
|
||||||
SetButton(real_mouse_identifier, static_cast<int>(button), false);
|
SetButton(real_mouse_identifier, static_cast<int>(button), false);
|
||||||
SetButton(touch_identifier, static_cast<int>(button), false);
|
SetButton(touch_identifier, static_cast<int>(button), false);
|
||||||
|
|
||||||
if (!IsMousePanningEnabled()) {
|
if (!IsMousePanningEnabled()) {
|
||||||
SetAxis(identifier, mouse_axis_x, 0);
|
SetAxis(mouse_identifier, mouse_axis_x, 0);
|
||||||
SetAxis(identifier, mouse_axis_y, 0);
|
SetAxis(mouse_identifier, mouse_axis_y, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
last_motion_change.x = 0;
|
last_motion_change.x = 0;
|
||||||
@@ -234,8 +234,8 @@ void Mouse::MouseWheelChange(int x, int y) {
|
|||||||
wheel_position.x += x;
|
wheel_position.x += x;
|
||||||
wheel_position.y += y;
|
wheel_position.y += y;
|
||||||
last_motion_change.z += static_cast<f32>(y);
|
last_motion_change.z += static_cast<f32>(y);
|
||||||
SetAxis(identifier, wheel_axis_x, static_cast<f32>(wheel_position.x));
|
SetAxis(mouse_identifier, wheel_axis_x, static_cast<f32>(wheel_position.x));
|
||||||
SetAxis(identifier, wheel_axis_y, static_cast<f32>(wheel_position.y));
|
SetAxis(mouse_identifier, wheel_axis_y, static_cast<f32>(wheel_position.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mouse::ReleaseAllButtons() {
|
void Mouse::ReleaseAllButtons() {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -6,14 +9,14 @@
|
|||||||
|
|
||||||
namespace InputCommon {
|
namespace InputCommon {
|
||||||
|
|
||||||
constexpr PadIdentifier identifier = {
|
constexpr PadIdentifier touch_screen_identifier = {
|
||||||
.guid = Common::UUID{},
|
.guid = Common::UUID{},
|
||||||
.port = 0,
|
.port = 0,
|
||||||
.pad = 0,
|
.pad = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
||||||
PreSetController(identifier);
|
PreSetController(touch_screen_identifier);
|
||||||
ReleaseAllTouch();
|
ReleaseAllTouch();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,9 +29,9 @@ void TouchScreen::TouchMoved(float x, float y, std::size_t finger_id) {
|
|||||||
}
|
}
|
||||||
const auto i = index.value();
|
const auto i = index.value();
|
||||||
fingers[i].is_active = true;
|
fingers[i].is_active = true;
|
||||||
SetButton(identifier, static_cast<int>(i), true);
|
SetButton(touch_screen_identifier, static_cast<int>(i), true);
|
||||||
SetAxis(identifier, static_cast<int>(i * 2), x);
|
SetAxis(touch_screen_identifier, static_cast<int>(i * 2), x);
|
||||||
SetAxis(identifier, static_cast<int>(i * 2 + 1), y);
|
SetAxis(touch_screen_identifier, static_cast<int>(i * 2 + 1), y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TouchScreen::TouchPressed(float x, float y, std::size_t finger_id) {
|
void TouchScreen::TouchPressed(float x, float y, std::size_t finger_id) {
|
||||||
@@ -55,9 +58,9 @@ void TouchScreen::TouchReleased(std::size_t finger_id) {
|
|||||||
}
|
}
|
||||||
const auto i = index.value();
|
const auto i = index.value();
|
||||||
fingers[i].is_enabled = false;
|
fingers[i].is_enabled = false;
|
||||||
SetButton(identifier, static_cast<int>(i), false);
|
SetButton(touch_screen_identifier, static_cast<int>(i), false);
|
||||||
SetAxis(identifier, static_cast<int>(i * 2), 0.0f);
|
SetAxis(touch_screen_identifier, static_cast<int>(i * 2), 0.0f);
|
||||||
SetAxis(identifier, static_cast<int>(i * 2 + 1), 0.0f);
|
SetAxis(touch_screen_identifier, static_cast<int>(i * 2 + 1), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::size_t> TouchScreen::GetIndexFromFingerId(std::size_t finger_id) const {
|
std::optional<std::size_t> TouchScreen::GetIndexFromFingerId(std::size_t finger_id) const {
|
||||||
|
|||||||
@@ -600,7 +600,7 @@ void TestCommunication(const std::string& host, u16 port, const std::function<vo
|
|||||||
}
|
}
|
||||||
|
|
||||||
CalibrationConfigurationJob::CalibrationConfigurationJob(
|
CalibrationConfigurationJob::CalibrationConfigurationJob(
|
||||||
const std::string& host, u16 port, std::function<void(Status)> status_callback,
|
const std::string& host, u16 port, std::function<void(CalibrationStatus)> status_callback,
|
||||||
std::function<void(u16, u16, u16, u16)> data_callback) {
|
std::function<void(u16, u16, u16, u16)> data_callback) {
|
||||||
|
|
||||||
std::thread([=, this] {
|
std::thread([=, this] {
|
||||||
@@ -609,13 +609,13 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
|
|||||||
u16 max_x{};
|
u16 max_x{};
|
||||||
u16 max_y{};
|
u16 max_y{};
|
||||||
|
|
||||||
Status current_status{Status::Initialized};
|
auto current_status = CalibrationStatus::Initialized;
|
||||||
SocketCallback callback{[](Response::Version) {}, [](Response::PortInfo) {}, [&](Response::PadData data) {
|
SocketCallback callback{[](Response::Version) {}, [](Response::PortInfo) {}, [&](Response::PadData data) {
|
||||||
constexpr u16 CALIBRATION_THRESHOLD = 100;
|
constexpr u16 CALIBRATION_THRESHOLD = 100;
|
||||||
|
|
||||||
if (current_status == Status::Initialized) {
|
if (current_status == CalibrationStatus::Initialized) {
|
||||||
// Receiving data means the communication is ready now
|
// Receiving data means the communication is ready now
|
||||||
current_status = Status::Ready;
|
current_status = CalibrationStatus::Ready;
|
||||||
status_callback(current_status);
|
status_callback(current_status);
|
||||||
}
|
}
|
||||||
if (data.touch[0].is_active == 0) {
|
if (data.touch[0].is_active == 0) {
|
||||||
@@ -624,9 +624,9 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
|
|||||||
LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x, data.touch[0].y);
|
LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x, data.touch[0].y);
|
||||||
min_x = (std::min)(min_x, u16(data.touch[0].x));
|
min_x = (std::min)(min_x, u16(data.touch[0].x));
|
||||||
min_y = (std::min)(min_y, u16(data.touch[0].y));
|
min_y = (std::min)(min_y, u16(data.touch[0].y));
|
||||||
if (current_status == Status::Ready) {
|
if (current_status == CalibrationStatus::Ready) {
|
||||||
// First touch - min data (min_x/min_y)
|
// First touch - min data (min_x/min_y)
|
||||||
current_status = Status::Stage1Completed;
|
current_status = CalibrationStatus::Stage1Completed;
|
||||||
status_callback(current_status);
|
status_callback(current_status);
|
||||||
}
|
}
|
||||||
if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD &&
|
if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD &&
|
||||||
@@ -635,7 +635,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
|
|||||||
// configuration
|
// configuration
|
||||||
max_x = data.touch[0].x;
|
max_x = data.touch[0].x;
|
||||||
max_y = data.touch[0].y;
|
max_y = data.touch[0].y;
|
||||||
current_status = Status::Completed;
|
current_status = CalibrationStatus::Completed;
|
||||||
data_callback(min_x, min_y, max_x, max_y);
|
data_callback(min_x, min_y, max_x, max_y);
|
||||||
status_callback(current_status);
|
status_callback(current_status);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2018 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2018 Citra Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -163,7 +166,7 @@ private:
|
|||||||
/// An async job allowing configuration of the touchpad calibration.
|
/// An async job allowing configuration of the touchpad calibration.
|
||||||
class CalibrationConfigurationJob {
|
class CalibrationConfigurationJob {
|
||||||
public:
|
public:
|
||||||
enum class Status {
|
enum class CalibrationStatus {
|
||||||
Initialized,
|
Initialized,
|
||||||
Ready,
|
Ready,
|
||||||
Stage1Completed,
|
Stage1Completed,
|
||||||
@@ -176,7 +179,7 @@ public:
|
|||||||
* @param data_callback Called when calibration data is ready
|
* @param data_callback Called when calibration data is ready
|
||||||
*/
|
*/
|
||||||
explicit CalibrationConfigurationJob(const std::string& host, u16 port,
|
explicit CalibrationConfigurationJob(const std::string& host, u16 port,
|
||||||
std::function<void(Status)> status_callback,
|
std::function<void(CalibrationStatus)> status_callback,
|
||||||
std::function<void(u16, u16, u16, u16)> data_callback);
|
std::function<void(u16, u16, u16, u16)> data_callback);
|
||||||
~CalibrationConfigurationJob();
|
~CalibrationConfigurationJob();
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#include "input_common/drivers/virtual_amiibo.h"
|
#include "input_common/drivers/virtual_amiibo.h"
|
||||||
|
|
||||||
namespace InputCommon {
|
namespace InputCommon {
|
||||||
constexpr PadIdentifier identifier = {
|
constexpr PadIdentifier virtual_amiibo_identifier = {
|
||||||
.guid = Common::UUID{},
|
.guid = Common::UUID{},
|
||||||
.port = 0,
|
.port = 0,
|
||||||
.pad = 0,
|
.pad = 0,
|
||||||
@@ -228,13 +228,13 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(std::span<u8> data) {
|
|||||||
status.state = Common::Input::NfcState::NewAmiibo,
|
status.state = Common::Input::NfcState::NewAmiibo,
|
||||||
memcpy(nfc_data.data(), data.data(), data.size_bytes());
|
memcpy(nfc_data.data(), data.data(), data.size_bytes());
|
||||||
memcpy(status.uuid.data(), nfc_data.data(), status.uuid_length);
|
memcpy(status.uuid.data(), nfc_data.data(), status.uuid_length);
|
||||||
SetNfc(identifier, status);
|
SetNfc(virtual_amiibo_identifier, status);
|
||||||
return Info::Success;
|
return Info::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() {
|
VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() {
|
||||||
if (state == State::TagNearby) {
|
if (state == State::TagNearby) {
|
||||||
SetNfc(identifier, status);
|
SetNfc(virtual_amiibo_identifier, status);
|
||||||
return Info::Success;
|
return Info::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,7 +248,7 @@ VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() {
|
|||||||
|
|
||||||
state = State::WaitingForAmiibo;
|
state = State::WaitingForAmiibo;
|
||||||
status.state = Common::Input::NfcState::AmiiboRemoved;
|
status.state = Common::Input::NfcState::AmiiboRemoved;
|
||||||
SetNfc(identifier, status);
|
SetNfc(virtual_amiibo_identifier, status);
|
||||||
status.tag_type = 0;
|
status.tag_type = 0;
|
||||||
return Info::Success;
|
return Info::Success;
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-10
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -5,6 +8,7 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
namespace Network {
|
namespace Network {
|
||||||
@@ -118,26 +122,21 @@ private:
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Packet& Packet::Read(std::vector<T>& out_data) {
|
Packet& Packet::Read(std::vector<T>& out_data) {
|
||||||
// First extract the size
|
|
||||||
u32 size = 0;
|
u32 size = 0;
|
||||||
Read(size);
|
Read(size);
|
||||||
out_data.resize(size);
|
out_data.resize(size);
|
||||||
|
|
||||||
// Then extract the data
|
for (auto& elem : out_data) {
|
||||||
for (std::size_t i = 0; i < out_data.size(); ++i) {
|
Read(elem);
|
||||||
T character;
|
|
||||||
Read(character);
|
|
||||||
out_data[i] = character;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t S>
|
template <typename T, std::size_t S>
|
||||||
Packet& Packet::Read(std::array<T, S>& out_data) {
|
Packet& Packet::Read(std::array<T, S>& out_data) {
|
||||||
for (std::size_t i = 0; i < out_data.size(); ++i) {
|
for (auto& elem : out_data) {
|
||||||
T character;
|
Read(elem);
|
||||||
Read(character);
|
|
||||||
out_data[i] = character;
|
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -832,7 +832,7 @@ void Room::RoomImpl::HandleProxyPacket(const ENetEvent* event) {
|
|||||||
|
|
||||||
in_packet.IgnoreBytes(sizeof(u8)); // Protocol
|
in_packet.IgnoreBytes(sizeof(u8)); // Protocol
|
||||||
|
|
||||||
bool broadcast;
|
bool broadcast = false;
|
||||||
in_packet.Read(broadcast); // Broadcast
|
in_packet.Read(broadcast); // Broadcast
|
||||||
|
|
||||||
Packet out_packet;
|
Packet out_packet;
|
||||||
@@ -886,7 +886,7 @@ void Room::RoomImpl::HandleLdnPacket(const ENetEvent* event) {
|
|||||||
IPv4Address remote_ip;
|
IPv4Address remote_ip;
|
||||||
in_packet.Read(remote_ip); // Remote IP
|
in_packet.Read(remote_ip); // Remote IP
|
||||||
|
|
||||||
bool broadcast;
|
bool broadcast = false;
|
||||||
in_packet.Read(broadcast); // Broadcast
|
in_packet.Read(broadcast); // Broadcast
|
||||||
|
|
||||||
Packet out_packet;
|
Packet out_packet;
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -45,11 +48,6 @@ void GetCbuf(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsInputArray(Stage stage) {
|
|
||||||
return stage == Stage::Geometry || stage == Stage::TessellationControl ||
|
|
||||||
stage == Stage::TessellationEval;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string VertexIndex(EmitContext& ctx, ScalarU32 vertex) {
|
std::string VertexIndex(EmitContext& ctx, ScalarU32 vertex) {
|
||||||
return IsInputArray(ctx.stage) ? fmt::format("[{}]", vertex) : "";
|
return IsInputArray(ctx.stage) ? fmt::format("[{}]", vertex) : "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "shader_recompiler/stage.h"
|
||||||
#include "shader_recompiler/backend/glasm/reg_alloc.h"
|
#include "shader_recompiler/backend/glasm/reg_alloc.h"
|
||||||
|
|
||||||
namespace Shader::IR {
|
namespace Shader::IR {
|
||||||
@@ -18,6 +19,11 @@ class Value;
|
|||||||
|
|
||||||
namespace Shader::Backend::GLASM {
|
namespace Shader::Backend::GLASM {
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool IsInputArray(Stage stage) {
|
||||||
|
return stage == Stage::Geometry || stage == Stage::TessellationControl
|
||||||
|
|| stage == Stage::TessellationEval;
|
||||||
|
}
|
||||||
|
|
||||||
class EmitContext;
|
class EmitContext;
|
||||||
|
|
||||||
// Microinstruction emitters
|
// Microinstruction emitters
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -7,94 +10,92 @@
|
|||||||
|
|
||||||
namespace Shader::Backend::GLASM {
|
namespace Shader::Backend::GLASM {
|
||||||
|
|
||||||
#define NotImplemented() throw NotImplementedException("GLASM instruction {}", __LINE__)
|
|
||||||
|
|
||||||
void EmitGetRegister(EmitContext& ctx) {
|
void EmitGetRegister(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetRegister(EmitContext& ctx) {
|
void EmitSetRegister(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetPred(EmitContext& ctx) {
|
void EmitGetPred(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetPred(EmitContext& ctx) {
|
void EmitSetPred(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetGotoVariable(EmitContext& ctx) {
|
void EmitSetGotoVariable(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetGotoVariable(EmitContext& ctx) {
|
void EmitGetGotoVariable(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetIndirectBranchVariable(EmitContext& ctx) {
|
void EmitSetIndirectBranchVariable(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetIndirectBranchVariable(EmitContext& ctx) {
|
void EmitGetIndirectBranchVariable(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetZFlag(EmitContext& ctx) {
|
void EmitGetZFlag(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetSFlag(EmitContext& ctx) {
|
void EmitGetSFlag(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetCFlag(EmitContext& ctx) {
|
void EmitGetCFlag(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetOFlag(EmitContext& ctx) {
|
void EmitGetOFlag(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetZFlag(EmitContext& ctx) {
|
void EmitSetZFlag(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetSFlag(EmitContext& ctx) {
|
void EmitSetSFlag(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetCFlag(EmitContext& ctx) {
|
void EmitSetCFlag(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetOFlag(EmitContext& ctx) {
|
void EmitSetOFlag(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetZeroFromOp(EmitContext& ctx) {
|
void EmitGetZeroFromOp(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetSignFromOp(EmitContext& ctx) {
|
void EmitGetSignFromOp(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetCarryFromOp(EmitContext& ctx) {
|
void EmitGetCarryFromOp(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetOverflowFromOp(EmitContext& ctx) {
|
void EmitGetOverflowFromOp(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetSparseFromOp(EmitContext& ctx) {
|
void EmitGetSparseFromOp(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetInBoundsFromOp(EmitContext& ctx) {
|
void EmitGetInBoundsFromOp(EmitContext& ctx) {
|
||||||
NotImplemented();
|
throw NotImplementedException("GLASM instruction {}", __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Shader::Backend::GLASM
|
} // namespace Shader::Backend::GLASM
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "shader_recompiler/backend/bindings.h"
|
#include "shader_recompiler/backend/bindings.h"
|
||||||
#include "shader_recompiler/backend/glasm/emit_glasm.h"
|
#include "shader_recompiler/backend/glasm/emit_glasm.h"
|
||||||
|
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||||
#include "shader_recompiler/frontend/ir/program.h"
|
#include "shader_recompiler/frontend/ir/program.h"
|
||||||
#include "shader_recompiler/profile.h"
|
#include "shader_recompiler/profile.h"
|
||||||
@@ -21,11 +25,6 @@ std::string_view InterpDecorator(Interpolation interp) {
|
|||||||
}
|
}
|
||||||
throw InvalidArgument("Invalid interpolation {}", interp);
|
throw InvalidArgument("Invalid interpolation {}", interp);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsInputArray(Stage stage) {
|
|
||||||
return stage == Stage::Geometry || stage == Stage::TessellationControl ||
|
|
||||||
stage == Stage::TessellationEval;
|
|
||||||
}
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_,
|
EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_,
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -9,14 +12,13 @@
|
|||||||
|
|
||||||
namespace Shader::Backend::GLSL {
|
namespace Shader::Backend::GLSL {
|
||||||
namespace {
|
namespace {
|
||||||
constexpr std::string_view SWIZZLE{"xyzw"};
|
|
||||||
void CompositeInsert(EmitContext& ctx, std::string_view result, std::string_view composite,
|
void CompositeInsert(EmitContext& ctx, std::string_view result, std::string_view composite,
|
||||||
std::string_view object, u32 index) {
|
std::string_view object, u32 index) {
|
||||||
if (result == composite) {
|
if (result == composite) {
|
||||||
// The result is aliased with the composite
|
// The result is aliased with the composite
|
||||||
ctx.Add("{}.{}={};", composite, SWIZZLE[index], object);
|
ctx.Add("{}.{}={};", composite, "xyzw"[index], object);
|
||||||
} else {
|
} else {
|
||||||
ctx.Add("{}={};{}.{}={};", result, composite, result, SWIZZLE[index], object);
|
ctx.Add("{}={};{}.{}={};", result, composite, result, "xyzw"[index], object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
@@ -38,17 +40,17 @@ void EmitCompositeConstructU32x4(EmitContext& ctx, IR::Inst& inst, std::string_v
|
|||||||
|
|
||||||
void EmitCompositeExtractU32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
void EmitCompositeExtractU32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||||
u32 index) {
|
u32 index) {
|
||||||
ctx.AddU32("{}={}.{};", inst, composite, SWIZZLE[index]);
|
ctx.AddU32("{}={}.{};", inst, composite, "xyzw"[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitCompositeExtractU32x3(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
void EmitCompositeExtractU32x3(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||||
u32 index) {
|
u32 index) {
|
||||||
ctx.AddU32("{}={}.{};", inst, composite, SWIZZLE[index]);
|
ctx.AddU32("{}={}.{};", inst, composite, "xyzw"[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitCompositeExtractU32x4(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
void EmitCompositeExtractU32x4(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||||
u32 index) {
|
u32 index) {
|
||||||
ctx.AddU32("{}={}.{};", inst, composite, SWIZZLE[index]);
|
ctx.AddU32("{}={}.{};", inst, composite, "xyzw"[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitCompositeInsertU32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
void EmitCompositeInsertU32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||||
@@ -146,17 +148,17 @@ void EmitCompositeConstructF32x4(EmitContext& ctx, IR::Inst& inst, std::string_v
|
|||||||
|
|
||||||
void EmitCompositeExtractF32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
void EmitCompositeExtractF32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||||
u32 index) {
|
u32 index) {
|
||||||
ctx.AddF32("{}={}.{};", inst, composite, SWIZZLE[index]);
|
ctx.AddF32("{}={}.{};", inst, composite, "xyzw"[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitCompositeExtractF32x3(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
void EmitCompositeExtractF32x3(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||||
u32 index) {
|
u32 index) {
|
||||||
ctx.AddF32("{}={}.{};", inst, composite, SWIZZLE[index]);
|
ctx.AddF32("{}={}.{};", inst, composite, "xyzw"[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitCompositeExtractF32x4(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
void EmitCompositeExtractF32x4(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||||
u32 index) {
|
u32 index) {
|
||||||
ctx.AddF32("{}={}.{};", inst, composite, SWIZZLE[index]);
|
ctx.AddF32("{}={}.{};", inst, composite, "xyzw"[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitCompositeInsertF32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
void EmitCompositeInsertF32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||||
@@ -203,16 +205,16 @@ void EmitCompositeExtractF64x4([[maybe_unused]] EmitContext& ctx) {
|
|||||||
|
|
||||||
void EmitCompositeInsertF64x2(EmitContext& ctx, std::string_view composite, std::string_view object,
|
void EmitCompositeInsertF64x2(EmitContext& ctx, std::string_view composite, std::string_view object,
|
||||||
u32 index) {
|
u32 index) {
|
||||||
ctx.Add("{}.{}={};", composite, SWIZZLE[index], object);
|
ctx.Add("{}.{}={};", composite, "xyzw"[index], object);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitCompositeInsertF64x3(EmitContext& ctx, std::string_view composite, std::string_view object,
|
void EmitCompositeInsertF64x3(EmitContext& ctx, std::string_view composite, std::string_view object,
|
||||||
u32 index) {
|
u32 index) {
|
||||||
ctx.Add("{}.{}={};", composite, SWIZZLE[index], object);
|
ctx.Add("{}.{}={};", composite, "xyzw"[index], object);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitCompositeInsertF64x4(EmitContext& ctx, std::string_view composite, std::string_view object,
|
void EmitCompositeInsertF64x4(EmitContext& ctx, std::string_view composite, std::string_view object,
|
||||||
u32 index) {
|
u32 index) {
|
||||||
ctx.Add("{}.{}={};", composite, SWIZZLE[index], object);
|
ctx.Add("{}.{}={};", composite, "xyzw"[index], object);
|
||||||
}
|
}
|
||||||
} // namespace Shader::Backend::GLSL
|
} // namespace Shader::Backend::GLSL
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -11,14 +14,13 @@
|
|||||||
|
|
||||||
namespace Shader::Backend::GLSL {
|
namespace Shader::Backend::GLSL {
|
||||||
namespace {
|
namespace {
|
||||||
constexpr char SWIZZLE[]{"xyzw"};
|
|
||||||
|
|
||||||
u32 CbufIndex(u32 offset) {
|
u32 CbufIndex(u32 offset) {
|
||||||
return (offset / 4) % 4;
|
return (offset / 4) % 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
char OffsetSwizzle(u32 offset) {
|
char OffsetSwizzle(u32 offset) {
|
||||||
return SWIZZLE[CbufIndex(offset)];
|
return "xyzw"[CbufIndex(offset)];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsInputArray(Stage stage) {
|
bool IsInputArray(Stage stage) {
|
||||||
@@ -30,10 +32,6 @@ std::string InputVertexIndex(EmitContext& ctx, std::string_view vertex) {
|
|||||||
return IsInputArray(ctx.stage) ? fmt::format("[{}]", vertex) : "";
|
return IsInputArray(ctx.stage) ? fmt::format("[{}]", vertex) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view OutputVertexIndex(EmitContext& ctx) {
|
|
||||||
return ctx.stage == Stage::TessellationControl ? "[gl_InvocationID]" : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ChooseCbuf(EmitContext& ctx, const IR::Value& binding, std::string_view index) {
|
std::string ChooseCbuf(EmitContext& ctx, const IR::Value& binding, std::string_view index) {
|
||||||
if (binding.IsImmediate()) {
|
if (binding.IsImmediate()) {
|
||||||
return fmt::format("{}_cbuf{}[{}]", ctx.stage_name, binding.U32(), index);
|
return fmt::format("{}_cbuf{}[{}]", ctx.stage_name, binding.U32(), index);
|
||||||
@@ -279,7 +277,7 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view val
|
|||||||
const u32 index{IR::GenericAttributeIndex(attr)};
|
const u32 index{IR::GenericAttributeIndex(attr)};
|
||||||
const u32 attr_element{IR::GenericAttributeElement(attr)};
|
const u32 attr_element{IR::GenericAttributeElement(attr)};
|
||||||
const GenericElementInfo& info{ctx.output_generics.at(index).at(attr_element)};
|
const GenericElementInfo& info{ctx.output_generics.at(index).at(attr_element)};
|
||||||
const auto output_decorator{OutputVertexIndex(ctx)};
|
const auto output_decorator = ctx.stage == Stage::TessellationControl ? "[gl_InvocationID]" : "";
|
||||||
if (info.num_components == 1) {
|
if (info.num_components == 1) {
|
||||||
ctx.Add("{}{}={};", info.name, output_decorator, value);
|
ctx.Add("{}{}={};", info.name, output_decorator, value);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -10,14 +13,13 @@
|
|||||||
|
|
||||||
namespace Shader::Backend::GLSL {
|
namespace Shader::Backend::GLSL {
|
||||||
namespace {
|
namespace {
|
||||||
constexpr char cas_loop[]{"for(;;){{uint old_value={};uint "
|
|
||||||
"cas_result=atomicCompSwap({},old_value,bitfieldInsert({},{},{},{}));"
|
|
||||||
"if(cas_result==old_value){{break;}}}}"};
|
|
||||||
|
|
||||||
void SsboWriteCas(EmitContext& ctx, const IR::Value& binding, std::string_view offset_var,
|
void SsboWriteCas(EmitContext& ctx, const IR::Value& binding, std::string_view offset_var,
|
||||||
std::string_view value, std::string_view bit_offset, u32 num_bits) {
|
std::string_view value, std::string_view bit_offset, u32 num_bits) {
|
||||||
const auto ssbo{fmt::format("{}_ssbo{}[{}>>2]", ctx.stage_name, binding.U32(), offset_var)};
|
const auto ssbo{fmt::format("{}_ssbo{}[{}>>2]", ctx.stage_name, binding.U32(), offset_var)};
|
||||||
ctx.Add(cas_loop, ssbo, ssbo, ssbo, value, bit_offset, num_bits);
|
ctx.Add(
|
||||||
|
"for(;;){{uint old_value={};uint "
|
||||||
|
"cas_result=atomicCompSwap({},old_value,bitfieldInsert({},{},{},{}));"
|
||||||
|
"if(cas_result==old_value){{break;}}}}", ssbo, ssbo, ssbo, value, bit_offset, num_bits);
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -7,14 +10,13 @@
|
|||||||
|
|
||||||
namespace Shader::Backend::GLSL {
|
namespace Shader::Backend::GLSL {
|
||||||
namespace {
|
namespace {
|
||||||
constexpr char cas_loop[]{"for(;;){{uint old_value={};uint "
|
|
||||||
"cas_result=atomicCompSwap({},old_value,bitfieldInsert({},{},{},{}));"
|
|
||||||
"if(cas_result==old_value){{break;}}}}"};
|
|
||||||
|
|
||||||
void SharedWriteCas(EmitContext& ctx, std::string_view offset, std::string_view value,
|
void SharedWriteCas(EmitContext& ctx, std::string_view offset, std::string_view value,
|
||||||
std::string_view bit_offset, u32 num_bits) {
|
std::string_view bit_offset, u32 num_bits) {
|
||||||
const auto smem{fmt::format("smem[{}>>2]", offset)};
|
const auto smem{fmt::format("smem[{}>>2]", offset)};
|
||||||
ctx.Add(cas_loop, smem, smem, smem, value, bit_offset, num_bits);
|
ctx.Add(
|
||||||
|
"for(;;){{uint old_value={};uint "
|
||||||
|
"cas_result=atomicCompSwap({},old_value,bitfieldInsert({},{},{},{}));"
|
||||||
|
"if(cas_result==old_value){{break;}}}}", smem, smem, smem, value, bit_offset, num_bits);
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -9,9 +12,6 @@
|
|||||||
|
|
||||||
namespace Shader::Backend::GLSL {
|
namespace Shader::Backend::GLSL {
|
||||||
namespace {
|
namespace {
|
||||||
std::string_view OutputVertexIndex(EmitContext& ctx) {
|
|
||||||
return ctx.stage == Stage::TessellationControl ? "[gl_InvocationID]" : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeOutputVaryings(EmitContext& ctx) {
|
void InitializeOutputVaryings(EmitContext& ctx) {
|
||||||
if (ctx.uses_geometry_passthrough) {
|
if (ctx.uses_geometry_passthrough) {
|
||||||
@@ -25,7 +25,7 @@ void InitializeOutputVaryings(EmitContext& ctx) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto& info_array{ctx.output_generics.at(index)};
|
const auto& info_array{ctx.output_generics.at(index)};
|
||||||
const auto output_decorator{OutputVertexIndex(ctx)};
|
const auto output_decorator = ctx.stage == Stage::TessellationControl ? "[gl_InvocationID]" : "";
|
||||||
size_t element{};
|
size_t element{};
|
||||||
while (element < info_array.size()) {
|
while (element < info_array.size()) {
|
||||||
const auto& info{info_array.at(element)};
|
const auto& info{info_array.at(element)};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace Shader::Backend::SPIRV {
|
namespace Shader::Backend::SPIRV {
|
||||||
namespace {
|
namespace {
|
||||||
Id Decorate(EmitContext& ctx, IR::Inst* inst, Id op) {
|
Id DecorateNoContraction(EmitContext& ctx, IR::Inst* inst, Id op) {
|
||||||
const auto flags{inst->Flags<IR::FpControl>()};
|
const auto flags{inst->Flags<IR::FpControl>()};
|
||||||
if (flags.no_contraction) {
|
if (flags.no_contraction) {
|
||||||
ctx.Decorate(op, spv::Decoration::NoContraction);
|
ctx.Decorate(op, spv::Decoration::NoContraction);
|
||||||
@@ -61,27 +61,27 @@ Id EmitFPAbs64(EmitContext& ctx, Id value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitFPAdd16(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
Id EmitFPAdd16(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||||
return Decorate(ctx, inst, ctx.OpFAdd(ctx.F16[1], a, b));
|
return DecorateNoContraction(ctx, inst, ctx.OpFAdd(ctx.F16[1], a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitFPAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
Id EmitFPAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||||
return Decorate(ctx, inst, ctx.OpFAdd(ctx.F32[1], a, b));
|
return DecorateNoContraction(ctx, inst, ctx.OpFAdd(ctx.F32[1], a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitFPAdd64(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
Id EmitFPAdd64(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||||
return Decorate(ctx, inst, ctx.OpFAdd(ctx.F64[1], a, b));
|
return DecorateNoContraction(ctx, inst, ctx.OpFAdd(ctx.F64[1], a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitFPFma16(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
|
Id EmitFPFma16(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
|
||||||
return Decorate(ctx, inst, ctx.OpFma(ctx.F16[1], a, b, c));
|
return DecorateNoContraction(ctx, inst, ctx.OpFma(ctx.F16[1], a, b, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitFPFma32(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
|
Id EmitFPFma32(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
|
||||||
return Decorate(ctx, inst, ctx.OpFma(ctx.F32[1], a, b, c));
|
return DecorateNoContraction(ctx, inst, ctx.OpFma(ctx.F32[1], a, b, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitFPFma64(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
|
Id EmitFPFma64(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
|
||||||
return Decorate(ctx, inst, ctx.OpFma(ctx.F64[1], a, b, c));
|
return DecorateNoContraction(ctx, inst, ctx.OpFma(ctx.F64[1], a, b, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitFPMax32(EmitContext& ctx, Id a, Id b) {
|
Id EmitFPMax32(EmitContext& ctx, Id a, Id b) {
|
||||||
@@ -101,15 +101,15 @@ Id EmitFPMin64(EmitContext& ctx, Id a, Id b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitFPMul16(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
Id EmitFPMul16(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||||
return Decorate(ctx, inst, ctx.OpFMul(ctx.F16[1], a, b));
|
return DecorateNoContraction(ctx, inst, ctx.OpFMul(ctx.F16[1], a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitFPMul32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
Id EmitFPMul32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||||
return Decorate(ctx, inst, ctx.OpFMul(ctx.F32[1], a, b));
|
return DecorateNoContraction(ctx, inst, ctx.OpFMul(ctx.F32[1], a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitFPMul64(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
Id EmitFPMul64(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||||
return Decorate(ctx, inst, ctx.OpFMul(ctx.F64[1], a, b));
|
return DecorateNoContraction(ctx, inst, ctx.OpFMul(ctx.F64[1], a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitFPNeg16(EmitContext& ctx, Id value) {
|
Id EmitFPNeg16(EmitContext& ctx, Id value) {
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ bool IsTextureInteger(EmitContext& ctx, const IR::TextureInstInfo& info) {
|
|||||||
return ctx.textures.at(info.descriptor_index).is_integer;
|
return ctx.textures.at(info.descriptor_index).is_integer;
|
||||||
}
|
}
|
||||||
|
|
||||||
Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) {
|
Id DecorateRelaxedPrecision(EmitContext& ctx, IR::Inst* inst, Id sample) {
|
||||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||||
if (info.relaxed_precision != 0) {
|
if (info.relaxed_precision != 0) {
|
||||||
ctx.Decorate(sample, spv::Decoration::RelaxedPrecision);
|
ctx.Decorate(sample, spv::Decoration::RelaxedPrecision);
|
||||||
@@ -280,14 +280,14 @@ Id Emit(MethodPtrType sparse_ptr, MethodPtrType non_sparse_ptr, EmitContext& ctx
|
|||||||
Id result_type, Args&&... args) {
|
Id result_type, Args&&... args) {
|
||||||
IR::Inst* const sparse{inst->GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp)};
|
IR::Inst* const sparse{inst->GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp)};
|
||||||
if (!sparse) {
|
if (!sparse) {
|
||||||
return Decorate(ctx, inst, (ctx.*non_sparse_ptr)(result_type, std::forward<Args>(args)...));
|
return DecorateRelaxedPrecision(ctx, inst, (ctx.*non_sparse_ptr)(result_type, std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
const Id struct_type{ctx.TypeStruct(ctx.U32[1], result_type)};
|
const Id struct_type{ctx.TypeStruct(ctx.U32[1], result_type)};
|
||||||
const Id sample{(ctx.*sparse_ptr)(struct_type, std::forward<Args>(args)...)};
|
const Id sample{(ctx.*sparse_ptr)(struct_type, std::forward<Args>(args)...)};
|
||||||
const Id resident_code{ctx.OpCompositeExtract(ctx.U32[1], sample, 0U)};
|
const Id resident_code{ctx.OpCompositeExtract(ctx.U32[1], sample, 0U)};
|
||||||
sparse->SetDefinition(ctx.OpImageSparseTexelsResident(ctx.U1, resident_code));
|
sparse->SetDefinition(ctx.OpImageSparseTexelsResident(ctx.U1, resident_code));
|
||||||
sparse->Invalidate();
|
sparse->Invalidate();
|
||||||
Decorate(ctx, inst, sample);
|
DecorateRelaxedPrecision(ctx, inst, sample);
|
||||||
return ctx.OpCompositeExtract(result_type, sample, 1U);
|
return ctx.OpCompositeExtract(result_type, sample, 1U);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -17,14 +20,13 @@ Id Image(EmitContext& ctx, IR::TextureInstInfo info) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<Id, Id> AtomicArgs(EmitContext& ctx) {
|
std::pair<Id, Id> AtomicImageArgs(EmitContext& ctx) {
|
||||||
const Id scope{ctx.Const(static_cast<u32>(spv::Scope::Device))};
|
const Id scope{ctx.Const(static_cast<u32>(spv::Scope::Device))};
|
||||||
const Id semantics{ctx.u32_zero_value};
|
const Id semantics{ctx.u32_zero_value};
|
||||||
return {scope, semantics};
|
return {scope, semantics};
|
||||||
}
|
}
|
||||||
|
|
||||||
Id ImageAtomicU32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id value,
|
Id ImageAtomicU32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id value, Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id)) {
|
||||||
Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id)) {
|
|
||||||
if (!index.IsImmediate() || index.U32() != 0) {
|
if (!index.IsImmediate() || index.U32() != 0) {
|
||||||
// TODO: handle layers
|
// TODO: handle layers
|
||||||
throw NotImplementedException("Image indexing");
|
throw NotImplementedException("Image indexing");
|
||||||
@@ -32,7 +34,7 @@ Id ImageAtomicU32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c
|
|||||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||||
const Id image{Image(ctx, info)};
|
const Id image{Image(ctx, info)};
|
||||||
const Id pointer{ctx.OpImageTexelPointer(ctx.image_u32, image, coords, ctx.Const(0U))};
|
const Id pointer{ctx.OpImageTexelPointer(ctx.image_u32, image, coords, ctx.Const(0U))};
|
||||||
const auto [scope, semantics]{AtomicArgs(ctx)};
|
const auto [scope, semantics] = AtomicImageArgs(ctx);
|
||||||
return (ctx.*atomic_func)(ctx.U32[1], pointer, scope, semantics, value);
|
return (ctx.*atomic_func)(ctx.U32[1], pointer, scope, semantics, value);
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -12,7 +15,7 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
union Encoding {
|
union EncodingIBTT {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<8, 8, IR::Reg> src_reg;
|
BitField<8, 8, IR::Reg> src_reg;
|
||||||
@@ -45,7 +48,7 @@ std::optional<u64> TrackLDC(Environment& env, Location block_begin, Location& po
|
|||||||
std::optional<u64> TrackSHL(Environment& env, Location block_begin, Location& pos,
|
std::optional<u64> TrackSHL(Environment& env, Location block_begin, Location& pos,
|
||||||
IR::Reg ldc_reg) {
|
IR::Reg ldc_reg) {
|
||||||
return Track(env, block_begin, pos, [ldc_reg](u64 insn, Opcode opcode) {
|
return Track(env, block_begin, pos, [ldc_reg](u64 insn, Opcode opcode) {
|
||||||
const Encoding shl{insn};
|
const EncodingIBTT shl{insn};
|
||||||
return opcode == Opcode::SHL_imm && shl.dest_reg == ldc_reg;
|
return opcode == Opcode::SHL_imm && shl.dest_reg == ldc_reg;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -53,7 +56,7 @@ std::optional<u64> TrackSHL(Environment& env, Location block_begin, Location& po
|
|||||||
std::optional<u64> TrackIMNMX(Environment& env, Location block_begin, Location& pos,
|
std::optional<u64> TrackIMNMX(Environment& env, Location block_begin, Location& pos,
|
||||||
IR::Reg shl_reg) {
|
IR::Reg shl_reg) {
|
||||||
return Track(env, block_begin, pos, [shl_reg](u64 insn, Opcode opcode) {
|
return Track(env, block_begin, pos, [shl_reg](u64 insn, Opcode opcode) {
|
||||||
const Encoding imnmx{insn};
|
const EncodingIBTT imnmx{insn};
|
||||||
return opcode == Opcode::IMNMX_imm && imnmx.dest_reg == shl_reg;
|
return opcode == Opcode::IMNMX_imm && imnmx.dest_reg == shl_reg;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -66,8 +69,8 @@ std::optional<IndirectBranchTableInfo> TrackIndirectBranchTable(Environment& env
|
|||||||
if (brx_opcode != Opcode::BRX && brx_opcode != Opcode::JMX) {
|
if (brx_opcode != Opcode::BRX && brx_opcode != Opcode::JMX) {
|
||||||
throw LogicError("Tracked instruction is not BRX or JMX");
|
throw LogicError("Tracked instruction is not BRX or JMX");
|
||||||
}
|
}
|
||||||
const IR::Reg brx_reg{Encoding{brx_insn}.src_reg};
|
const IR::Reg brx_reg{EncodingIBTT{brx_insn}.src_reg};
|
||||||
const s32 brx_offset{static_cast<s32>(Encoding{brx_insn}.brx_offset)};
|
const s32 brx_offset{static_cast<s32>(EncodingIBTT{brx_insn}.brx_offset)};
|
||||||
|
|
||||||
Location pos{brx_pos};
|
Location pos{brx_pos};
|
||||||
const std::optional<u64> ldc_insn{TrackLDC(env, block_begin, pos, brx_reg)};
|
const std::optional<u64> ldc_insn{TrackLDC(env, block_begin, pos, brx_reg)};
|
||||||
@@ -83,14 +86,14 @@ std::optional<IndirectBranchTableInfo> TrackIndirectBranchTable(Environment& env
|
|||||||
if (!shl_insn) {
|
if (!shl_insn) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
const Encoding shl{*shl_insn};
|
const EncodingIBTT shl{*shl_insn};
|
||||||
const IR::Reg shl_reg{shl.src_reg};
|
const IR::Reg shl_reg{shl.src_reg};
|
||||||
|
|
||||||
const std::optional<u64> imnmx_insn{TrackIMNMX(env, block_begin, pos, shl_reg)};
|
const std::optional<u64> imnmx_insn{TrackIMNMX(env, block_begin, pos, shl_reg)};
|
||||||
if (!imnmx_insn) {
|
if (!imnmx_insn) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
const Encoding imnmx{*imnmx_insn};
|
const EncodingIBTT imnmx{*imnmx_insn};
|
||||||
if (imnmx.is_negative != 0) {
|
if (imnmx.is_negative != 0) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-25
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class AtomOp : u64 {
|
enum class AtomicGlobalMemoryOp : u64 {
|
||||||
ADD,
|
ADD,
|
||||||
MIN,
|
MIN,
|
||||||
MAX,
|
MAX,
|
||||||
@@ -32,33 +32,33 @@ enum class AtomSize : u64 {
|
|||||||
S64,
|
S64,
|
||||||
};
|
};
|
||||||
|
|
||||||
IR::U32U64 ApplyIntegerAtomOp(IR::IREmitter& ir, const IR::U32U64& offset, const IR::U32U64& op_b, AtomOp op, AtomSize size) {
|
IR::U32U64 ApplyIntegerAtomOp(IR::IREmitter& ir, const IR::U32U64& offset, const IR::U32U64& op_b, AtomicGlobalMemoryOp op, AtomSize size) {
|
||||||
bool const is_signed = size == AtomSize::S64 || size == AtomSize::S32;
|
bool const is_signed = size == AtomSize::S64 || size == AtomSize::S32;
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case AtomOp::ADD:
|
case AtomicGlobalMemoryOp::ADD:
|
||||||
return ir.GlobalAtomicIAdd(offset, op_b);
|
return ir.GlobalAtomicIAdd(offset, op_b);
|
||||||
case AtomOp::MIN:
|
case AtomicGlobalMemoryOp::MIN:
|
||||||
return ir.GlobalAtomicIMin(offset, op_b, is_signed);
|
return ir.GlobalAtomicIMin(offset, op_b, is_signed);
|
||||||
case AtomOp::MAX:
|
case AtomicGlobalMemoryOp::MAX:
|
||||||
return ir.GlobalAtomicIMax(offset, op_b, is_signed);
|
return ir.GlobalAtomicIMax(offset, op_b, is_signed);
|
||||||
case AtomOp::INC:
|
case AtomicGlobalMemoryOp::INC:
|
||||||
return ir.GlobalAtomicInc(offset, op_b);
|
return ir.GlobalAtomicInc(offset, op_b);
|
||||||
case AtomOp::DEC:
|
case AtomicGlobalMemoryOp::DEC:
|
||||||
return ir.GlobalAtomicDec(offset, op_b);
|
return ir.GlobalAtomicDec(offset, op_b);
|
||||||
case AtomOp::AND:
|
case AtomicGlobalMemoryOp::AND:
|
||||||
return ir.GlobalAtomicAnd(offset, op_b);
|
return ir.GlobalAtomicAnd(offset, op_b);
|
||||||
case AtomOp::OR:
|
case AtomicGlobalMemoryOp::OR:
|
||||||
return ir.GlobalAtomicOr(offset, op_b);
|
return ir.GlobalAtomicOr(offset, op_b);
|
||||||
case AtomOp::XOR:
|
case AtomicGlobalMemoryOp::XOR:
|
||||||
return ir.GlobalAtomicXor(offset, op_b);
|
return ir.GlobalAtomicXor(offset, op_b);
|
||||||
case AtomOp::EXCH:
|
case AtomicGlobalMemoryOp::EXCH:
|
||||||
return ir.GlobalAtomicExchange(offset, op_b);
|
return ir.GlobalAtomicExchange(offset, op_b);
|
||||||
default:
|
default:
|
||||||
throw NotImplementedException("Integer Atom Operation {}", op);
|
throw NotImplementedException("Integer Atom Operation {}", op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Value ApplyFpAtomOp(IR::IREmitter& ir, const IR::U64& offset, const IR::Value& op_b, AtomOp op,
|
IR::Value ApplyFpAtomOp(IR::IREmitter& ir, const IR::U64& offset, const IR::Value& op_b, AtomicGlobalMemoryOp op,
|
||||||
AtomSize size) {
|
AtomSize size) {
|
||||||
static constexpr IR::FpControl f16_control{
|
static constexpr IR::FpControl f16_control{
|
||||||
.no_contraction = false,
|
.no_contraction = false,
|
||||||
@@ -71,12 +71,12 @@ IR::Value ApplyFpAtomOp(IR::IREmitter& ir, const IR::U64& offset, const IR::Valu
|
|||||||
.fmz_mode = IR::FmzMode::FTZ,
|
.fmz_mode = IR::FmzMode::FTZ,
|
||||||
};
|
};
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case AtomOp::ADD:
|
case AtomicGlobalMemoryOp::ADD:
|
||||||
return size == AtomSize::F32 ? ir.GlobalAtomicF32Add(offset, op_b, f32_control)
|
return size == AtomSize::F32 ? ir.GlobalAtomicF32Add(offset, op_b, f32_control)
|
||||||
: ir.GlobalAtomicF16x2Add(offset, op_b, f16_control);
|
: ir.GlobalAtomicF16x2Add(offset, op_b, f16_control);
|
||||||
case AtomOp::MIN:
|
case AtomicGlobalMemoryOp::MIN:
|
||||||
return ir.GlobalAtomicF16x2Min(offset, op_b, f16_control);
|
return ir.GlobalAtomicF16x2Min(offset, op_b, f16_control);
|
||||||
case AtomOp::MAX:
|
case AtomicGlobalMemoryOp::MAX:
|
||||||
return ir.GlobalAtomicF16x2Max(offset, op_b, f16_control);
|
return ir.GlobalAtomicF16x2Max(offset, op_b, f16_control);
|
||||||
default:
|
default:
|
||||||
throw NotImplementedException("FP Atom Operation {}", op);
|
throw NotImplementedException("FP Atom Operation {}", op);
|
||||||
@@ -112,19 +112,19 @@ IR::U64 AtomOffset(TranslatorVisitor& v, u64 insn) {
|
|||||||
// ADD, INC, DEC for S64 does nothing
|
// ADD, INC, DEC for S64 does nothing
|
||||||
// Only ADD does something for F32
|
// Only ADD does something for F32
|
||||||
// Only ADD, MIN and MAX does something for F16x2
|
// Only ADD, MIN and MAX does something for F16x2
|
||||||
bool AtomOpNotApplicable(AtomSize size, AtomOp op) {
|
bool AtomOpNotApplicable(AtomSize size, AtomicGlobalMemoryOp op) {
|
||||||
// TODO: SAFEADD
|
// TODO: SAFEADD
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case AtomSize::U32:
|
case AtomSize::U32:
|
||||||
case AtomSize::S32:
|
case AtomSize::S32:
|
||||||
case AtomSize::U64:
|
case AtomSize::U64:
|
||||||
return (op == AtomOp::INC || op == AtomOp::DEC);
|
return (op == AtomicGlobalMemoryOp::INC || op == AtomicGlobalMemoryOp::DEC);
|
||||||
case AtomSize::S64:
|
case AtomSize::S64:
|
||||||
return (op == AtomOp::ADD || op == AtomOp::INC || op == AtomOp::DEC);
|
return (op == AtomicGlobalMemoryOp::ADD || op == AtomicGlobalMemoryOp::INC || op == AtomicGlobalMemoryOp::DEC);
|
||||||
case AtomSize::F32:
|
case AtomSize::F32:
|
||||||
return op != AtomOp::ADD;
|
return op != AtomicGlobalMemoryOp::ADD;
|
||||||
case AtomSize::F16x2:
|
case AtomSize::F16x2:
|
||||||
return !(op == AtomOp::ADD || op == AtomOp::MIN || op == AtomOp::MAX);
|
return !(op == AtomicGlobalMemoryOp::ADD || op == AtomicGlobalMemoryOp::MIN || op == AtomicGlobalMemoryOp::MAX);
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -162,7 +162,7 @@ void StoreResult(TranslatorVisitor& v, IR::Reg dest_reg, const IR::Value& result
|
|||||||
}
|
}
|
||||||
|
|
||||||
IR::Value ApplyAtomOp(TranslatorVisitor& v, IR::Reg operand_reg, const IR::U64& offset,
|
IR::Value ApplyAtomOp(TranslatorVisitor& v, IR::Reg operand_reg, const IR::U64& offset,
|
||||||
AtomSize size, AtomOp op) {
|
AtomSize size, AtomicGlobalMemoryOp op) {
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case AtomSize::U32:
|
case AtomSize::U32:
|
||||||
case AtomSize::S32:
|
case AtomSize::S32:
|
||||||
@@ -180,7 +180,7 @@ IR::Value ApplyAtomOp(TranslatorVisitor& v, IR::Reg operand_reg, const IR::U64&
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GlobalAtomic(TranslatorVisitor& v, IR::Reg dest_reg, IR::Reg operand_reg,
|
void GlobalAtomic(TranslatorVisitor& v, IR::Reg dest_reg, IR::Reg operand_reg,
|
||||||
const IR::U64& offset, AtomSize size, AtomOp op, bool write_dest) {
|
const IR::U64& offset, AtomSize size, AtomicGlobalMemoryOp op, bool write_dest) {
|
||||||
IR::Value result = AtomOpNotApplicable(size, op)
|
IR::Value result = AtomOpNotApplicable(size, op)
|
||||||
? LoadGlobal(v.ir, offset, size)
|
? LoadGlobal(v.ir, offset, size)
|
||||||
: ApplyAtomOp(v, operand_reg, offset, size, op);
|
: ApplyAtomOp(v, operand_reg, offset, size, op);
|
||||||
@@ -195,7 +195,7 @@ void TranslatorVisitor::ATOM(u64 insn) {
|
|||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<20, 8, IR::Reg> operand_reg;
|
BitField<20, 8, IR::Reg> operand_reg;
|
||||||
BitField<49, 3, AtomSize> size;
|
BitField<49, 3, AtomSize> size;
|
||||||
BitField<52, 4, AtomOp> op;
|
BitField<52, 4, AtomicGlobalMemoryOp> op;
|
||||||
} const atom{insn};
|
} const atom{insn};
|
||||||
const IR::U64 offset{AtomOffset(*this, insn)};
|
const IR::U64 offset{AtomOffset(*this, insn)};
|
||||||
GlobalAtomic(*this, atom.dest_reg, atom.operand_reg, offset, atom.size, atom.op, true);
|
GlobalAtomic(*this, atom.dest_reg, atom.operand_reg, offset, atom.size, atom.op, true);
|
||||||
@@ -206,7 +206,7 @@ void TranslatorVisitor::RED(u64 insn) {
|
|||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<0, 8, IR::Reg> operand_reg;
|
BitField<0, 8, IR::Reg> operand_reg;
|
||||||
BitField<20, 3, AtomSize> size;
|
BitField<20, 3, AtomSize> size;
|
||||||
BitField<23, 3, AtomOp> op;
|
BitField<23, 3, AtomicGlobalMemoryOp> op;
|
||||||
} const red{insn};
|
} const red{insn};
|
||||||
const IR::U64 offset{AtomOffset(*this, insn)};
|
const IR::U64 offset{AtomOffset(*this, insn)};
|
||||||
GlobalAtomic(*this, IR::Reg::RZ, red.operand_reg, offset, red.size, red.op, true);
|
GlobalAtomic(*this, IR::Reg::RZ, red.operand_reg, offset, red.size, red.op, true);
|
||||||
|
|||||||
+16
-14
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -7,7 +10,7 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class AtomOp : u64 {
|
enum class AtomicSharedMemoryOp : u64 {
|
||||||
ADD,
|
ADD,
|
||||||
MIN,
|
MIN,
|
||||||
MAX,
|
MAX,
|
||||||
@@ -25,26 +28,25 @@ enum class AtomsSize : u64 {
|
|||||||
U64,
|
U64,
|
||||||
};
|
};
|
||||||
|
|
||||||
IR::U32U64 ApplyAtomsOp(IR::IREmitter& ir, const IR::U32& offset, const IR::U32U64& op_b, AtomOp op,
|
IR::U32U64 ApplyAtomsOp(IR::IREmitter& ir, const IR::U32& offset, const IR::U32U64& op_b, AtomicSharedMemoryOp op, bool is_signed) {
|
||||||
bool is_signed) {
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case AtomOp::ADD:
|
case AtomicSharedMemoryOp::ADD:
|
||||||
return ir.SharedAtomicIAdd(offset, op_b);
|
return ir.SharedAtomicIAdd(offset, op_b);
|
||||||
case AtomOp::MIN:
|
case AtomicSharedMemoryOp::MIN:
|
||||||
return ir.SharedAtomicIMin(offset, op_b, is_signed);
|
return ir.SharedAtomicIMin(offset, op_b, is_signed);
|
||||||
case AtomOp::MAX:
|
case AtomicSharedMemoryOp::MAX:
|
||||||
return ir.SharedAtomicIMax(offset, op_b, is_signed);
|
return ir.SharedAtomicIMax(offset, op_b, is_signed);
|
||||||
case AtomOp::INC:
|
case AtomicSharedMemoryOp::INC:
|
||||||
return ir.SharedAtomicInc(offset, op_b);
|
return ir.SharedAtomicInc(offset, op_b);
|
||||||
case AtomOp::DEC:
|
case AtomicSharedMemoryOp::DEC:
|
||||||
return ir.SharedAtomicDec(offset, op_b);
|
return ir.SharedAtomicDec(offset, op_b);
|
||||||
case AtomOp::AND:
|
case AtomicSharedMemoryOp::AND:
|
||||||
return ir.SharedAtomicAnd(offset, op_b);
|
return ir.SharedAtomicAnd(offset, op_b);
|
||||||
case AtomOp::OR:
|
case AtomicSharedMemoryOp::OR:
|
||||||
return ir.SharedAtomicOr(offset, op_b);
|
return ir.SharedAtomicOr(offset, op_b);
|
||||||
case AtomOp::XOR:
|
case AtomicSharedMemoryOp::XOR:
|
||||||
return ir.SharedAtomicXor(offset, op_b);
|
return ir.SharedAtomicXor(offset, op_b);
|
||||||
case AtomOp::EXCH:
|
case AtomicSharedMemoryOp::EXCH:
|
||||||
return ir.SharedAtomicExchange(offset, op_b);
|
return ir.SharedAtomicExchange(offset, op_b);
|
||||||
default:
|
default:
|
||||||
throw NotImplementedException("Integer Atoms Operation {}", op);
|
throw NotImplementedException("Integer Atoms Operation {}", op);
|
||||||
@@ -87,11 +89,11 @@ void TranslatorVisitor::ATOMS(u64 insn) {
|
|||||||
BitField<8, 8, IR::Reg> addr_reg;
|
BitField<8, 8, IR::Reg> addr_reg;
|
||||||
BitField<20, 8, IR::Reg> src_reg_b;
|
BitField<20, 8, IR::Reg> src_reg_b;
|
||||||
BitField<28, 2, AtomsSize> size;
|
BitField<28, 2, AtomsSize> size;
|
||||||
BitField<52, 4, AtomOp> op;
|
BitField<52, 4, AtomicSharedMemoryOp> op;
|
||||||
} const atoms{insn};
|
} const atoms{insn};
|
||||||
|
|
||||||
const bool size_64{atoms.size == AtomsSize::U64};
|
const bool size_64{atoms.size == AtomsSize::U64};
|
||||||
if (size_64 && atoms.op != AtomOp::EXCH) {
|
if (size_64 && atoms.op != AtomicSharedMemoryOp::EXCH) {
|
||||||
throw NotImplementedException("64-bit Atoms Operation {}", atoms.op.Value());
|
throw NotImplementedException("64-bit Atoms Operation {}", atoms.op.Value());
|
||||||
}
|
}
|
||||||
const bool is_signed{atoms.size == AtomsSize::S32};
|
const bool is_signed{atoms.size == AtomsSize::S32};
|
||||||
|
|||||||
+29
-26
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -6,7 +9,7 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class FloatFormat : u64 {
|
enum class FloatConversionFormat : u64 {
|
||||||
F16 = 1,
|
F16 = 1,
|
||||||
F32 = 2,
|
F32 = 2,
|
||||||
F64 = 3,
|
F64 = 3,
|
||||||
@@ -21,13 +24,13 @@ enum class RoundingOp : u64 {
|
|||||||
Trunc = 11,
|
Trunc = 11,
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] u32 WidthSize(FloatFormat width) {
|
[[nodiscard]] u32 WidthSize(FloatConversionFormat width) {
|
||||||
switch (width) {
|
switch (width) {
|
||||||
case FloatFormat::F16:
|
case FloatConversionFormat::F16:
|
||||||
return 16;
|
return 16;
|
||||||
case FloatFormat::F32:
|
case FloatConversionFormat::F32:
|
||||||
return 32;
|
return 32;
|
||||||
case FloatFormat::F64:
|
case FloatConversionFormat::F64:
|
||||||
return 64;
|
return 64;
|
||||||
default:
|
default:
|
||||||
throw NotImplementedException("Invalid width {}", width);
|
throw NotImplementedException("Invalid width {}", width);
|
||||||
@@ -44,8 +47,8 @@ void F2F(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a, bool abs) {
|
|||||||
BitField<50, 1, u64> sat;
|
BitField<50, 1, u64> sat;
|
||||||
BitField<39, 4, u64> rounding_op;
|
BitField<39, 4, u64> rounding_op;
|
||||||
BitField<39, 2, FpRounding> rounding;
|
BitField<39, 2, FpRounding> rounding;
|
||||||
BitField<10, 2, FloatFormat> src_size;
|
BitField<10, 2, FloatConversionFormat> src_size;
|
||||||
BitField<8, 2, FloatFormat> dst_size;
|
BitField<8, 2, FloatConversionFormat> dst_size;
|
||||||
|
|
||||||
[[nodiscard]] RoundingOp RoundingOperation() const {
|
[[nodiscard]] RoundingOp RoundingOperation() const {
|
||||||
constexpr u64 rounding_mask = 0x0B;
|
constexpr u64 rounding_mask = 0x0B;
|
||||||
@@ -59,7 +62,7 @@ void F2F(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a, bool abs) {
|
|||||||
|
|
||||||
IR::F16F32F64 input{v.ir.FPAbsNeg(src_a, abs, f2f.neg != 0)};
|
IR::F16F32F64 input{v.ir.FPAbsNeg(src_a, abs, f2f.neg != 0)};
|
||||||
|
|
||||||
const bool any_fp64{f2f.src_size == FloatFormat::F64 || f2f.dst_size == FloatFormat::F64};
|
const bool any_fp64{f2f.src_size == FloatConversionFormat::F64 || f2f.dst_size == FloatConversionFormat::F64};
|
||||||
IR::FpControl fp_control{
|
IR::FpControl fp_control{
|
||||||
.no_contraction = false,
|
.no_contraction = false,
|
||||||
.rounding = IR::FpRounding::DontCare,
|
.rounding = IR::FpRounding::DontCare,
|
||||||
@@ -74,13 +77,13 @@ void F2F(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a, bool abs) {
|
|||||||
case RoundingOp::Pass:
|
case RoundingOp::Pass:
|
||||||
// Make sure NANs are handled properly
|
// Make sure NANs are handled properly
|
||||||
switch (f2f.src_size) {
|
switch (f2f.src_size) {
|
||||||
case FloatFormat::F16:
|
case FloatConversionFormat::F16:
|
||||||
input = v.ir.FPAdd(input, v.ir.FPConvert(16, v.ir.Imm32(0.0f)), fp_control);
|
input = v.ir.FPAdd(input, v.ir.FPConvert(16, v.ir.Imm32(0.0f)), fp_control);
|
||||||
break;
|
break;
|
||||||
case FloatFormat::F32:
|
case FloatConversionFormat::F32:
|
||||||
input = v.ir.FPAdd(input, v.ir.Imm32(0.0f), fp_control);
|
input = v.ir.FPAdd(input, v.ir.Imm32(0.0f), fp_control);
|
||||||
break;
|
break;
|
||||||
case FloatFormat::F64:
|
case FloatConversionFormat::F64:
|
||||||
input = v.ir.FPAdd(input, v.ir.Imm64(0.0), fp_control);
|
input = v.ir.FPAdd(input, v.ir.Imm64(0.0), fp_control);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -106,15 +109,15 @@ void F2F(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a, bool abs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (f2f.dst_size) {
|
switch (f2f.dst_size) {
|
||||||
case FloatFormat::F16: {
|
case FloatConversionFormat::F16: {
|
||||||
const IR::F16 imm{v.ir.FPConvert(16, v.ir.Imm32(0.0f))};
|
const IR::F16 imm{v.ir.FPConvert(16, v.ir.Imm32(0.0f))};
|
||||||
v.X(f2f.dest_reg, v.ir.PackFloat2x16(v.ir.CompositeConstruct(input, imm)));
|
v.X(f2f.dest_reg, v.ir.PackFloat2x16(v.ir.CompositeConstruct(input, imm)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FloatFormat::F32:
|
case FloatConversionFormat::F32:
|
||||||
v.F(f2f.dest_reg, input);
|
v.F(f2f.dest_reg, input);
|
||||||
break;
|
break;
|
||||||
case FloatFormat::F64:
|
case FloatConversionFormat::F64:
|
||||||
v.D(f2f.dest_reg, input);
|
v.D(f2f.dest_reg, input);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -127,21 +130,21 @@ void TranslatorVisitor::F2F_reg(u64 insn) {
|
|||||||
union {
|
union {
|
||||||
u64 insn;
|
u64 insn;
|
||||||
BitField<49, 1, u64> abs;
|
BitField<49, 1, u64> abs;
|
||||||
BitField<10, 2, FloatFormat> src_size;
|
BitField<10, 2, FloatConversionFormat> src_size;
|
||||||
BitField<41, 1, u64> selector;
|
BitField<41, 1, u64> selector;
|
||||||
} const f2f{insn};
|
} const f2f{insn};
|
||||||
|
|
||||||
IR::F16F32F64 src_a;
|
IR::F16F32F64 src_a;
|
||||||
switch (f2f.src_size) {
|
switch (f2f.src_size) {
|
||||||
case FloatFormat::F16: {
|
case FloatConversionFormat::F16: {
|
||||||
auto [lhs_a, rhs_a]{Extract(ir, GetReg20(insn), Swizzle::H1_H0)};
|
auto [lhs_a, rhs_a]{Extract(ir, GetReg20(insn), Swizzle::H1_H0)};
|
||||||
src_a = f2f.selector != 0 ? rhs_a : lhs_a;
|
src_a = f2f.selector != 0 ? rhs_a : lhs_a;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FloatFormat::F32:
|
case FloatConversionFormat::F32:
|
||||||
src_a = GetFloatReg20(insn);
|
src_a = GetFloatReg20(insn);
|
||||||
break;
|
break;
|
||||||
case FloatFormat::F64:
|
case FloatConversionFormat::F64:
|
||||||
src_a = GetDoubleReg20(insn);
|
src_a = GetDoubleReg20(insn);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -154,21 +157,21 @@ void TranslatorVisitor::F2F_cbuf(u64 insn) {
|
|||||||
union {
|
union {
|
||||||
u64 insn;
|
u64 insn;
|
||||||
BitField<49, 1, u64> abs;
|
BitField<49, 1, u64> abs;
|
||||||
BitField<10, 2, FloatFormat> src_size;
|
BitField<10, 2, FloatConversionFormat> src_size;
|
||||||
BitField<41, 1, u64> selector;
|
BitField<41, 1, u64> selector;
|
||||||
} const f2f{insn};
|
} const f2f{insn};
|
||||||
|
|
||||||
IR::F16F32F64 src_a;
|
IR::F16F32F64 src_a;
|
||||||
switch (f2f.src_size) {
|
switch (f2f.src_size) {
|
||||||
case FloatFormat::F16: {
|
case FloatConversionFormat::F16: {
|
||||||
auto [lhs_a, rhs_a]{Extract(ir, GetCbuf(insn), Swizzle::H1_H0)};
|
auto [lhs_a, rhs_a]{Extract(ir, GetCbuf(insn), Swizzle::H1_H0)};
|
||||||
src_a = f2f.selector != 0 ? rhs_a : lhs_a;
|
src_a = f2f.selector != 0 ? rhs_a : lhs_a;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FloatFormat::F32:
|
case FloatConversionFormat::F32:
|
||||||
src_a = GetFloatCbuf(insn);
|
src_a = GetFloatCbuf(insn);
|
||||||
break;
|
break;
|
||||||
case FloatFormat::F64:
|
case FloatConversionFormat::F64:
|
||||||
src_a = GetDoubleCbuf(insn);
|
src_a = GetDoubleCbuf(insn);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -181,7 +184,7 @@ void TranslatorVisitor::F2F_imm([[maybe_unused]] u64 insn) {
|
|||||||
union {
|
union {
|
||||||
u64 insn;
|
u64 insn;
|
||||||
BitField<49, 1, u64> abs;
|
BitField<49, 1, u64> abs;
|
||||||
BitField<10, 2, FloatFormat> src_size;
|
BitField<10, 2, FloatConversionFormat> src_size;
|
||||||
BitField<41, 1, u64> selector;
|
BitField<41, 1, u64> selector;
|
||||||
BitField<20, 19, u64> imm;
|
BitField<20, 19, u64> imm;
|
||||||
BitField<56, 1, u64> imm_neg;
|
BitField<56, 1, u64> imm_neg;
|
||||||
@@ -189,7 +192,7 @@ void TranslatorVisitor::F2F_imm([[maybe_unused]] u64 insn) {
|
|||||||
|
|
||||||
IR::F16F32F64 src_a;
|
IR::F16F32F64 src_a;
|
||||||
switch (f2f.src_size) {
|
switch (f2f.src_size) {
|
||||||
case FloatFormat::F16: {
|
case FloatConversionFormat::F16: {
|
||||||
const u32 imm{static_cast<u32>(f2f.imm & 0x0000ffff)};
|
const u32 imm{static_cast<u32>(f2f.imm & 0x0000ffff)};
|
||||||
const IR::Value vector{ir.UnpackFloat2x16(ir.Imm32(imm | (imm << 16)))};
|
const IR::Value vector{ir.UnpackFloat2x16(ir.Imm32(imm | (imm << 16)))};
|
||||||
src_a = IR::F16{ir.CompositeExtract(vector, f2f.selector != 0 ? 0 : 1)};
|
src_a = IR::F16{ir.CompositeExtract(vector, f2f.selector != 0 ? 0 : 1)};
|
||||||
@@ -198,10 +201,10 @@ void TranslatorVisitor::F2F_imm([[maybe_unused]] u64 insn) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FloatFormat::F32:
|
case FloatConversionFormat::F32:
|
||||||
src_a = GetFloatImm20(insn);
|
src_a = GetFloatImm20(insn);
|
||||||
break;
|
break;
|
||||||
case FloatFormat::F64:
|
case FloatConversionFormat::F64:
|
||||||
src_a = GetDoubleImm20(insn);
|
src_a = GetDoubleImm20(insn);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
+5
-2
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -7,7 +10,7 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class Mode : u64 {
|
enum class FPReduceMode : u64 {
|
||||||
SINCOS,
|
SINCOS,
|
||||||
EX2,
|
EX2,
|
||||||
};
|
};
|
||||||
@@ -16,7 +19,7 @@ void RRO(TranslatorVisitor& v, u64 insn, const IR::F32& src) {
|
|||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<39, 1, Mode> mode;
|
BitField<39, 1, FPReduceMode> mode;
|
||||||
BitField<45, 1, u64> neg;
|
BitField<45, 1, u64> neg;
|
||||||
BitField<49, 1, u64> abs;
|
BitField<49, 1, u64> abs;
|
||||||
} const rro{insn};
|
} const rro{insn};
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -7,48 +10,48 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class Shift : u64 {
|
enum class IADD3Shift : u64 {
|
||||||
None,
|
None,
|
||||||
Right,
|
Right,
|
||||||
Left,
|
Left,
|
||||||
};
|
};
|
||||||
enum class Half : u64 {
|
enum class IADD3Half : u64 {
|
||||||
All,
|
All,
|
||||||
Lower,
|
Lower,
|
||||||
Upper,
|
Upper,
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] IR::U32 IntegerHalf(IR::IREmitter& ir, const IR::U32& value, Half half) {
|
[[nodiscard]] IR::U32 IntegerHalf(IR::IREmitter& ir, const IR::U32& value, IADD3Half half) {
|
||||||
constexpr bool is_signed{false};
|
constexpr bool is_signed{false};
|
||||||
switch (half) {
|
switch (half) {
|
||||||
case Half::All:
|
case IADD3Half::All:
|
||||||
return value;
|
return value;
|
||||||
case Half::Lower:
|
case IADD3Half::Lower:
|
||||||
return ir.BitFieldExtract(value, ir.Imm32(0), ir.Imm32(16), is_signed);
|
return ir.BitFieldExtract(value, ir.Imm32(0), ir.Imm32(16), is_signed);
|
||||||
case Half::Upper:
|
case IADD3Half::Upper:
|
||||||
return ir.BitFieldExtract(value, ir.Imm32(16), ir.Imm32(16), is_signed);
|
return ir.BitFieldExtract(value, ir.Imm32(16), ir.Imm32(16), is_signed);
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid half");
|
throw NotImplementedException("Invalid half");
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] IR::U32 IntegerShift(IR::IREmitter& ir, const IR::U32& value, Shift shift) {
|
[[nodiscard]] IR::U32 IntegerShift(IR::IREmitter& ir, const IR::U32& value, IADD3Shift shift) {
|
||||||
switch (shift) {
|
switch (shift) {
|
||||||
case Shift::None:
|
case IADD3Shift::None:
|
||||||
return value;
|
return value;
|
||||||
case Shift::Right: {
|
case IADD3Shift::Right: {
|
||||||
// 33-bit RS IADD3 edge case
|
// 33-bit RS IADD3 edge case
|
||||||
const IR::U1 edge_case{ir.GetCarryFromOp(value)};
|
const IR::U1 edge_case{ir.GetCarryFromOp(value)};
|
||||||
const IR::U32 shifted{ir.ShiftRightLogical(value, ir.Imm32(16))};
|
const IR::U32 shifted{ir.ShiftRightLogical(value, ir.Imm32(16))};
|
||||||
return IR::U32{ir.Select(edge_case, ir.IAdd(shifted, ir.Imm32(0x10000)), shifted)};
|
return IR::U32{ir.Select(edge_case, ir.IAdd(shifted, ir.Imm32(0x10000)), shifted)};
|
||||||
}
|
}
|
||||||
case Shift::Left:
|
case IADD3Shift::Left:
|
||||||
return ir.ShiftLeftLogical(value, ir.Imm32(16));
|
return ir.ShiftLeftLogical(value, ir.Imm32(16));
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid shift");
|
throw NotImplementedException("Invalid shift");
|
||||||
}
|
}
|
||||||
|
|
||||||
void IADD3(TranslatorVisitor& v, u64 insn, IR::U32 op_a, IR::U32 op_b, IR::U32 op_c,
|
void IADD3(TranslatorVisitor& v, u64 insn, IR::U32 op_a, IR::U32 op_b, IR::U32 op_c,
|
||||||
Shift shift = Shift::None) {
|
IADD3Shift shift = IADD3Shift::None) {
|
||||||
union {
|
union {
|
||||||
u64 insn;
|
u64 insn;
|
||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
@@ -71,7 +74,7 @@ void IADD3(TranslatorVisitor& v, u64 insn, IR::U32 op_a, IR::U32 op_b, IR::U32 o
|
|||||||
IR::U32 lhs_1{v.ir.IAdd(op_a, op_b)};
|
IR::U32 lhs_1{v.ir.IAdd(op_a, op_b)};
|
||||||
if (iadd3.x != 0) {
|
if (iadd3.x != 0) {
|
||||||
// TODO: How does RS behave when X is set?
|
// TODO: How does RS behave when X is set?
|
||||||
if (shift == Shift::Right) {
|
if (shift == IADD3Shift::Right) {
|
||||||
throw NotImplementedException("IADD3 X+RS");
|
throw NotImplementedException("IADD3 X+RS");
|
||||||
}
|
}
|
||||||
const IR::U32 carry{v.ir.Select(v.ir.GetCFlag(), v.ir.Imm32(1), v.ir.Imm32(0))};
|
const IR::U32 carry{v.ir.Select(v.ir.GetCFlag(), v.ir.Imm32(1), v.ir.Imm32(0))};
|
||||||
@@ -98,10 +101,10 @@ void IADD3(TranslatorVisitor& v, u64 insn, IR::U32 op_a, IR::U32 op_b, IR::U32 o
|
|||||||
void TranslatorVisitor::IADD3_reg(u64 insn) {
|
void TranslatorVisitor::IADD3_reg(u64 insn) {
|
||||||
union {
|
union {
|
||||||
u64 insn;
|
u64 insn;
|
||||||
BitField<37, 2, Shift> shift;
|
BitField<37, 2, IADD3Shift> shift;
|
||||||
BitField<35, 2, Half> half_a;
|
BitField<35, 2, IADD3Half> half_a;
|
||||||
BitField<33, 2, Half> half_b;
|
BitField<33, 2, IADD3Half> half_b;
|
||||||
BitField<31, 2, Half> half_c;
|
BitField<31, 2, IADD3Half> half_c;
|
||||||
} const iadd3{insn};
|
} const iadd3{insn};
|
||||||
|
|
||||||
const auto op_a{IntegerHalf(ir, GetReg8(insn), iadd3.half_a)};
|
const auto op_a{IntegerHalf(ir, GetReg8(insn), iadd3.half_a)};
|
||||||
|
|||||||
+13
-13
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class FloatFormat : u64 {
|
enum class IntegerToFloatFormat : u64 {
|
||||||
F16 = 1,
|
F16 = 1,
|
||||||
F32 = 2,
|
F32 = 2,
|
||||||
F64 = 3,
|
F64 = 3,
|
||||||
@@ -24,10 +24,10 @@ enum class IntFormat : u64 {
|
|||||||
U64 = 3,
|
U64 = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
union Encoding {
|
union EncodingIFPC {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<8, 2, FloatFormat> float_format;
|
BitField<8, 2, IntegerToFloatFormat> float_format;
|
||||||
BitField<10, 2, IntFormat> int_format;
|
BitField<10, 2, IntFormat> int_format;
|
||||||
BitField<13, 1, u64> is_signed;
|
BitField<13, 1, u64> is_signed;
|
||||||
BitField<39, 2, FpRounding> fp_rounding;
|
BitField<39, 2, FpRounding> fp_rounding;
|
||||||
@@ -38,16 +38,16 @@ union Encoding {
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool Is64(u64 insn) {
|
bool Is64(u64 insn) {
|
||||||
return Encoding{insn}.int_format == IntFormat::U64;
|
return EncodingIFPC{insn}.int_format == IntFormat::U64;
|
||||||
}
|
}
|
||||||
|
|
||||||
int BitSize(FloatFormat format) {
|
int BitSize(IntegerToFloatFormat format) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case FloatFormat::F16:
|
case IntegerToFloatFormat::F16:
|
||||||
return 16;
|
return 16;
|
||||||
case FloatFormat::F32:
|
case IntegerToFloatFormat::F32:
|
||||||
return 32;
|
return 32;
|
||||||
case FloatFormat::F64:
|
case IntegerToFloatFormat::F64:
|
||||||
return 64;
|
return 64;
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid float format {}", format);
|
throw NotImplementedException("Invalid float format {}", format);
|
||||||
@@ -62,7 +62,7 @@ IR::U32 SmallAbs(TranslatorVisitor& v, const IR::U32& value, int bitsize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void I2F(TranslatorVisitor& v, u64 insn, IR::U32U64 src) {
|
void I2F(TranslatorVisitor& v, u64 insn, IR::U32U64 src) {
|
||||||
const Encoding i2f{insn};
|
const EncodingIFPC i2f{insn};
|
||||||
if (i2f.cc != 0) {
|
if (i2f.cc != 0) {
|
||||||
throw NotImplementedException("I2F CC");
|
throw NotImplementedException("I2F CC");
|
||||||
}
|
}
|
||||||
@@ -119,15 +119,15 @@ void I2F(TranslatorVisitor& v, u64 insn, IR::U32U64 src) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (i2f.float_format) {
|
switch (i2f.float_format) {
|
||||||
case FloatFormat::F16: {
|
case IntegerToFloatFormat::F16: {
|
||||||
const IR::F16 zero{v.ir.FPConvert(16, v.ir.Imm32(0.0f))};
|
const IR::F16 zero{v.ir.FPConvert(16, v.ir.Imm32(0.0f))};
|
||||||
v.X(i2f.dest_reg, v.ir.PackFloat2x16(v.ir.CompositeConstruct(value, zero)));
|
v.X(i2f.dest_reg, v.ir.PackFloat2x16(v.ir.CompositeConstruct(value, zero)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FloatFormat::F32:
|
case IntegerToFloatFormat::F32:
|
||||||
v.F(i2f.dest_reg, value);
|
v.F(i2f.dest_reg, value);
|
||||||
break;
|
break;
|
||||||
case FloatFormat::F64: {
|
case IntegerToFloatFormat::F64: {
|
||||||
if (!IR::IsAligned(i2f.dest_reg, 2)) {
|
if (!IR::IsAligned(i2f.dest_reg, 2)) {
|
||||||
throw NotImplementedException("Unaligned destination {}", i2f.dest_reg.Value());
|
throw NotImplementedException("Unaligned destination {}", i2f.dest_reg.Value());
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-12
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -15,18 +18,18 @@ enum class SelectMode : u64 {
|
|||||||
CBCC,
|
CBCC,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Half : u64 {
|
enum class IMADHalf : u64 {
|
||||||
H0, // Least-significant bits (15:0)
|
H0, // Least-significant bits (15:0)
|
||||||
H1, // Most-significant bits (31:16)
|
H1, // Most-significant bits (31:16)
|
||||||
};
|
};
|
||||||
|
|
||||||
IR::U32 ExtractHalf(TranslatorVisitor& v, const IR::U32& src, Half half, bool is_signed) {
|
IR::U32 ExtractHalf(TranslatorVisitor& v, const IR::U32& src, IMADHalf half, bool is_signed) {
|
||||||
const IR::U32 offset{v.ir.Imm32(half == Half::H1 ? 16 : 0)};
|
const IR::U32 offset{v.ir.Imm32(half == IMADHalf::H1 ? 16 : 0)};
|
||||||
return v.ir.BitFieldExtract(src, offset, v.ir.Imm32(16), is_signed);
|
return v.ir.BitFieldExtract(src, offset, v.ir.Imm32(16), is_signed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XMAD(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, const IR::U32& src_c,
|
void XMAD(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, const IR::U32& src_c,
|
||||||
SelectMode select_mode, Half half_b, bool psl, bool mrg, bool x) {
|
SelectMode select_mode, IMADHalf half_b, bool psl, bool mrg, bool x) {
|
||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
@@ -34,7 +37,7 @@ void XMAD(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, const IR::U32& s
|
|||||||
BitField<47, 1, u64> cc;
|
BitField<47, 1, u64> cc;
|
||||||
BitField<48, 1, u64> is_a_signed;
|
BitField<48, 1, u64> is_a_signed;
|
||||||
BitField<49, 1, u64> is_b_signed;
|
BitField<49, 1, u64> is_b_signed;
|
||||||
BitField<53, 1, Half> half_a;
|
BitField<53, 1, IMADHalf> half_a;
|
||||||
} const xmad{insn};
|
} const xmad{insn};
|
||||||
|
|
||||||
if (x) {
|
if (x) {
|
||||||
@@ -53,9 +56,9 @@ void XMAD(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, const IR::U32& s
|
|||||||
case SelectMode::Default:
|
case SelectMode::Default:
|
||||||
return src_c;
|
return src_c;
|
||||||
case SelectMode::CLO:
|
case SelectMode::CLO:
|
||||||
return ExtractHalf(v, src_c, Half::H0, false);
|
return ExtractHalf(v, src_c, IMADHalf::H0, false);
|
||||||
case SelectMode::CHI:
|
case SelectMode::CHI:
|
||||||
return ExtractHalf(v, src_c, Half::H1, false);
|
return ExtractHalf(v, src_c, IMADHalf::H1, false);
|
||||||
case SelectMode::CBCC:
|
case SelectMode::CBCC:
|
||||||
return v.ir.IAdd(v.ir.ShiftLeftLogical(src_b, v.ir.Imm32(16)), src_c);
|
return v.ir.IAdd(v.ir.ShiftLeftLogical(src_b, v.ir.Imm32(16)), src_c);
|
||||||
case SelectMode::CSFU:
|
case SelectMode::CSFU:
|
||||||
@@ -66,7 +69,7 @@ void XMAD(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, const IR::U32& s
|
|||||||
IR::U32 result{v.ir.IAdd(product, op_c)};
|
IR::U32 result{v.ir.IAdd(product, op_c)};
|
||||||
if (mrg) {
|
if (mrg) {
|
||||||
// .MRG inserts src_b [15:0] into result's [31:16].
|
// .MRG inserts src_b [15:0] into result's [31:16].
|
||||||
const IR::U32 lsb_b{ExtractHalf(v, src_b, Half::H0, false)};
|
const IR::U32 lsb_b{ExtractHalf(v, src_b, IMADHalf::H0, false)};
|
||||||
result = v.ir.BitFieldInsert(result, lsb_b, v.ir.Imm32(16), v.ir.Imm32(16));
|
result = v.ir.BitFieldInsert(result, lsb_b, v.ir.Imm32(16), v.ir.Imm32(16));
|
||||||
}
|
}
|
||||||
if (xmad.cc) {
|
if (xmad.cc) {
|
||||||
@@ -80,7 +83,7 @@ void XMAD(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, const IR::U32& s
|
|||||||
void TranslatorVisitor::XMAD_reg(u64 insn) {
|
void TranslatorVisitor::XMAD_reg(u64 insn) {
|
||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<35, 1, Half> half_b;
|
BitField<35, 1, IMADHalf> half_b;
|
||||||
BitField<36, 1, u64> psl;
|
BitField<36, 1, u64> psl;
|
||||||
BitField<37, 1, u64> mrg;
|
BitField<37, 1, u64> mrg;
|
||||||
BitField<38, 1, u64> x;
|
BitField<38, 1, u64> x;
|
||||||
@@ -95,7 +98,7 @@ void TranslatorVisitor::XMAD_rc(u64 insn) {
|
|||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<50, 2, SelectMode> select_mode;
|
BitField<50, 2, SelectMode> select_mode;
|
||||||
BitField<52, 1, Half> half_b;
|
BitField<52, 1, IMADHalf> half_b;
|
||||||
BitField<54, 1, u64> x;
|
BitField<54, 1, u64> x;
|
||||||
} const xmad{insn};
|
} const xmad{insn};
|
||||||
|
|
||||||
@@ -107,7 +110,7 @@ void TranslatorVisitor::XMAD_cr(u64 insn) {
|
|||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<50, 2, SelectMode> select_mode;
|
BitField<50, 2, SelectMode> select_mode;
|
||||||
BitField<52, 1, Half> half_b;
|
BitField<52, 1, IMADHalf> half_b;
|
||||||
BitField<54, 1, u64> x;
|
BitField<54, 1, u64> x;
|
||||||
BitField<55, 1, u64> psl;
|
BitField<55, 1, u64> psl;
|
||||||
BitField<56, 1, u64> mrg;
|
BitField<56, 1, u64> mrg;
|
||||||
@@ -128,7 +131,7 @@ void TranslatorVisitor::XMAD_imm(u64 insn) {
|
|||||||
} const xmad{insn};
|
} const xmad{insn};
|
||||||
|
|
||||||
XMAD(*this, insn, ir.Imm32(static_cast<u32>(xmad.src_b)), GetReg39(insn), xmad.select_mode,
|
XMAD(*this, insn, ir.Imm32(static_cast<u32>(xmad.src_b)), GetReg39(insn), xmad.select_mode,
|
||||||
Half::H0, xmad.psl != 0, xmad.mrg != 0, xmad.x != 0);
|
IMADHalf::H0, xmad.psl != 0, xmad.mrg != 0, xmad.x != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Shader::Maxwell
|
} // namespace Shader::Maxwell
|
||||||
|
|||||||
+13
-13
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class Mode : u64 {
|
enum class ISBERDMode : u64 {
|
||||||
Default,
|
Default,
|
||||||
Patch,
|
Patch,
|
||||||
Prim,
|
Prim,
|
||||||
@@ -24,17 +24,17 @@ enum class SZ : u64 {
|
|||||||
F32
|
F32
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Shift : u64 {
|
enum class ISBERDShift : u64 {
|
||||||
Default,
|
Default,
|
||||||
U16,
|
U16,
|
||||||
B32,
|
B32,
|
||||||
};
|
};
|
||||||
|
|
||||||
IR::U32 scaleIndex(IR::IREmitter& ir, IR::U32 index, Shift shift) {
|
IR::U32 scaleIndex(IR::IREmitter& ir, IR::U32 index, ISBERDShift shift) {
|
||||||
switch (shift) {
|
switch (shift) {
|
||||||
case Shift::Default: return index;
|
case ISBERDShift::Default: return index;
|
||||||
case Shift::U16: return ir.ShiftLeftLogical(index, ir.Imm32(1));
|
case ISBERDShift::U16: return ir.ShiftLeftLogical(index, ir.Imm32(1));
|
||||||
case Shift::B32: return ir.ShiftLeftLogical(index, ir.Imm32(2));
|
case ISBERDShift::B32: return ir.ShiftLeftLogical(index, ir.Imm32(2));
|
||||||
default: UNREACHABLE();
|
default: UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,9 +63,9 @@ void TranslatorVisitor::ISBERD(u64 insn) {
|
|||||||
BitField<24, 8, u32> imm;
|
BitField<24, 8, u32> imm;
|
||||||
BitField<31, 1, u64> skew;
|
BitField<31, 1, u64> skew;
|
||||||
BitField<32, 1, u64> o;
|
BitField<32, 1, u64> o;
|
||||||
BitField<33, 2, Mode> mode;
|
BitField<33, 2, ISBERDMode> mode;
|
||||||
BitField<36, 4, SZ> sz;
|
BitField<36, 4, SZ> sz;
|
||||||
BitField<47, 2, Shift> shift;
|
BitField<47, 2, ISBERDShift> shift;
|
||||||
} const isberd{insn};
|
} const isberd{insn};
|
||||||
|
|
||||||
IR::U32 index{};
|
IR::U32 index{};
|
||||||
@@ -95,18 +95,18 @@ void TranslatorVisitor::ISBERD(u64 insn) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isberd.mode.Value() != Mode::Default) {
|
if (isberd.mode.Value() != ISBERDMode::Default) {
|
||||||
if (isberd.skew.Value()) {
|
if (isberd.skew.Value()) {
|
||||||
index = ir.IAdd(index, skewBytes(ir, SZ::U32));
|
index = ir.IAdd(index, skewBytes(ir, SZ::U32));
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::F32 float_index{};
|
IR::F32 float_index{};
|
||||||
switch (isberd.mode.Value()) {
|
switch (isberd.mode.Value()) {
|
||||||
case Mode::Patch: float_index = ir.GetPatch(index.Patch());
|
case ISBERDMode::Patch: float_index = ir.GetPatch(index.Patch());
|
||||||
break;
|
break;
|
||||||
case Mode::Prim: float_index = ir.GetAttribute(index.Attribute());
|
case ISBERDMode::Prim: float_index = ir.GetAttribute(index.Attribute());
|
||||||
break;
|
break;
|
||||||
case Mode::Attr: float_index = ir.GetAttributeIndexed(index);
|
case ISBERDMode::Attr: float_index = ir.GetAttributeIndexed(index);
|
||||||
break;
|
break;
|
||||||
default: UNREACHABLE();
|
default: UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class Size : u64 {
|
enum class InterpolationSize : u64 {
|
||||||
B32,
|
B32,
|
||||||
B64,
|
B64,
|
||||||
B96,
|
B96,
|
||||||
@@ -32,15 +32,15 @@ enum class SampleMode : u64 {
|
|||||||
Offset,
|
Offset,
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 NumElements(Size size) {
|
u32 NumElements(InterpolationSize size) {
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case Size::B32:
|
case InterpolationSize::B32:
|
||||||
return 1;
|
return 1;
|
||||||
case Size::B64:
|
case InterpolationSize::B64:
|
||||||
return 2;
|
return 2;
|
||||||
case Size::B96:
|
case InterpolationSize::B96:
|
||||||
return 3;
|
return 3;
|
||||||
case Size::B128:
|
case InterpolationSize::B128:
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
throw InvalidArgument("Invalid size {}", size);
|
throw InvalidArgument("Invalid size {}", size);
|
||||||
@@ -68,7 +68,7 @@ void TranslatorVisitor::ALD(u64 insn) {
|
|||||||
BitField<39, 8, IR::Reg> vertex_reg;
|
BitField<39, 8, IR::Reg> vertex_reg;
|
||||||
BitField<32, 1, u64> o;
|
BitField<32, 1, u64> o;
|
||||||
BitField<31, 1, u64> patch;
|
BitField<31, 1, u64> patch;
|
||||||
BitField<47, 2, Size> size;
|
BitField<47, 2, InterpolationSize> size;
|
||||||
} const ald{insn};
|
} const ald{insn};
|
||||||
|
|
||||||
const u64 offset{ald.absolute_offset.Value()};
|
const u64 offset{ald.absolute_offset.Value()};
|
||||||
@@ -106,7 +106,7 @@ void TranslatorVisitor::AST(u64 insn) {
|
|||||||
BitField<20, 11, s64> relative_offset;
|
BitField<20, 11, s64> relative_offset;
|
||||||
BitField<31, 1, u64> patch;
|
BitField<31, 1, u64> patch;
|
||||||
BitField<39, 8, IR::Reg> vertex_reg;
|
BitField<39, 8, IR::Reg> vertex_reg;
|
||||||
BitField<47, 2, Size> size;
|
BitField<47, 2, InterpolationSize> size;
|
||||||
} const ast{insn};
|
} const ast{insn};
|
||||||
|
|
||||||
if (ast.index_reg != IR::Reg::RZ) {
|
if (ast.index_reg != IR::Reg::RZ) {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -7,7 +10,7 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class Size : u64 {
|
enum class LoadStoreLocalSharedSize : u64 {
|
||||||
U8,
|
U8,
|
||||||
S8,
|
S8,
|
||||||
U16,
|
U16,
|
||||||
@@ -45,23 +48,23 @@ std::pair<IR::U32, IR::U32> WordOffset(TranslatorVisitor& v, u64 insn) {
|
|||||||
std::pair<int, bool> GetSize(u64 insn) {
|
std::pair<int, bool> GetSize(u64 insn) {
|
||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<48, 3, Size> size;
|
BitField<48, 3, LoadStoreLocalSharedSize> size;
|
||||||
} const encoding{insn};
|
} const encoding{insn};
|
||||||
|
|
||||||
switch (encoding.size) {
|
switch (encoding.size) {
|
||||||
case Size::U8:
|
case LoadStoreLocalSharedSize::U8:
|
||||||
return {8, false};
|
return {8, false};
|
||||||
case Size::S8:
|
case LoadStoreLocalSharedSize::S8:
|
||||||
return {8, true};
|
return {8, true};
|
||||||
case Size::U16:
|
case LoadStoreLocalSharedSize::U16:
|
||||||
return {16, false};
|
return {16, false};
|
||||||
case Size::S16:
|
case LoadStoreLocalSharedSize::S16:
|
||||||
return {16, true};
|
return {16, true};
|
||||||
case Size::B32:
|
case LoadStoreLocalSharedSize::B32:
|
||||||
return {32, false};
|
return {32, false};
|
||||||
case Size::B64:
|
case LoadStoreLocalSharedSize::B64:
|
||||||
return {64, false};
|
return {64, false};
|
||||||
case Size::B128:
|
case LoadStoreLocalSharedSize::B128:
|
||||||
return {128, false};
|
return {128, false};
|
||||||
default:
|
default:
|
||||||
throw NotImplementedException("Invalid size {}", encoding.size.Value());
|
throw NotImplementedException("Invalid size {}", encoding.size.Value());
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -30,7 +33,7 @@ enum class StoreSize : u64 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// See Table 27 in https://docs.nvidia.com/cuda/parallel-thread-execution/index.html
|
// See Table 27 in https://docs.nvidia.com/cuda/parallel-thread-execution/index.html
|
||||||
enum class LoadCache : u64 {
|
enum class XMEMLoadCache : u64 {
|
||||||
CA, // Cache at all levels, likely to be accessed again
|
CA, // Cache at all levels, likely to be accessed again
|
||||||
CG, // Cache at global level (cache in L2 and below, not L1)
|
CG, // Cache at global level (cache in L2 and below, not L1)
|
||||||
CI, // ???
|
CI, // ???
|
||||||
@@ -38,7 +41,7 @@ enum class LoadCache : u64 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// See Table 28 in https://docs.nvidia.com/cuda/parallel-thread-execution/index.html
|
// See Table 28 in https://docs.nvidia.com/cuda/parallel-thread-execution/index.html
|
||||||
enum class StoreCache : u64 {
|
enum class XMEMStoreCache : u64 {
|
||||||
WB, // Cache write-back all coherent levels
|
WB, // Cache write-back all coherent levels
|
||||||
CG, // Cache at global level
|
CG, // Cache at global level
|
||||||
CS, // Cache streaming, likely to be accessed once
|
CS, // Cache streaming, likely to be accessed once
|
||||||
@@ -83,7 +86,7 @@ void TranslatorVisitor::LDG(u64 insn) {
|
|||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<46, 2, LoadCache> cache;
|
BitField<46, 2, XMEMLoadCache> cache;
|
||||||
BitField<48, 3, LoadSize> size;
|
BitField<48, 3, LoadSize> size;
|
||||||
} const ldg{insn};
|
} const ldg{insn};
|
||||||
|
|
||||||
@@ -137,7 +140,7 @@ void TranslatorVisitor::STG(u64 insn) {
|
|||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<0, 8, IR::Reg> data_reg;
|
BitField<0, 8, IR::Reg> data_reg;
|
||||||
BitField<46, 2, StoreCache> cache;
|
BitField<46, 2, XMEMStoreCache> cache;
|
||||||
BitField<48, 3, StoreSize> size;
|
BitField<48, 3, StoreSize> size;
|
||||||
} const stg{insn};
|
} const stg{insn};
|
||||||
|
|
||||||
|
|||||||
+6
-3
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -7,7 +10,7 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class Mode : u64 {
|
enum class MovePredicateFlagMode : u64 {
|
||||||
PR,
|
PR,
|
||||||
CC,
|
CC,
|
||||||
};
|
};
|
||||||
@@ -26,12 +29,12 @@ void TranslatorVisitor::P2R_imm(u64 insn) {
|
|||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<8, 8, IR::Reg> src;
|
BitField<8, 8, IR::Reg> src;
|
||||||
BitField<40, 1, Mode> mode;
|
BitField<40, 1, MovePredicateFlagMode> mode;
|
||||||
BitField<41, 2, u64> byte_selector;
|
BitField<41, 2, u64> byte_selector;
|
||||||
} const p2r{insn};
|
} const p2r{insn};
|
||||||
|
|
||||||
const u32 mask{GetImm20(insn).U32()};
|
const u32 mask{GetImm20(insn).U32()};
|
||||||
const bool pr_mode{p2r.mode == Mode::PR};
|
const bool pr_mode{p2r.mode == MovePredicateFlagMode::PR};
|
||||||
const u32 num_items{pr_mode ? 7U : 4U};
|
const u32 num_items{pr_mode ? 7U : 4U};
|
||||||
const u32 offset{static_cast<u32>(p2r.byte_selector) * 8};
|
const u32 offset{static_cast<u32>(p2r.byte_selector) * 8};
|
||||||
IR::U32 insert{ir.Imm32(0)};
|
IR::U32 insert{ir.Imm32(0)};
|
||||||
|
|||||||
+6
-3
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -7,7 +10,7 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class Mode : u64 {
|
enum class PredicateFlagMode : u64 {
|
||||||
PR,
|
PR,
|
||||||
CC,
|
CC,
|
||||||
};
|
};
|
||||||
@@ -31,12 +34,12 @@ void R2P(TranslatorVisitor& v, u64 insn, const IR::U32& mask) {
|
|||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<8, 8, IR::Reg> src_reg;
|
BitField<8, 8, IR::Reg> src_reg;
|
||||||
BitField<40, 1, Mode> mode;
|
BitField<40, 1, PredicateFlagMode> mode;
|
||||||
BitField<41, 2, u64> byte_selector;
|
BitField<41, 2, u64> byte_selector;
|
||||||
} const r2p{insn};
|
} const r2p{insn};
|
||||||
const IR::U32 src{v.X(r2p.src_reg)};
|
const IR::U32 src{v.X(r2p.src_reg)};
|
||||||
const IR::U32 count{v.ir.Imm32(1)};
|
const IR::U32 count{v.ir.Imm32(1)};
|
||||||
const bool pr_mode{r2p.mode == Mode::PR};
|
const bool pr_mode{r2p.mode == PredicateFlagMode::PR};
|
||||||
const u32 num_items{pr_mode ? 7U : 4U};
|
const u32 num_items{pr_mode ? 7U : 4U};
|
||||||
const u32 offset_base{static_cast<u32>(r2p.byte_selector) * 8};
|
const u32 offset_base{static_cast<u32>(r2p.byte_selector) * 8};
|
||||||
for (u32 index = 0; index < num_items; ++index) {
|
for (u32 index = 0; index < num_items; ++index) {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -7,7 +10,7 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class Mode : u64 {
|
enum class PixelLoadMode : u64 {
|
||||||
Default,
|
Default,
|
||||||
CovMask,
|
CovMask,
|
||||||
Covered,
|
Covered,
|
||||||
@@ -20,7 +23,7 @@ enum class Mode : u64 {
|
|||||||
void TranslatorVisitor::PIXLD(u64 insn) {
|
void TranslatorVisitor::PIXLD(u64 insn) {
|
||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<31, 3, Mode> mode;
|
BitField<31, 3, PixelLoadMode> mode;
|
||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<8, 8, IR::Reg> addr_reg;
|
BitField<8, 8, IR::Reg> addr_reg;
|
||||||
BitField<20, 8, s64> addr_offset;
|
BitField<20, 8, s64> addr_offset;
|
||||||
@@ -34,11 +37,11 @@ void TranslatorVisitor::PIXLD(u64 insn) {
|
|||||||
throw NotImplementedException("Non-zero source register");
|
throw NotImplementedException("Non-zero source register");
|
||||||
}
|
}
|
||||||
switch (pixld.mode) {
|
switch (pixld.mode) {
|
||||||
case Mode::MyIndex:
|
case PixelLoadMode::MyIndex:
|
||||||
X(pixld.dest_reg, ir.SampleId());
|
X(pixld.dest_reg, ir.SampleId());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw NotImplementedException("Mode {}", pixld.mode.Value());
|
throw NotImplementedException("PixelLoadMode {}", pixld.mode.Value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+37
-37
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class Type : u64 {
|
enum class SurfaceAtomicType : u64 {
|
||||||
_1D = 0,
|
_1D = 0,
|
||||||
_1D_BUFFER = 1,
|
_1D_BUFFER = 1,
|
||||||
_1D_ARRAY = 2,
|
_1D_ARRAY = 2,
|
||||||
@@ -25,7 +25,7 @@ enum class Type : u64 {
|
|||||||
/// For any would be newcomer to here: Yes - GPU dissasembly says S64 should
|
/// For any would be newcomer to here: Yes - GPU dissasembly says S64 should
|
||||||
/// be after F16x2FTZRN. However if you do plan to revert this, you MUST test
|
/// be after F16x2FTZRN. However if you do plan to revert this, you MUST test
|
||||||
/// ToTK beforehand. As the game will break with the subtle change
|
/// ToTK beforehand. As the game will break with the subtle change
|
||||||
enum class Size : u64 {
|
enum class SurfaceAtomicSize : u64 {
|
||||||
U32,
|
U32,
|
||||||
S32,
|
S32,
|
||||||
U64,
|
U64,
|
||||||
@@ -48,46 +48,46 @@ enum class AtomicOp : u64 {
|
|||||||
EXCH,
|
EXCH,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Clamp : u64 {
|
enum class SurfaceAtomicClamp : u64 {
|
||||||
IGN,
|
IGN,
|
||||||
Default,
|
Default,
|
||||||
TRAP,
|
TRAP,
|
||||||
};
|
};
|
||||||
|
|
||||||
TextureType GetType(Type type) {
|
TextureType GetType(SurfaceAtomicType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Type::_1D:
|
case SurfaceAtomicType::_1D:
|
||||||
return TextureType::Color1D;
|
return TextureType::Color1D;
|
||||||
case Type::_1D_BUFFER:
|
case SurfaceAtomicType::_1D_BUFFER:
|
||||||
return TextureType::Buffer;
|
return TextureType::Buffer;
|
||||||
case Type::_1D_ARRAY:
|
case SurfaceAtomicType::_1D_ARRAY:
|
||||||
return TextureType::ColorArray1D;
|
return TextureType::ColorArray1D;
|
||||||
case Type::_2D:
|
case SurfaceAtomicType::_2D:
|
||||||
return TextureType::Color2D;
|
return TextureType::Color2D;
|
||||||
case Type::_2D_ARRAY:
|
case SurfaceAtomicType::_2D_ARRAY:
|
||||||
return TextureType::ColorArray2D;
|
return TextureType::ColorArray2D;
|
||||||
case Type::_3D:
|
case SurfaceAtomicType::_3D:
|
||||||
return TextureType::Color3D;
|
return TextureType::Color3D;
|
||||||
default:
|
default:
|
||||||
throw NotImplementedException("Invalid type {}", type);
|
throw NotImplementedException("Invalid type {}", type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, Type type) {
|
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, SurfaceAtomicType type) {
|
||||||
const auto array{[&](int index) {
|
const auto array{[&](int index) {
|
||||||
return v.ir.BitFieldExtract(v.X(reg + index), v.ir.Imm32(0), v.ir.Imm32(16));
|
return v.ir.BitFieldExtract(v.X(reg + index), v.ir.Imm32(0), v.ir.Imm32(16));
|
||||||
}};
|
}};
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Type::_1D:
|
case SurfaceAtomicType::_1D:
|
||||||
case Type::_1D_BUFFER:
|
case SurfaceAtomicType::_1D_BUFFER:
|
||||||
return v.X(reg);
|
return v.X(reg);
|
||||||
case Type::_1D_ARRAY:
|
case SurfaceAtomicType::_1D_ARRAY:
|
||||||
return v.ir.CompositeConstruct(v.X(reg), array(1));
|
return v.ir.CompositeConstruct(v.X(reg), array(1));
|
||||||
case Type::_2D:
|
case SurfaceAtomicType::_2D:
|
||||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1));
|
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1));
|
||||||
case Type::_2D_ARRAY:
|
case SurfaceAtomicType::_2D_ARRAY:
|
||||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), array(2));
|
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), array(2));
|
||||||
case Type::_3D:
|
case SurfaceAtomicType::_3D:
|
||||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), v.X(reg + 2));
|
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), v.X(reg + 2));
|
||||||
default:
|
default:
|
||||||
throw NotImplementedException("Invalid type {}", type);
|
throw NotImplementedException("Invalid type {}", type);
|
||||||
@@ -121,11 +121,11 @@ IR::Value ApplyAtomicOp(IR::IREmitter& ir, const IR::U32& handle, const IR::Valu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageFormat Format(Size size) {
|
ImageFormat Format(SurfaceAtomicSize size) {
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case Size::U32:
|
case SurfaceAtomicSize::U32:
|
||||||
case Size::S32:
|
case SurfaceAtomicSize::S32:
|
||||||
case Size::SD32:
|
case SurfaceAtomicSize::SD32:
|
||||||
return ImageFormat::R32_UINT;
|
return ImageFormat::R32_UINT;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -133,11 +133,11 @@ ImageFormat Format(Size size) {
|
|||||||
throw NotImplementedException("Invalid size {}", size);
|
throw NotImplementedException("Invalid size {}", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsSizeInt32(Size size) {
|
bool IsSizeInt32(SurfaceAtomicSize size) {
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case Size::U32:
|
case SurfaceAtomicSize::U32:
|
||||||
case Size::S32:
|
case SurfaceAtomicSize::S32:
|
||||||
case Size::SD32:
|
case SurfaceAtomicSize::SD32:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@@ -145,15 +145,15 @@ bool IsSizeInt32(Size size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ImageAtomOp(TranslatorVisitor& v, IR::Reg dest_reg, IR::Reg operand_reg, IR::Reg coord_reg,
|
void ImageAtomOp(TranslatorVisitor& v, IR::Reg dest_reg, IR::Reg operand_reg, IR::Reg coord_reg,
|
||||||
std::optional<IR::Reg> bindless_reg, AtomicOp op, Clamp clamp, Size size, Type type,
|
std::optional<IR::Reg> bindless_reg, AtomicOp op, SurfaceAtomicClamp clamp, SurfaceAtomicSize size, SurfaceAtomicType type,
|
||||||
u64 bound_offset, bool is_bindless, bool write_result) {
|
u64 bound_offset, bool is_bindless, bool write_result) {
|
||||||
if (clamp != Clamp::IGN) {
|
if (clamp != SurfaceAtomicClamp::IGN) {
|
||||||
throw NotImplementedException("Clamp {}", clamp);
|
throw NotImplementedException("SurfaceAtomicClamp {}", clamp);
|
||||||
}
|
}
|
||||||
if (!IsSizeInt32(size)) {
|
if (!IsSizeInt32(size)) {
|
||||||
throw NotImplementedException("Size {}", size);
|
throw NotImplementedException("SurfaceAtomicSize {}", size);
|
||||||
}
|
}
|
||||||
const bool is_signed{size == Size::S32};
|
const bool is_signed{size == SurfaceAtomicSize::S32};
|
||||||
const ImageFormat format{Format(size)};
|
const ImageFormat format{Format(size)};
|
||||||
const TextureType tex_type{GetType(type)};
|
const TextureType tex_type{GetType(type)};
|
||||||
const IR::Value coords{MakeCoords(v, coord_reg, type)};
|
const IR::Value coords{MakeCoords(v, coord_reg, type)};
|
||||||
@@ -178,9 +178,9 @@ void TranslatorVisitor::SUATOM(u64 insn) {
|
|||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<54, 1, u64> is_bindless;
|
BitField<54, 1, u64> is_bindless;
|
||||||
BitField<29, 4, AtomicOp> op;
|
BitField<29, 4, AtomicOp> op;
|
||||||
BitField<33, 3, Type> type;
|
BitField<33, 3, SurfaceAtomicType> type;
|
||||||
BitField<51, 3, Size> size;
|
BitField<51, 3, SurfaceAtomicSize> size;
|
||||||
BitField<49, 2, Clamp> clamp;
|
BitField<49, 2, SurfaceAtomicClamp> clamp;
|
||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<8, 8, IR::Reg> coord_reg;
|
BitField<8, 8, IR::Reg> coord_reg;
|
||||||
BitField<20, 8, IR::Reg> operand_reg;
|
BitField<20, 8, IR::Reg> operand_reg;
|
||||||
@@ -199,9 +199,9 @@ void TranslatorVisitor::SURED(u64 insn) {
|
|||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<51, 1, u64> is_bound;
|
BitField<51, 1, u64> is_bound;
|
||||||
BitField<24, 3, AtomicOp> op; //OK - 24 (SURedOp)
|
BitField<24, 3, AtomicOp> op; //OK - 24 (SURedOp)
|
||||||
BitField<33, 3, Type> type; //OK? - 33 (Dim)
|
BitField<33, 3, SurfaceAtomicType> type; //OK? - 33 (Dim)
|
||||||
BitField<20, 3, Size> size; //?
|
BitField<20, 3, SurfaceAtomicSize> size; //?
|
||||||
BitField<49, 2, Clamp> clamp; //OK - 49 (Clamp4)
|
BitField<49, 2, SurfaceAtomicClamp> clamp; //OK - 49 (Clamp4)
|
||||||
BitField<0, 8, IR::Reg> operand_reg; //RA?
|
BitField<0, 8, IR::Reg> operand_reg; //RA?
|
||||||
BitField<8, 8, IR::Reg> coord_reg; //RB?
|
BitField<8, 8, IR::Reg> coord_reg; //RB?
|
||||||
BitField<36, 13, u64> bound_offset; //OK 33 (TidB)
|
BitField<36, 13, u64> bound_offset; //OK 33 (TidB)
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -11,7 +14,7 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class Type : u64 {
|
enum class SurfaceLoadStoreType : u64 {
|
||||||
_1D,
|
_1D,
|
||||||
BUFFER_1D,
|
BUFFER_1D,
|
||||||
ARRAY_1D,
|
ARRAY_1D,
|
||||||
@@ -20,31 +23,31 @@ enum class Type : u64 {
|
|||||||
_3D,
|
_3D,
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr unsigned R = 1 << 0;
|
constexpr unsigned SHADER_R = 1 << 0;
|
||||||
constexpr unsigned G = 1 << 1;
|
constexpr unsigned SHADER_G = 1 << 1;
|
||||||
constexpr unsigned B = 1 << 2;
|
constexpr unsigned SHADER_B = 1 << 2;
|
||||||
constexpr unsigned A = 1 << 3;
|
constexpr unsigned SHADER_A = 1 << 3;
|
||||||
|
|
||||||
constexpr std::array MASK{
|
constexpr std::array MASK{
|
||||||
0U, //
|
0U, //
|
||||||
R, //
|
SHADER_R, //
|
||||||
G, //
|
SHADER_G, //
|
||||||
R | G, //
|
SHADER_R | SHADER_G, //
|
||||||
B, //
|
SHADER_B, //
|
||||||
R | B, //
|
SHADER_R | SHADER_B, //
|
||||||
G | B, //
|
SHADER_G | SHADER_B, //
|
||||||
R | G | B, //
|
SHADER_R | SHADER_G | SHADER_B, //
|
||||||
A, //
|
SHADER_A, //
|
||||||
R | A, //
|
SHADER_R | SHADER_A, //
|
||||||
G | A, //
|
SHADER_G | SHADER_A, //
|
||||||
R | G | A, //
|
SHADER_R | SHADER_G | SHADER_A, //
|
||||||
B | A, //
|
SHADER_B | SHADER_A, //
|
||||||
R | B | A, //
|
SHADER_R | SHADER_B | SHADER_A, //
|
||||||
G | B | A, //
|
SHADER_G | SHADER_B | SHADER_A, //
|
||||||
R | G | B | A, //
|
SHADER_R | SHADER_G | SHADER_B | SHADER_A, //
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Size : u64 {
|
enum class SurfaceLoadStoreSize : u64 {
|
||||||
U8,
|
U8,
|
||||||
S8,
|
S8,
|
||||||
U16,
|
U16,
|
||||||
@@ -54,96 +57,96 @@ enum class Size : u64 {
|
|||||||
B128,
|
B128,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Clamp : u64 {
|
enum class SurfaceLoadStoreClamp : u64 {
|
||||||
IGN,
|
IGN,
|
||||||
Default,
|
Default,
|
||||||
TRAP,
|
TRAP,
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#cache-operators
|
// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#cache-operators
|
||||||
enum class LoadCache : u64 {
|
enum class SURFLoadCache : u64 {
|
||||||
CA, // Cache at all levels, likely to be accessed again
|
CA, // Cache at all levels, likely to be accessed again
|
||||||
CG, // Cache at global level (L2 and below, not L1)
|
CG, // Cache at global level (L2 and below, not L1)
|
||||||
CI, // ???
|
CI, // ???
|
||||||
CV, // Don't cache and fetch again (volatile)
|
CV, // Don't cache and fetch again (volatile)
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class StoreCache : u64 {
|
enum class SURFStoreCache : u64 {
|
||||||
WB, // Cache write-back all coherent levels
|
WB, // Cache write-back all coherent levels
|
||||||
CG, // Cache at global level (L2 and below, not L1)
|
CG, // Cache at global level (L2 and below, not L1)
|
||||||
CS, // Cache streaming, likely to be accessed once
|
CS, // Cache streaming, likely to be accessed once
|
||||||
WT, // Cache write-through (to system memory, volatile?)
|
WT, // Cache write-through (to system memory, volatile?)
|
||||||
};
|
};
|
||||||
|
|
||||||
ImageFormat Format(Size size) {
|
ImageFormat Format(SurfaceLoadStoreSize size) {
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case Size::U8:
|
case SurfaceLoadStoreSize::U8:
|
||||||
return ImageFormat::R8_UINT;
|
return ImageFormat::R8_UINT;
|
||||||
case Size::S8:
|
case SurfaceLoadStoreSize::S8:
|
||||||
return ImageFormat::R8_SINT;
|
return ImageFormat::R8_SINT;
|
||||||
case Size::U16:
|
case SurfaceLoadStoreSize::U16:
|
||||||
return ImageFormat::R16_UINT;
|
return ImageFormat::R16_UINT;
|
||||||
case Size::S16:
|
case SurfaceLoadStoreSize::S16:
|
||||||
return ImageFormat::R16_SINT;
|
return ImageFormat::R16_SINT;
|
||||||
case Size::B32:
|
case SurfaceLoadStoreSize::B32:
|
||||||
return ImageFormat::R32_UINT;
|
return ImageFormat::R32_UINT;
|
||||||
case Size::B64:
|
case SurfaceLoadStoreSize::B64:
|
||||||
return ImageFormat::R32G32_UINT;
|
return ImageFormat::R32G32_UINT;
|
||||||
case Size::B128:
|
case SurfaceLoadStoreSize::B128:
|
||||||
return ImageFormat::R32G32B32A32_UINT;
|
return ImageFormat::R32G32B32A32_UINT;
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid size {}", size);
|
throw NotImplementedException("Invalid size {}", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SizeInRegs(Size size) {
|
int SizeInRegs(SurfaceLoadStoreSize size) {
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case Size::U8:
|
case SurfaceLoadStoreSize::U8:
|
||||||
case Size::S8:
|
case SurfaceLoadStoreSize::S8:
|
||||||
case Size::U16:
|
case SurfaceLoadStoreSize::U16:
|
||||||
case Size::S16:
|
case SurfaceLoadStoreSize::S16:
|
||||||
case Size::B32:
|
case SurfaceLoadStoreSize::B32:
|
||||||
return 1;
|
return 1;
|
||||||
case Size::B64:
|
case SurfaceLoadStoreSize::B64:
|
||||||
return 2;
|
return 2;
|
||||||
case Size::B128:
|
case SurfaceLoadStoreSize::B128:
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid size {}", size);
|
throw NotImplementedException("Invalid size {}", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureType GetType(Type type) {
|
TextureType GetType(SurfaceLoadStoreType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Type::_1D:
|
case SurfaceLoadStoreType::_1D:
|
||||||
return TextureType::Color1D;
|
return TextureType::Color1D;
|
||||||
case Type::BUFFER_1D:
|
case SurfaceLoadStoreType::BUFFER_1D:
|
||||||
return TextureType::Buffer;
|
return TextureType::Buffer;
|
||||||
case Type::ARRAY_1D:
|
case SurfaceLoadStoreType::ARRAY_1D:
|
||||||
return TextureType::ColorArray1D;
|
return TextureType::ColorArray1D;
|
||||||
case Type::_2D:
|
case SurfaceLoadStoreType::_2D:
|
||||||
return TextureType::Color2D;
|
return TextureType::Color2D;
|
||||||
case Type::ARRAY_2D:
|
case SurfaceLoadStoreType::ARRAY_2D:
|
||||||
return TextureType::ColorArray2D;
|
return TextureType::ColorArray2D;
|
||||||
case Type::_3D:
|
case SurfaceLoadStoreType::_3D:
|
||||||
return TextureType::Color3D;
|
return TextureType::Color3D;
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid type {}", type);
|
throw NotImplementedException("Invalid type {}", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, Type type) {
|
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, SurfaceLoadStoreType type) {
|
||||||
const auto array{[&](int index) {
|
const auto array{[&](int index) {
|
||||||
return v.ir.BitFieldExtract(v.X(reg + index), v.ir.Imm32(0), v.ir.Imm32(16));
|
return v.ir.BitFieldExtract(v.X(reg + index), v.ir.Imm32(0), v.ir.Imm32(16));
|
||||||
}};
|
}};
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Type::_1D:
|
case SurfaceLoadStoreType::_1D:
|
||||||
case Type::BUFFER_1D:
|
case SurfaceLoadStoreType::BUFFER_1D:
|
||||||
return v.X(reg);
|
return v.X(reg);
|
||||||
case Type::ARRAY_1D:
|
case SurfaceLoadStoreType::ARRAY_1D:
|
||||||
return v.ir.CompositeConstruct(v.X(reg), array(1));
|
return v.ir.CompositeConstruct(v.X(reg), array(1));
|
||||||
case Type::_2D:
|
case SurfaceLoadStoreType::_2D:
|
||||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1));
|
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1));
|
||||||
case Type::ARRAY_2D:
|
case SurfaceLoadStoreType::ARRAY_2D:
|
||||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), array(2));
|
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), array(2));
|
||||||
case Type::_3D:
|
case SurfaceLoadStoreType::_3D:
|
||||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), v.X(reg + 2));
|
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), v.X(reg + 2));
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid type {}", type);
|
throw NotImplementedException("Invalid type {}", type);
|
||||||
@@ -174,21 +177,21 @@ void TranslatorVisitor::SULD(u64 insn) {
|
|||||||
BitField<51, 1, u64> is_bound;
|
BitField<51, 1, u64> is_bound;
|
||||||
BitField<52, 1, u64> d;
|
BitField<52, 1, u64> d;
|
||||||
BitField<23, 1, u64> ba;
|
BitField<23, 1, u64> ba;
|
||||||
BitField<33, 3, Type> type;
|
BitField<33, 3, SurfaceLoadStoreType> type;
|
||||||
BitField<24, 2, LoadCache> cache;
|
BitField<24, 2, SURFLoadCache> cache;
|
||||||
BitField<20, 3, Size> size; // .D
|
BitField<20, 3, SurfaceLoadStoreSize> size; // .D
|
||||||
BitField<20, 4, u64> swizzle; // .P
|
BitField<20, 4, u64> swizzle; // .P
|
||||||
BitField<49, 2, Clamp> clamp;
|
BitField<49, 2, SurfaceLoadStoreClamp> clamp;
|
||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<8, 8, IR::Reg> coord_reg;
|
BitField<8, 8, IR::Reg> coord_reg;
|
||||||
BitField<36, 13, u64> bound_offset; // is_bound
|
BitField<36, 13, u64> bound_offset; // is_bound
|
||||||
BitField<39, 8, IR::Reg> bindless_reg; // !is_bound
|
BitField<39, 8, IR::Reg> bindless_reg; // !is_bound
|
||||||
} const suld{insn};
|
} const suld{insn};
|
||||||
|
|
||||||
if (suld.clamp != Clamp::IGN) {
|
if (suld.clamp != SurfaceLoadStoreClamp::IGN) {
|
||||||
throw NotImplementedException("Clamp {}", suld.clamp.Value());
|
throw NotImplementedException("SurfaceLoadStoreClamp {}", suld.clamp.Value());
|
||||||
}
|
}
|
||||||
if (suld.cache != LoadCache::CA && suld.cache != LoadCache::CG) {
|
if (suld.cache != SURFLoadCache::CA && suld.cache != SURFLoadCache::CG) {
|
||||||
throw NotImplementedException("Cache {}", suld.cache.Value());
|
throw NotImplementedException("Cache {}", suld.cache.Value());
|
||||||
}
|
}
|
||||||
const bool is_typed{suld.d != 0};
|
const bool is_typed{suld.d != 0};
|
||||||
@@ -234,21 +237,21 @@ void TranslatorVisitor::SUST(u64 insn) {
|
|||||||
BitField<51, 1, u64> is_bound;
|
BitField<51, 1, u64> is_bound;
|
||||||
BitField<52, 1, u64> d;
|
BitField<52, 1, u64> d;
|
||||||
BitField<23, 1, u64> ba;
|
BitField<23, 1, u64> ba;
|
||||||
BitField<33, 3, Type> type;
|
BitField<33, 3, SurfaceLoadStoreType> type;
|
||||||
BitField<24, 2, StoreCache> cache;
|
BitField<24, 2, SURFStoreCache> cache;
|
||||||
BitField<20, 3, Size> size; // .D
|
BitField<20, 3, SurfaceLoadStoreSize> size; // .D
|
||||||
BitField<20, 4, u64> swizzle; // .P
|
BitField<20, 4, u64> swizzle; // .P
|
||||||
BitField<49, 2, Clamp> clamp;
|
BitField<49, 2, SurfaceLoadStoreClamp> clamp;
|
||||||
BitField<0, 8, IR::Reg> data_reg;
|
BitField<0, 8, IR::Reg> data_reg;
|
||||||
BitField<8, 8, IR::Reg> coord_reg;
|
BitField<8, 8, IR::Reg> coord_reg;
|
||||||
BitField<36, 13, u64> bound_offset; // is_bound
|
BitField<36, 13, u64> bound_offset; // is_bound
|
||||||
BitField<39, 8, IR::Reg> bindless_reg; // !is_bound
|
BitField<39, 8, IR::Reg> bindless_reg; // !is_bound
|
||||||
} const sust{insn};
|
} const sust{insn};
|
||||||
|
|
||||||
if (sust.clamp != Clamp::IGN) {
|
if (sust.clamp != SurfaceLoadStoreClamp::IGN) {
|
||||||
throw NotImplementedException("Clamp {}", sust.clamp.Value());
|
throw NotImplementedException("SurfaceLoadStoreClamp {}", sust.clamp.Value());
|
||||||
}
|
}
|
||||||
if (sust.cache != StoreCache::WB && sust.cache != StoreCache::CG) {
|
if (sust.cache != SURFStoreCache::WB && sust.cache != SURFStoreCache::CG) {
|
||||||
throw NotImplementedException("Cache {}", sust.cache.Value());
|
throw NotImplementedException("Cache {}", sust.cache.Value());
|
||||||
}
|
}
|
||||||
const bool is_typed{sust.d != 0};
|
const bool is_typed{sust.d != 0};
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -21,7 +24,7 @@ enum class Blod : u64 {
|
|||||||
LLA,
|
LLA,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class TextureType : u64 {
|
enum class TextureFetchType : u64 {
|
||||||
_1D,
|
_1D,
|
||||||
ARRAY_1D,
|
ARRAY_1D,
|
||||||
_2D,
|
_2D,
|
||||||
@@ -32,46 +35,46 @@ enum class TextureType : u64 {
|
|||||||
ARRAY_CUBE,
|
ARRAY_CUBE,
|
||||||
};
|
};
|
||||||
|
|
||||||
Shader::TextureType GetType(TextureType type) {
|
Shader::TextureType GetType(TextureFetchType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TextureType::_1D:
|
case TextureFetchType::_1D:
|
||||||
return Shader::TextureType::Color1D;
|
return Shader::TextureType::Color1D;
|
||||||
case TextureType::ARRAY_1D:
|
case TextureFetchType::ARRAY_1D:
|
||||||
return Shader::TextureType::ColorArray1D;
|
return Shader::TextureType::ColorArray1D;
|
||||||
case TextureType::_2D:
|
case TextureFetchType::_2D:
|
||||||
return Shader::TextureType::Color2D;
|
return Shader::TextureType::Color2D;
|
||||||
case TextureType::ARRAY_2D:
|
case TextureFetchType::ARRAY_2D:
|
||||||
return Shader::TextureType::ColorArray2D;
|
return Shader::TextureType::ColorArray2D;
|
||||||
case TextureType::_3D:
|
case TextureFetchType::_3D:
|
||||||
return Shader::TextureType::Color3D;
|
return Shader::TextureType::Color3D;
|
||||||
case TextureType::ARRAY_3D:
|
case TextureFetchType::ARRAY_3D:
|
||||||
throw NotImplementedException("3D array texture type");
|
throw NotImplementedException("3D array texture type");
|
||||||
case TextureType::CUBE:
|
case TextureFetchType::CUBE:
|
||||||
return Shader::TextureType::ColorCube;
|
return Shader::TextureType::ColorCube;
|
||||||
case TextureType::ARRAY_CUBE:
|
case TextureFetchType::ARRAY_CUBE:
|
||||||
return Shader::TextureType::ColorArrayCube;
|
return Shader::TextureType::ColorArrayCube;
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid texture type {}", type);
|
throw NotImplementedException("Invalid texture type {}", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureType type) {
|
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureFetchType type) {
|
||||||
const auto read_array{[&]() -> IR::F32 { return v.ir.ConvertUToF(32, 16, v.X(reg)); }};
|
const auto read_array{[&]() -> IR::F32 { return v.ir.ConvertUToF(32, 16, v.X(reg)); }};
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TextureType::_1D:
|
case TextureFetchType::_1D:
|
||||||
return v.F(reg);
|
return v.F(reg);
|
||||||
case TextureType::ARRAY_1D:
|
case TextureFetchType::ARRAY_1D:
|
||||||
return v.ir.CompositeConstruct(v.F(reg + 1), read_array());
|
return v.ir.CompositeConstruct(v.F(reg + 1), read_array());
|
||||||
case TextureType::_2D:
|
case TextureFetchType::_2D:
|
||||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1));
|
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1));
|
||||||
case TextureType::ARRAY_2D:
|
case TextureFetchType::ARRAY_2D:
|
||||||
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2), read_array());
|
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2), read_array());
|
||||||
case TextureType::_3D:
|
case TextureFetchType::_3D:
|
||||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
||||||
case TextureType::ARRAY_3D:
|
case TextureFetchType::ARRAY_3D:
|
||||||
throw NotImplementedException("3D array texture type");
|
throw NotImplementedException("3D array texture type");
|
||||||
case TextureType::CUBE:
|
case TextureFetchType::CUBE:
|
||||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
||||||
case TextureType::ARRAY_CUBE:
|
case TextureFetchType::ARRAY_CUBE:
|
||||||
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2), v.F(reg + 3), read_array());
|
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2), v.F(reg + 3), read_array());
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid texture type {}", type);
|
throw NotImplementedException("Invalid texture type {}", type);
|
||||||
@@ -95,25 +98,25 @@ IR::F32 MakeLod(TranslatorVisitor& v, IR::Reg& reg, Blod blod) {
|
|||||||
throw NotImplementedException("Invalid blod {}", blod);
|
throw NotImplementedException("Invalid blod {}", blod);
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg& reg, TextureType type) {
|
IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg& reg, TextureFetchType type) {
|
||||||
const IR::U32 value{v.X(reg++)};
|
const IR::U32 value{v.X(reg++)};
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TextureType::_1D:
|
case TextureFetchType::_1D:
|
||||||
case TextureType::ARRAY_1D:
|
case TextureFetchType::ARRAY_1D:
|
||||||
return v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true);
|
return v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true);
|
||||||
case TextureType::_2D:
|
case TextureFetchType::_2D:
|
||||||
case TextureType::ARRAY_2D:
|
case TextureFetchType::ARRAY_2D:
|
||||||
return v.ir.CompositeConstruct(
|
return v.ir.CompositeConstruct(
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true),
|
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true),
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(4), v.ir.Imm32(4), true));
|
v.ir.BitFieldExtract(value, v.ir.Imm32(4), v.ir.Imm32(4), true));
|
||||||
case TextureType::_3D:
|
case TextureFetchType::_3D:
|
||||||
case TextureType::ARRAY_3D:
|
case TextureFetchType::ARRAY_3D:
|
||||||
return v.ir.CompositeConstruct(
|
return v.ir.CompositeConstruct(
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true),
|
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true),
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(4), v.ir.Imm32(4), true),
|
v.ir.BitFieldExtract(value, v.ir.Imm32(4), v.ir.Imm32(4), true),
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(8), v.ir.Imm32(4), true));
|
v.ir.BitFieldExtract(value, v.ir.Imm32(8), v.ir.Imm32(4), true));
|
||||||
case TextureType::CUBE:
|
case TextureFetchType::CUBE:
|
||||||
case TextureType::ARRAY_CUBE:
|
case TextureFetchType::ARRAY_CUBE:
|
||||||
throw NotImplementedException("Illegal offset on CUBE sample");
|
throw NotImplementedException("Illegal offset on CUBE sample");
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid texture type {}", type);
|
throw NotImplementedException("Invalid texture type {}", type);
|
||||||
@@ -141,7 +144,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool aoffi, Blod blod, bool lc,
|
|||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<8, 8, IR::Reg> coord_reg;
|
BitField<8, 8, IR::Reg> coord_reg;
|
||||||
BitField<20, 8, IR::Reg> meta_reg;
|
BitField<20, 8, IR::Reg> meta_reg;
|
||||||
BitField<28, 3, TextureType> type;
|
BitField<28, 3, TextureFetchType> type;
|
||||||
BitField<31, 4, u64> mask;
|
BitField<31, 4, u64> mask;
|
||||||
} const tex{insn};
|
} const tex{insn};
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -8,14 +11,14 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class Precision : u64 {
|
enum class TextureFetchSwizzledPrecision : u64 {
|
||||||
F16,
|
F16,
|
||||||
F32,
|
F32,
|
||||||
};
|
};
|
||||||
|
|
||||||
union Encoding {
|
union EncodinTFS {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<59, 1, Precision> precision;
|
BitField<59, 1, TextureFetchSwizzledPrecision> precision;
|
||||||
BitField<53, 4, u64> encoding;
|
BitField<53, 4, u64> encoding;
|
||||||
BitField<49, 1, u64> nodep;
|
BitField<49, 1, u64> nodep;
|
||||||
BitField<28, 8, IR::Reg> dest_reg_b;
|
BitField<28, 8, IR::Reg> dest_reg_b;
|
||||||
@@ -26,31 +29,7 @@ union Encoding {
|
|||||||
BitField<50, 3, u64> swizzle;
|
BitField<50, 3, u64> swizzle;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr unsigned R = 1;
|
void CheckAlignmentTFS(IR::Reg reg, size_t alignment) {
|
||||||
constexpr unsigned G = 2;
|
|
||||||
constexpr unsigned B = 4;
|
|
||||||
constexpr unsigned A = 8;
|
|
||||||
|
|
||||||
constexpr std::array RG_LUT{
|
|
||||||
R, //
|
|
||||||
G, //
|
|
||||||
B, //
|
|
||||||
A, //
|
|
||||||
R | G, //
|
|
||||||
R | A, //
|
|
||||||
G | A, //
|
|
||||||
B | A, //
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr std::array RGBA_LUT{
|
|
||||||
R | G | B, //
|
|
||||||
R | G | A, //
|
|
||||||
R | B | A, //
|
|
||||||
G | B | A, //
|
|
||||||
R | G | B | A, //
|
|
||||||
};
|
|
||||||
|
|
||||||
void CheckAlignment(IR::Reg reg, size_t alignment) {
|
|
||||||
if (!IR::IsAligned(reg, alignment)) {
|
if (!IR::IsAligned(reg, alignment)) {
|
||||||
throw NotImplementedException("Unaligned source register {}", reg);
|
throw NotImplementedException("Unaligned source register {}", reg);
|
||||||
}
|
}
|
||||||
@@ -65,14 +44,14 @@ IR::F32 ReadArray(TranslatorVisitor& v, const IR::U32& value) {
|
|||||||
return v.ir.ConvertUToF(32, 16, v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(16)));
|
return v.ir.ConvertUToF(32, 16, v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(16)));
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
IR::Value SampleTFS(TranslatorVisitor& v, u64 insn) {
|
||||||
const Encoding texs{insn};
|
const EncodinTFS texs{insn};
|
||||||
const IR::U32 handle{v.ir.Imm32(static_cast<u32>(texs.cbuf_offset * 4))};
|
const IR::U32 handle{v.ir.Imm32(static_cast<u32>(texs.cbuf_offset * 4))};
|
||||||
const IR::F32 zero{v.ir.Imm32(0.0f)};
|
const IR::F32 zero{v.ir.Imm32(0.0f)};
|
||||||
const IR::Reg reg_a{texs.src_reg_a};
|
const IR::Reg reg_a{texs.src_reg_a};
|
||||||
const IR::Reg reg_b{texs.src_reg_b};
|
const IR::Reg reg_b{texs.src_reg_b};
|
||||||
IR::TextureInstInfo info{};
|
IR::TextureInstInfo info{};
|
||||||
if (texs.precision == Precision::F16) {
|
if (texs.precision == TextureFetchSwizzledPrecision::F16) {
|
||||||
info.relaxed_precision.Assign(1);
|
info.relaxed_precision.Assign(1);
|
||||||
}
|
}
|
||||||
switch (texs.encoding) {
|
switch (texs.encoding) {
|
||||||
@@ -86,67 +65,67 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
|||||||
info.type.Assign(TextureType::Color2D);
|
info.type.Assign(TextureType::Color2D);
|
||||||
return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_b), zero, {}, info);
|
return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_b), zero, {}, info);
|
||||||
case 3: // 2D.LL
|
case 3: // 2D.LL
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTFS(reg_a, 2);
|
||||||
info.type.Assign(TextureType::Color2D);
|
info.type.Assign(TextureType::Color2D);
|
||||||
return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b), {},
|
return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b), {},
|
||||||
info);
|
info);
|
||||||
case 4: // 2D.DC
|
case 4: // 2D.DC
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTFS(reg_a, 2);
|
||||||
info.type.Assign(TextureType::Color2D);
|
info.type.Assign(TextureType::Color2D);
|
||||||
info.is_depth.Assign(1);
|
info.is_depth.Assign(1);
|
||||||
return v.ir.ImageSampleDrefImplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b),
|
return v.ir.ImageSampleDrefImplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b),
|
||||||
{}, {}, {}, info);
|
{}, {}, {}, info);
|
||||||
case 5: // 2D.LL.DC
|
case 5: // 2D.LL.DC
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTFS(reg_a, 2);
|
||||||
CheckAlignment(reg_b, 2);
|
CheckAlignmentTFS(reg_b, 2);
|
||||||
info.type.Assign(TextureType::Color2D);
|
info.type.Assign(TextureType::Color2D);
|
||||||
info.is_depth.Assign(1);
|
info.is_depth.Assign(1);
|
||||||
return v.ir.ImageSampleDrefExplicitLod(handle, Composite(v, reg_a, reg_a + 1),
|
return v.ir.ImageSampleDrefExplicitLod(handle, Composite(v, reg_a, reg_a + 1),
|
||||||
v.F(reg_b + 1), v.F(reg_b), {}, info);
|
v.F(reg_b + 1), v.F(reg_b), {}, info);
|
||||||
case 6: // 2D.LZ.DC
|
case 6: // 2D.LZ.DC
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTFS(reg_a, 2);
|
||||||
info.type.Assign(TextureType::Color2D);
|
info.type.Assign(TextureType::Color2D);
|
||||||
info.is_depth.Assign(1);
|
info.is_depth.Assign(1);
|
||||||
return v.ir.ImageSampleDrefExplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b),
|
return v.ir.ImageSampleDrefExplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b),
|
||||||
zero, {}, info);
|
zero, {}, info);
|
||||||
case 7: // ARRAY_2D
|
case 7: // ARRAY_2D
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTFS(reg_a, 2);
|
||||||
info.type.Assign(TextureType::ColorArray2D);
|
info.type.Assign(TextureType::ColorArray2D);
|
||||||
return v.ir.ImageSampleImplicitLod(
|
return v.ir.ImageSampleImplicitLod(
|
||||||
handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))),
|
handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))),
|
||||||
{}, {}, {}, info);
|
{}, {}, {}, info);
|
||||||
case 8: // ARRAY_2D.LZ
|
case 8: // ARRAY_2D.LZ
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTFS(reg_a, 2);
|
||||||
info.type.Assign(TextureType::ColorArray2D);
|
info.type.Assign(TextureType::ColorArray2D);
|
||||||
return v.ir.ImageSampleExplicitLod(
|
return v.ir.ImageSampleExplicitLod(
|
||||||
handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))),
|
handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))),
|
||||||
zero, {}, info);
|
zero, {}, info);
|
||||||
case 9: // ARRAY_2D.LZ.DC
|
case 9: // ARRAY_2D.LZ.DC
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTFS(reg_a, 2);
|
||||||
CheckAlignment(reg_b, 2);
|
CheckAlignmentTFS(reg_b, 2);
|
||||||
info.type.Assign(TextureType::ColorArray2D);
|
info.type.Assign(TextureType::ColorArray2D);
|
||||||
info.is_depth.Assign(1);
|
info.is_depth.Assign(1);
|
||||||
return v.ir.ImageSampleDrefExplicitLod(
|
return v.ir.ImageSampleDrefExplicitLod(
|
||||||
handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))),
|
handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))),
|
||||||
v.F(reg_b + 1), zero, {}, info);
|
v.F(reg_b + 1), zero, {}, info);
|
||||||
case 10: // 3D
|
case 10: // 3D
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTFS(reg_a, 2);
|
||||||
info.type.Assign(TextureType::Color3D);
|
info.type.Assign(TextureType::Color3D);
|
||||||
return v.ir.ImageSampleImplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), {}, {},
|
return v.ir.ImageSampleImplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), {}, {},
|
||||||
{}, info);
|
{}, info);
|
||||||
case 11: // 3D.LZ
|
case 11: // 3D.LZ
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTFS(reg_a, 2);
|
||||||
info.type.Assign(TextureType::Color3D);
|
info.type.Assign(TextureType::Color3D);
|
||||||
return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), zero, {},
|
return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), zero, {},
|
||||||
info);
|
info);
|
||||||
case 12: // CUBE
|
case 12: // CUBE
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTFS(reg_a, 2);
|
||||||
info.type.Assign(TextureType::ColorCube);
|
info.type.Assign(TextureType::ColorCube);
|
||||||
return v.ir.ImageSampleImplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), {}, {},
|
return v.ir.ImageSampleImplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), {}, {},
|
||||||
{}, info);
|
{}, info);
|
||||||
case 13: // CUBE.LL
|
case 13: // CUBE.LL
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTFS(reg_a, 2);
|
||||||
CheckAlignment(reg_b, 2);
|
CheckAlignmentTFS(reg_b, 2);
|
||||||
info.type.Assign(TextureType::ColorCube);
|
info.type.Assign(TextureType::ColorCube);
|
||||||
return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b),
|
return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b),
|
||||||
v.F(reg_b + 1), {}, info);
|
v.F(reg_b + 1), {}, info);
|
||||||
@@ -155,23 +134,46 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned Swizzle(u64 insn) {
|
unsigned FetchSwizzle(u64 insn) {
|
||||||
const Encoding texs{insn};
|
#define R 1
|
||||||
|
#define G 2
|
||||||
|
#define B 4
|
||||||
|
#define A 8
|
||||||
|
constexpr std::array<unsigned, 8> RG_LUT{
|
||||||
|
R, //
|
||||||
|
G, //
|
||||||
|
B, //
|
||||||
|
A, //
|
||||||
|
R | G, //
|
||||||
|
R | A, //
|
||||||
|
G | A, //
|
||||||
|
B | A, //
|
||||||
|
};
|
||||||
|
constexpr std::array<unsigned, 5> RGBA_LUT{
|
||||||
|
R | G | B, //
|
||||||
|
R | G | A, //
|
||||||
|
R | B | A, //
|
||||||
|
G | B | A, //
|
||||||
|
R | G | B | A, //
|
||||||
|
};
|
||||||
|
#undef R
|
||||||
|
#undef G
|
||||||
|
#undef B
|
||||||
|
#undef A
|
||||||
|
const EncodinTFS texs{insn};
|
||||||
const size_t encoding{texs.swizzle};
|
const size_t encoding{texs.swizzle};
|
||||||
if (texs.dest_reg_b == IR::Reg::RZ) {
|
if (texs.dest_reg_b == IR::Reg::RZ) {
|
||||||
if (encoding >= RG_LUT.size()) {
|
if (encoding >= RG_LUT.size())
|
||||||
throw NotImplementedException("Illegal RG encoding {}", encoding);
|
throw NotImplementedException("Illegal RG encoding {}", encoding);
|
||||||
}
|
|
||||||
return RG_LUT[encoding];
|
return RG_LUT[encoding];
|
||||||
} else {
|
} else {
|
||||||
if (encoding >= RGBA_LUT.size()) {
|
if (encoding >= RGBA_LUT.size())
|
||||||
throw NotImplementedException("Illegal RGBA encoding {}", encoding);
|
throw NotImplementedException("Illegal RGBA encoding {}", encoding);
|
||||||
}
|
|
||||||
return RGBA_LUT[encoding];
|
return RGBA_LUT[encoding];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::F32 Extract(TranslatorVisitor& v, const IR::Value& sample, unsigned component) {
|
IR::F32 FetchExtract(TranslatorVisitor& v, const IR::Value& sample, unsigned component) {
|
||||||
const bool is_shadow{sample.Type() == IR::Type::F32};
|
const bool is_shadow{sample.Type() == IR::Type::F32};
|
||||||
if (is_shadow) {
|
if (is_shadow) {
|
||||||
const bool is_alpha{component == 3};
|
const bool is_alpha{component == 3};
|
||||||
@@ -181,69 +183,69 @@ IR::F32 Extract(TranslatorVisitor& v, const IR::Value& sample, unsigned componen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Reg RegStoreComponent32(u64 insn, unsigned index) {
|
IR::Reg FetchRegStoreComponent32(u64 insn, unsigned index) {
|
||||||
const Encoding texs{insn};
|
const EncodinTFS texs{insn};
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
return texs.dest_reg_a;
|
return texs.dest_reg_a;
|
||||||
case 1:
|
case 1:
|
||||||
CheckAlignment(texs.dest_reg_a, 2);
|
CheckAlignmentTFS(texs.dest_reg_a, 2);
|
||||||
return texs.dest_reg_a + 1;
|
return texs.dest_reg_a + 1;
|
||||||
case 2:
|
case 2:
|
||||||
return texs.dest_reg_b;
|
return texs.dest_reg_b;
|
||||||
case 3:
|
case 3:
|
||||||
CheckAlignment(texs.dest_reg_b, 2);
|
CheckAlignmentTFS(texs.dest_reg_b, 2);
|
||||||
return texs.dest_reg_b + 1;
|
return texs.dest_reg_b + 1;
|
||||||
}
|
}
|
||||||
throw LogicError("Invalid store index {}", index);
|
throw LogicError("Invalid store index {}", index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Store32(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
void Store32TFS(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||||
const unsigned swizzle{Swizzle(insn)};
|
const unsigned swizzle{FetchSwizzle(insn)};
|
||||||
unsigned store_index{0};
|
unsigned store_index{0};
|
||||||
for (unsigned component = 0; component < 4; ++component) {
|
for (unsigned component = 0; component < 4; ++component) {
|
||||||
if (((swizzle >> component) & 1) == 0) {
|
if (((swizzle >> component) & 1) == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const IR::Reg dest{RegStoreComponent32(insn, store_index)};
|
const IR::Reg dest{FetchRegStoreComponent32(insn, store_index)};
|
||||||
v.F(dest, Extract(v, sample, component));
|
v.F(dest, FetchExtract(v, sample, component));
|
||||||
++store_index;
|
++store_index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U32 Pack(TranslatorVisitor& v, const IR::F32& lhs, const IR::F32& rhs) {
|
IR::U32 PackTFS(TranslatorVisitor& v, const IR::F32& lhs, const IR::F32& rhs) {
|
||||||
return v.ir.PackHalf2x16(v.ir.CompositeConstruct(lhs, rhs));
|
return v.ir.PackHalf2x16(v.ir.CompositeConstruct(lhs, rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Store16(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
void Store16TFS(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||||
const unsigned swizzle{Swizzle(insn)};
|
const unsigned swizzle{FetchSwizzle(insn)};
|
||||||
unsigned store_index{0};
|
unsigned store_index{0};
|
||||||
std::array<IR::F32, 4> swizzled;
|
std::array<IR::F32, 4> swizzled;
|
||||||
for (unsigned component = 0; component < 4; ++component) {
|
for (unsigned component = 0; component < 4; ++component) {
|
||||||
if (((swizzle >> component) & 1) == 0) {
|
if (((swizzle >> component) & 1) == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
swizzled[store_index] = Extract(v, sample, component);
|
swizzled[store_index] = FetchExtract(v, sample, component);
|
||||||
++store_index;
|
++store_index;
|
||||||
}
|
}
|
||||||
const IR::F32 zero{v.ir.Imm32(0.0f)};
|
const IR::F32 zero{v.ir.Imm32(0.0f)};
|
||||||
const Encoding texs{insn};
|
const EncodinTFS texs{insn};
|
||||||
switch (store_index) {
|
switch (store_index) {
|
||||||
case 1:
|
case 1:
|
||||||
v.X(texs.dest_reg_a, Pack(v, swizzled[0], zero));
|
v.X(texs.dest_reg_a, PackTFS(v, swizzled[0], zero));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
case 4:
|
case 4:
|
||||||
v.X(texs.dest_reg_a, Pack(v, swizzled[0], swizzled[1]));
|
v.X(texs.dest_reg_a, PackTFS(v, swizzled[0], swizzled[1]));
|
||||||
switch (store_index) {
|
switch (store_index) {
|
||||||
case 2:
|
case 2:
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
v.X(texs.dest_reg_b, Pack(v, swizzled[2], zero));
|
v.X(texs.dest_reg_b, PackTFS(v, swizzled[2], zero));
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
v.X(texs.dest_reg_b, Pack(v, swizzled[2], swizzled[3]));
|
v.X(texs.dest_reg_b, PackTFS(v, swizzled[2], swizzled[3]));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -252,11 +254,11 @@ void Store16(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
|||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
void TranslatorVisitor::TEXS(u64 insn) {
|
void TranslatorVisitor::TEXS(u64 insn) {
|
||||||
const IR::Value sample{Sample(*this, insn)};
|
const IR::Value sample{SampleTFS(*this, insn)};
|
||||||
if (Encoding{insn}.precision == Precision::F32) {
|
if (EncodinTFS{insn}.precision == TextureFetchSwizzledPrecision::F32) {
|
||||||
Store32(*this, insn, sample);
|
Store32TFS(*this, insn, sample);
|
||||||
} else {
|
} else {
|
||||||
Store16(*this, insn, sample);
|
Store16TFS(*this, insn, sample);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -9,7 +12,7 @@
|
|||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
enum class TextureType : u64 {
|
enum class TextureGatherType : u64 {
|
||||||
_1D,
|
_1D,
|
||||||
ARRAY_1D,
|
ARRAY_1D,
|
||||||
_2D,
|
_2D,
|
||||||
@@ -27,77 +30,77 @@ enum class OffsetType : u64 {
|
|||||||
Invalid,
|
Invalid,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ComponentType : u64 {
|
enum class TextureGatherComponentType : u64 {
|
||||||
R = 0,
|
R = 0,
|
||||||
G = 1,
|
G = 1,
|
||||||
B = 2,
|
B = 2,
|
||||||
A = 3,
|
A = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
Shader::TextureType GetType(TextureType type) {
|
Shader::TextureType GetTextureGatherType(TextureGatherType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TextureType::_1D:
|
case TextureGatherType::_1D:
|
||||||
return Shader::TextureType::Color1D;
|
return Shader::TextureType::Color1D;
|
||||||
case TextureType::ARRAY_1D:
|
case TextureGatherType::ARRAY_1D:
|
||||||
return Shader::TextureType::ColorArray1D;
|
return Shader::TextureType::ColorArray1D;
|
||||||
case TextureType::_2D:
|
case TextureGatherType::_2D:
|
||||||
return Shader::TextureType::Color2D;
|
return Shader::TextureType::Color2D;
|
||||||
case TextureType::ARRAY_2D:
|
case TextureGatherType::ARRAY_2D:
|
||||||
return Shader::TextureType::ColorArray2D;
|
return Shader::TextureType::ColorArray2D;
|
||||||
case TextureType::_3D:
|
case TextureGatherType::_3D:
|
||||||
return Shader::TextureType::Color3D;
|
return Shader::TextureType::Color3D;
|
||||||
case TextureType::ARRAY_3D:
|
case TextureGatherType::ARRAY_3D:
|
||||||
throw NotImplementedException("3D array texture type");
|
throw NotImplementedException("3D array texture type");
|
||||||
case TextureType::CUBE:
|
case TextureGatherType::CUBE:
|
||||||
return Shader::TextureType::ColorCube;
|
return Shader::TextureType::ColorCube;
|
||||||
case TextureType::ARRAY_CUBE:
|
case TextureGatherType::ARRAY_CUBE:
|
||||||
return Shader::TextureType::ColorArrayCube;
|
return Shader::TextureType::ColorArrayCube;
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid texture type {}", type);
|
throw NotImplementedException("Invalid texture type {}", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureType type) {
|
IR::Value MakeTextureGatherCoords(TranslatorVisitor& v, IR::Reg reg, TextureGatherType type) {
|
||||||
const auto read_array{[&]() -> IR::F32 { return v.ir.ConvertUToF(32, 16, v.X(reg)); }};
|
const auto read_array{[&]() -> IR::F32 { return v.ir.ConvertUToF(32, 16, v.X(reg)); }};
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TextureType::_1D:
|
case TextureGatherType::_1D:
|
||||||
return v.F(reg);
|
return v.F(reg);
|
||||||
case TextureType::ARRAY_1D:
|
case TextureGatherType::ARRAY_1D:
|
||||||
return v.ir.CompositeConstruct(v.F(reg + 1), read_array());
|
return v.ir.CompositeConstruct(v.F(reg + 1), read_array());
|
||||||
case TextureType::_2D:
|
case TextureGatherType::_2D:
|
||||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1));
|
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1));
|
||||||
case TextureType::ARRAY_2D:
|
case TextureGatherType::ARRAY_2D:
|
||||||
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2), read_array());
|
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2), read_array());
|
||||||
case TextureType::_3D:
|
case TextureGatherType::_3D:
|
||||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
||||||
case TextureType::ARRAY_3D:
|
case TextureGatherType::ARRAY_3D:
|
||||||
throw NotImplementedException("3D array texture type");
|
throw NotImplementedException("3D array texture type");
|
||||||
case TextureType::CUBE:
|
case TextureGatherType::CUBE:
|
||||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
||||||
case TextureType::ARRAY_CUBE:
|
case TextureGatherType::ARRAY_CUBE:
|
||||||
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2), v.F(reg + 3), read_array());
|
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2), v.F(reg + 3), read_array());
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid texture type {}", type);
|
throw NotImplementedException("Invalid texture type {}", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg& reg, TextureType type) {
|
IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg& reg, TextureGatherType type) {
|
||||||
const IR::U32 value{v.X(reg++)};
|
const IR::U32 value{v.X(reg++)};
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TextureType::_1D:
|
case TextureGatherType::_1D:
|
||||||
case TextureType::ARRAY_1D:
|
case TextureGatherType::ARRAY_1D:
|
||||||
return v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(6), true);
|
return v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(6), true);
|
||||||
case TextureType::_2D:
|
case TextureGatherType::_2D:
|
||||||
case TextureType::ARRAY_2D:
|
case TextureGatherType::ARRAY_2D:
|
||||||
return v.ir.CompositeConstruct(
|
return v.ir.CompositeConstruct(
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(6), true),
|
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(6), true),
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(8), v.ir.Imm32(6), true));
|
v.ir.BitFieldExtract(value, v.ir.Imm32(8), v.ir.Imm32(6), true));
|
||||||
case TextureType::_3D:
|
case TextureGatherType::_3D:
|
||||||
case TextureType::ARRAY_3D:
|
case TextureGatherType::ARRAY_3D:
|
||||||
return v.ir.CompositeConstruct(
|
return v.ir.CompositeConstruct(
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(6), true),
|
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(6), true),
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(8), v.ir.Imm32(6), true),
|
v.ir.BitFieldExtract(value, v.ir.Imm32(8), v.ir.Imm32(6), true),
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(16), v.ir.Imm32(6), true));
|
v.ir.BitFieldExtract(value, v.ir.Imm32(16), v.ir.Imm32(6), true));
|
||||||
case TextureType::CUBE:
|
case TextureGatherType::CUBE:
|
||||||
case TextureType::ARRAY_CUBE:
|
case TextureGatherType::ARRAY_CUBE:
|
||||||
throw NotImplementedException("Illegal offset on CUBE sample");
|
throw NotImplementedException("Illegal offset on CUBE sample");
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid texture type {}", type);
|
throw NotImplementedException("Invalid texture type {}", type);
|
||||||
@@ -116,7 +119,7 @@ std::pair<IR::Value, IR::Value> MakeOffsetPTP(TranslatorVisitor& v, IR::Reg& reg
|
|||||||
return {make_vector(value1), make_vector(value2)};
|
return {make_vector(value1), make_vector(value2)};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Impl(TranslatorVisitor& v, u64 insn, ComponentType component_type, OffsetType offset_type,
|
void Impl(TranslatorVisitor& v, u64 insn, TextureGatherComponentType component_type, OffsetType offset_type,
|
||||||
bool is_bindless) {
|
bool is_bindless) {
|
||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
@@ -127,12 +130,12 @@ void Impl(TranslatorVisitor& v, u64 insn, ComponentType component_type, OffsetTy
|
|||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<8, 8, IR::Reg> coord_reg;
|
BitField<8, 8, IR::Reg> coord_reg;
|
||||||
BitField<20, 8, IR::Reg> meta_reg;
|
BitField<20, 8, IR::Reg> meta_reg;
|
||||||
BitField<28, 3, TextureType> type;
|
BitField<28, 3, TextureGatherType> type;
|
||||||
BitField<31, 4, u64> mask;
|
BitField<31, 4, u64> mask;
|
||||||
BitField<36, 13, u64> cbuf_offset;
|
BitField<36, 13, u64> cbuf_offset;
|
||||||
} const tld4{insn};
|
} const tld4{insn};
|
||||||
|
|
||||||
const IR::Value coords{MakeCoords(v, tld4.coord_reg, tld4.type)};
|
const IR::Value coords{MakeTextureGatherCoords(v, tld4.coord_reg, tld4.type)};
|
||||||
|
|
||||||
IR::Reg meta_reg{tld4.meta_reg};
|
IR::Reg meta_reg{tld4.meta_reg};
|
||||||
IR::Value handle;
|
IR::Value handle;
|
||||||
@@ -160,7 +163,7 @@ void Impl(TranslatorVisitor& v, u64 insn, ComponentType component_type, OffsetTy
|
|||||||
dref = v.F(meta_reg++);
|
dref = v.F(meta_reg++);
|
||||||
}
|
}
|
||||||
IR::TextureInstInfo info{};
|
IR::TextureInstInfo info{};
|
||||||
info.type.Assign(GetType(tld4.type));
|
info.type.Assign(GetTextureGatherType(tld4.type));
|
||||||
info.is_depth.Assign(tld4.dc != 0 ? 1 : 0);
|
info.is_depth.Assign(tld4.dc != 0 ? 1 : 0);
|
||||||
info.gather_component.Assign(static_cast<u32>(component_type));
|
info.gather_component.Assign(static_cast<u32>(component_type));
|
||||||
const IR::Value sample{[&] {
|
const IR::Value sample{[&] {
|
||||||
@@ -187,7 +190,7 @@ void Impl(TranslatorVisitor& v, u64 insn, ComponentType component_type, OffsetTy
|
|||||||
void TranslatorVisitor::TLD4(u64 insn) {
|
void TranslatorVisitor::TLD4(u64 insn) {
|
||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<56, 2, ComponentType> component;
|
BitField<56, 2, TextureGatherComponentType> component;
|
||||||
BitField<54, 2, OffsetType> offset;
|
BitField<54, 2, OffsetType> offset;
|
||||||
} const tld4{insn};
|
} const tld4{insn};
|
||||||
Impl(*this, insn, tld4.component, tld4.offset, false);
|
Impl(*this, insn, tld4.component, tld4.offset, false);
|
||||||
@@ -196,7 +199,7 @@ void TranslatorVisitor::TLD4(u64 insn) {
|
|||||||
void TranslatorVisitor::TLD4_b(u64 insn) {
|
void TranslatorVisitor::TLD4_b(u64 insn) {
|
||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<38, 2, ComponentType> component;
|
BitField<38, 2, TextureGatherComponentType> component;
|
||||||
BitField<36, 2, OffsetType> offset;
|
BitField<36, 2, OffsetType> offset;
|
||||||
} const tld4{insn};
|
} const tld4{insn};
|
||||||
Impl(*this, insn, tld4.component, tld4.offset, true);
|
Impl(*this, insn, tld4.component, tld4.offset, true);
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -8,22 +11,22 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class Precision : u64 {
|
enum class TextureGatherSwizzledPrecision : u64 {
|
||||||
F32,
|
F32,
|
||||||
F16,
|
F16,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ComponentType : u64 {
|
enum class TextureGatherSwizzledComponentType : u64 {
|
||||||
R = 0,
|
R = 0,
|
||||||
G = 1,
|
G = 1,
|
||||||
B = 2,
|
B = 2,
|
||||||
A = 3,
|
A = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
union Encoding {
|
union EncodinTGS {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<55, 1, Precision> precision;
|
BitField<55, 1, TextureGatherSwizzledPrecision> precision;
|
||||||
BitField<52, 2, ComponentType> component_type;
|
BitField<52, 2, TextureGatherSwizzledComponentType> component_type;
|
||||||
BitField<51, 1, u64> aoffi;
|
BitField<51, 1, u64> aoffi;
|
||||||
BitField<50, 1, u64> dc;
|
BitField<50, 1, u64> dc;
|
||||||
BitField<49, 1, u64> nodep;
|
BitField<49, 1, u64> nodep;
|
||||||
@@ -34,25 +37,25 @@ union Encoding {
|
|||||||
BitField<36, 13, u64> cbuf_offset;
|
BitField<36, 13, u64> cbuf_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
void CheckAlignment(IR::Reg reg, size_t alignment) {
|
void CheckAlignmentTGS(IR::Reg reg, size_t alignment) {
|
||||||
if (!IR::IsAligned(reg, alignment)) {
|
if (!IR::IsAligned(reg, alignment)) {
|
||||||
throw NotImplementedException("Unaligned source register {}", reg);
|
throw NotImplementedException("Unaligned source register {}", reg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg reg) {
|
IR::Value MakeGatherOffset(TranslatorVisitor& v, IR::Reg reg) {
|
||||||
const IR::U32 value{v.X(reg)};
|
const IR::U32 value{v.X(reg)};
|
||||||
return v.ir.CompositeConstruct(v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(6), true),
|
return v.ir.CompositeConstruct(v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(6), true),
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(8), v.ir.Imm32(6), true));
|
v.ir.BitFieldExtract(value, v.ir.Imm32(8), v.ir.Imm32(6), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
IR::Value SampleTGS(TranslatorVisitor& v, u64 insn) {
|
||||||
const Encoding tld4s{insn};
|
const EncodinTGS tld4s{insn};
|
||||||
const IR::U32 handle{v.ir.Imm32(static_cast<u32>(tld4s.cbuf_offset * 4))};
|
const IR::U32 handle{v.ir.Imm32(static_cast<u32>(tld4s.cbuf_offset * 4))};
|
||||||
const IR::Reg reg_a{tld4s.src_reg_a};
|
const IR::Reg reg_a{tld4s.src_reg_a};
|
||||||
const IR::Reg reg_b{tld4s.src_reg_b};
|
const IR::Reg reg_b{tld4s.src_reg_b};
|
||||||
IR::TextureInstInfo info{};
|
IR::TextureInstInfo info{};
|
||||||
if (tld4s.precision == Precision::F16) {
|
if (tld4s.precision == TextureGatherSwizzledPrecision::F16) {
|
||||||
info.relaxed_precision.Assign(1);
|
info.relaxed_precision.Assign(1);
|
||||||
}
|
}
|
||||||
info.gather_component.Assign(static_cast<u32>(tld4s.component_type.Value()));
|
info.gather_component.Assign(static_cast<u32>(tld4s.component_type.Value()));
|
||||||
@@ -60,18 +63,18 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
|||||||
info.is_depth.Assign(tld4s.dc != 0 ? 1 : 0);
|
info.is_depth.Assign(tld4s.dc != 0 ? 1 : 0);
|
||||||
IR::Value coords;
|
IR::Value coords;
|
||||||
if (tld4s.aoffi != 0) {
|
if (tld4s.aoffi != 0) {
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTGS(reg_a, 2);
|
||||||
coords = v.ir.CompositeConstruct(v.F(reg_a), v.F(reg_a + 1));
|
coords = v.ir.CompositeConstruct(v.F(reg_a), v.F(reg_a + 1));
|
||||||
IR::Value offset = MakeOffset(v, reg_b);
|
IR::Value offset = MakeGatherOffset(v, reg_b);
|
||||||
if (tld4s.dc != 0) {
|
if (tld4s.dc != 0) {
|
||||||
CheckAlignment(reg_b, 2);
|
CheckAlignmentTGS(reg_b, 2);
|
||||||
IR::F32 dref = v.F(reg_b + 1);
|
IR::F32 dref = v.F(reg_b + 1);
|
||||||
return v.ir.ImageGatherDref(handle, coords, offset, {}, dref, info);
|
return v.ir.ImageGatherDref(handle, coords, offset, {}, dref, info);
|
||||||
}
|
}
|
||||||
return v.ir.ImageGather(handle, coords, offset, {}, info);
|
return v.ir.ImageGather(handle, coords, offset, {}, info);
|
||||||
}
|
}
|
||||||
if (tld4s.dc != 0) {
|
if (tld4s.dc != 0) {
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTGS(reg_a, 2);
|
||||||
coords = v.ir.CompositeConstruct(v.F(reg_a), v.F(reg_a + 1));
|
coords = v.ir.CompositeConstruct(v.F(reg_a), v.F(reg_a + 1));
|
||||||
IR::F32 dref = v.F(reg_b);
|
IR::F32 dref = v.F(reg_b);
|
||||||
return v.ir.ImageGatherDref(handle, coords, {}, {}, dref, info);
|
return v.ir.ImageGatherDref(handle, coords, {}, {}, dref, info);
|
||||||
@@ -81,50 +84,50 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IR::Reg RegStoreComponent32(u64 insn, size_t index) {
|
IR::Reg RegStoreComponent32(u64 insn, size_t index) {
|
||||||
const Encoding tlds4{insn};
|
const EncodinTGS tlds4{insn};
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
return tlds4.dest_reg_a;
|
return tlds4.dest_reg_a;
|
||||||
case 1:
|
case 1:
|
||||||
CheckAlignment(tlds4.dest_reg_a, 2);
|
CheckAlignmentTGS(tlds4.dest_reg_a, 2);
|
||||||
return tlds4.dest_reg_a + 1;
|
return tlds4.dest_reg_a + 1;
|
||||||
case 2:
|
case 2:
|
||||||
return tlds4.dest_reg_b;
|
return tlds4.dest_reg_b;
|
||||||
case 3:
|
case 3:
|
||||||
CheckAlignment(tlds4.dest_reg_b, 2);
|
CheckAlignmentTGS(tlds4.dest_reg_b, 2);
|
||||||
return tlds4.dest_reg_b + 1;
|
return tlds4.dest_reg_b + 1;
|
||||||
}
|
}
|
||||||
throw LogicError("Invalid store index {}", index);
|
throw LogicError("Invalid store index {}", index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Store32(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
void Store32TGS(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||||
for (size_t component = 0; component < 4; ++component) {
|
for (size_t component = 0; component < 4; ++component) {
|
||||||
const IR::Reg dest{RegStoreComponent32(insn, component)};
|
const IR::Reg dest{RegStoreComponent32(insn, component)};
|
||||||
v.F(dest, IR::F32{v.ir.CompositeExtract(sample, component)});
|
v.F(dest, IR::F32{v.ir.CompositeExtract(sample, component)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U32 Pack(TranslatorVisitor& v, const IR::F32& lhs, const IR::F32& rhs) {
|
IR::U32 PackTGS(TranslatorVisitor& v, const IR::F32& lhs, const IR::F32& rhs) {
|
||||||
return v.ir.PackHalf2x16(v.ir.CompositeConstruct(lhs, rhs));
|
return v.ir.PackHalf2x16(v.ir.CompositeConstruct(lhs, rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Store16(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
void Store16TGS(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||||
std::array<IR::F32, 4> swizzled;
|
std::array<IR::F32, 4> swizzled;
|
||||||
for (size_t component = 0; component < 4; ++component) {
|
for (size_t component = 0; component < 4; ++component) {
|
||||||
swizzled[component] = IR::F32{v.ir.CompositeExtract(sample, component)};
|
swizzled[component] = IR::F32{v.ir.CompositeExtract(sample, component)};
|
||||||
}
|
}
|
||||||
const Encoding tld4s{insn};
|
const EncodinTGS tld4s{insn};
|
||||||
v.X(tld4s.dest_reg_a, Pack(v, swizzled[0], swizzled[1]));
|
v.X(tld4s.dest_reg_a, PackTGS(v, swizzled[0], swizzled[1]));
|
||||||
v.X(tld4s.dest_reg_b, Pack(v, swizzled[2], swizzled[3]));
|
v.X(tld4s.dest_reg_b, PackTGS(v, swizzled[2], swizzled[3]));
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
void TranslatorVisitor::TLD4S(u64 insn) {
|
void TranslatorVisitor::TLD4S(u64 insn) {
|
||||||
const IR::Value sample{Sample(*this, insn)};
|
const IR::Value sample{SampleTGS(*this, insn)};
|
||||||
if (Encoding{insn}.precision == Precision::F32) {
|
if (EncodinTGS{insn}.precision == TextureGatherSwizzledPrecision::F32) {
|
||||||
Store32(*this, insn, sample);
|
Store32TGS(*this, insn, sample);
|
||||||
} else {
|
} else {
|
||||||
Store16(*this, insn, sample);
|
Store16TGS(*this, insn, sample);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -9,7 +12,7 @@
|
|||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
enum class TextureType : u64 {
|
enum class TextureGradientType : u64 {
|
||||||
_1D,
|
_1D,
|
||||||
ARRAY_1D,
|
ARRAY_1D,
|
||||||
_2D,
|
_2D,
|
||||||
@@ -20,23 +23,23 @@ enum class TextureType : u64 {
|
|||||||
ARRAY_CUBE,
|
ARRAY_CUBE,
|
||||||
};
|
};
|
||||||
|
|
||||||
Shader::TextureType GetType(TextureType type) {
|
Shader::TextureType GetType(TextureGradientType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TextureType::_1D:
|
case TextureGradientType::_1D:
|
||||||
return Shader::TextureType::Color1D;
|
return Shader::TextureType::Color1D;
|
||||||
case TextureType::ARRAY_1D:
|
case TextureGradientType::ARRAY_1D:
|
||||||
return Shader::TextureType::ColorArray1D;
|
return Shader::TextureType::ColorArray1D;
|
||||||
case TextureType::_2D:
|
case TextureGradientType::_2D:
|
||||||
return Shader::TextureType::Color2D;
|
return Shader::TextureType::Color2D;
|
||||||
case TextureType::ARRAY_2D:
|
case TextureGradientType::ARRAY_2D:
|
||||||
return Shader::TextureType::ColorArray2D;
|
return Shader::TextureType::ColorArray2D;
|
||||||
case TextureType::_3D:
|
case TextureGradientType::_3D:
|
||||||
return Shader::TextureType::Color3D;
|
return Shader::TextureType::Color3D;
|
||||||
case TextureType::ARRAY_3D:
|
case TextureGradientType::ARRAY_3D:
|
||||||
throw NotImplementedException("3D array texture type");
|
throw NotImplementedException("3D array texture type");
|
||||||
case TextureType::CUBE:
|
case TextureGradientType::CUBE:
|
||||||
return Shader::TextureType::ColorCube;
|
return Shader::TextureType::ColorCube;
|
||||||
case TextureType::ARRAY_CUBE:
|
case TextureGradientType::ARRAY_CUBE:
|
||||||
return Shader::TextureType::ColorArrayCube;
|
return Shader::TextureType::ColorArrayCube;
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid texture type {}", type);
|
throw NotImplementedException("Invalid texture type {}", type);
|
||||||
@@ -50,7 +53,7 @@ IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg reg, bool has_lod_clamp) {
|
|||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(base + 4), v.ir.Imm32(4), true));
|
v.ir.BitFieldExtract(value, v.ir.Imm32(base + 4), v.ir.Imm32(4), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
void TextureGatherImpl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<49, 1, u64> nodep;
|
BitField<49, 1, u64> nodep;
|
||||||
@@ -60,7 +63,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
|||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<8, 8, IR::Reg> coord_reg;
|
BitField<8, 8, IR::Reg> coord_reg;
|
||||||
BitField<20, 8, IR::Reg> derivative_reg;
|
BitField<20, 8, IR::Reg> derivative_reg;
|
||||||
BitField<28, 3, TextureType> type;
|
BitField<28, 3, TextureGradientType> type;
|
||||||
BitField<31, 4, u64> mask;
|
BitField<31, 4, u64> mask;
|
||||||
BitField<36, 13, u64> cbuf_offset;
|
BitField<36, 13, u64> cbuf_offset;
|
||||||
} const txd{insn};
|
} const txd{insn};
|
||||||
@@ -88,25 +91,25 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
|||||||
return v.ir.ConvertUToF(32, 16, array_index);
|
return v.ir.ConvertUToF(32, 16, array_index);
|
||||||
}};
|
}};
|
||||||
switch (txd.type) {
|
switch (txd.type) {
|
||||||
case TextureType::_1D: {
|
case TextureGradientType::_1D: {
|
||||||
coords = v.F(base_reg);
|
coords = v.F(base_reg);
|
||||||
num_derivatives = 1;
|
num_derivatives = 1;
|
||||||
last_reg = base_reg + 1;
|
last_reg = base_reg + 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TextureType::ARRAY_1D: {
|
case TextureGradientType::ARRAY_1D: {
|
||||||
last_reg = base_reg + 1;
|
last_reg = base_reg + 1;
|
||||||
coords = v.ir.CompositeConstruct(v.F(base_reg), read_array());
|
coords = v.ir.CompositeConstruct(v.F(base_reg), read_array());
|
||||||
num_derivatives = 1;
|
num_derivatives = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TextureType::_2D: {
|
case TextureGradientType::_2D: {
|
||||||
last_reg = base_reg + 2;
|
last_reg = base_reg + 2;
|
||||||
coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1));
|
coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1));
|
||||||
num_derivatives = 2;
|
num_derivatives = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TextureType::ARRAY_2D: {
|
case TextureGradientType::ARRAY_2D: {
|
||||||
last_reg = base_reg + 2;
|
last_reg = base_reg + 2;
|
||||||
coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1), read_array());
|
coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1), read_array());
|
||||||
num_derivatives = 2;
|
num_derivatives = 2;
|
||||||
@@ -170,11 +173,11 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
|||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
void TranslatorVisitor::TXD(u64 insn) {
|
void TranslatorVisitor::TXD(u64 insn) {
|
||||||
Impl(*this, insn, false);
|
TextureGatherImpl(*this, insn, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TranslatorVisitor::TXD_b(u64 insn) {
|
void TranslatorVisitor::TXD_b(u64 insn) {
|
||||||
Impl(*this, insn, true);
|
TextureGatherImpl(*this, insn, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Shader::Maxwell
|
} // namespace Shader::Maxwell
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -9,7 +12,7 @@
|
|||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
enum class TextureType : u64 {
|
enum class TextureLoadType : u64 {
|
||||||
_1D,
|
_1D,
|
||||||
ARRAY_1D,
|
ARRAY_1D,
|
||||||
_2D,
|
_2D,
|
||||||
@@ -20,77 +23,77 @@ enum class TextureType : u64 {
|
|||||||
ARRAY_CUBE,
|
ARRAY_CUBE,
|
||||||
};
|
};
|
||||||
|
|
||||||
Shader::TextureType GetType(TextureType type) {
|
Shader::TextureType GetType(TextureLoadType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TextureType::_1D:
|
case TextureLoadType::_1D:
|
||||||
return Shader::TextureType::Color1D;
|
return Shader::TextureType::Color1D;
|
||||||
case TextureType::ARRAY_1D:
|
case TextureLoadType::ARRAY_1D:
|
||||||
return Shader::TextureType::ColorArray1D;
|
return Shader::TextureType::ColorArray1D;
|
||||||
case TextureType::_2D:
|
case TextureLoadType::_2D:
|
||||||
return Shader::TextureType::Color2D;
|
return Shader::TextureType::Color2D;
|
||||||
case TextureType::ARRAY_2D:
|
case TextureLoadType::ARRAY_2D:
|
||||||
return Shader::TextureType::ColorArray2D;
|
return Shader::TextureType::ColorArray2D;
|
||||||
case TextureType::_3D:
|
case TextureLoadType::_3D:
|
||||||
return Shader::TextureType::Color3D;
|
return Shader::TextureType::Color3D;
|
||||||
case TextureType::ARRAY_3D:
|
case TextureLoadType::ARRAY_3D:
|
||||||
throw NotImplementedException("3D array texture type");
|
throw NotImplementedException("3D array texture type");
|
||||||
case TextureType::CUBE:
|
case TextureLoadType::CUBE:
|
||||||
return Shader::TextureType::ColorCube;
|
return Shader::TextureType::ColorCube;
|
||||||
case TextureType::ARRAY_CUBE:
|
case TextureLoadType::ARRAY_CUBE:
|
||||||
return Shader::TextureType::ColorArrayCube;
|
return Shader::TextureType::ColorArrayCube;
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid texture type {}", type);
|
throw NotImplementedException("Invalid texture type {}", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureType type) {
|
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureLoadType type) {
|
||||||
const auto read_array{
|
const auto read_array{
|
||||||
[&]() -> IR::U32 { return v.ir.BitFieldExtract(v.X(reg), v.ir.Imm32(0), v.ir.Imm32(16)); }};
|
[&]() -> IR::U32 { return v.ir.BitFieldExtract(v.X(reg), v.ir.Imm32(0), v.ir.Imm32(16)); }};
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TextureType::_1D:
|
case TextureLoadType::_1D:
|
||||||
return v.X(reg);
|
return v.X(reg);
|
||||||
case TextureType::ARRAY_1D:
|
case TextureLoadType::ARRAY_1D:
|
||||||
return v.ir.CompositeConstruct(v.X(reg + 1), read_array());
|
return v.ir.CompositeConstruct(v.X(reg + 1), read_array());
|
||||||
case TextureType::_2D:
|
case TextureLoadType::_2D:
|
||||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1));
|
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1));
|
||||||
case TextureType::ARRAY_2D:
|
case TextureLoadType::ARRAY_2D:
|
||||||
return v.ir.CompositeConstruct(v.X(reg + 1), v.X(reg + 2), read_array());
|
return v.ir.CompositeConstruct(v.X(reg + 1), v.X(reg + 2), read_array());
|
||||||
case TextureType::_3D:
|
case TextureLoadType::_3D:
|
||||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), v.X(reg + 2));
|
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), v.X(reg + 2));
|
||||||
case TextureType::ARRAY_3D:
|
case TextureLoadType::ARRAY_3D:
|
||||||
throw NotImplementedException("3D array texture type");
|
throw NotImplementedException("3D array texture type");
|
||||||
case TextureType::CUBE:
|
case TextureLoadType::CUBE:
|
||||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), v.X(reg + 2));
|
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), v.X(reg + 2));
|
||||||
case TextureType::ARRAY_CUBE:
|
case TextureLoadType::ARRAY_CUBE:
|
||||||
return v.ir.CompositeConstruct(v.X(reg + 1), v.X(reg + 2), v.X(reg + 3), read_array());
|
return v.ir.CompositeConstruct(v.X(reg + 1), v.X(reg + 2), v.X(reg + 3), read_array());
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid texture type {}", type);
|
throw NotImplementedException("Invalid texture type {}", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg& reg, TextureType type) {
|
IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg& reg, TextureLoadType type) {
|
||||||
const IR::U32 value{v.X(reg++)};
|
const IR::U32 value{v.X(reg++)};
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TextureType::_1D:
|
case TextureLoadType::_1D:
|
||||||
case TextureType::ARRAY_1D:
|
case TextureLoadType::ARRAY_1D:
|
||||||
return v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true);
|
return v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true);
|
||||||
case TextureType::_2D:
|
case TextureLoadType::_2D:
|
||||||
case TextureType::ARRAY_2D:
|
case TextureLoadType::ARRAY_2D:
|
||||||
return v.ir.CompositeConstruct(
|
return v.ir.CompositeConstruct(
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true),
|
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true),
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(4), v.ir.Imm32(4), true));
|
v.ir.BitFieldExtract(value, v.ir.Imm32(4), v.ir.Imm32(4), true));
|
||||||
case TextureType::_3D:
|
case TextureLoadType::_3D:
|
||||||
case TextureType::ARRAY_3D:
|
case TextureLoadType::ARRAY_3D:
|
||||||
return v.ir.CompositeConstruct(
|
return v.ir.CompositeConstruct(
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true),
|
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true),
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(4), v.ir.Imm32(4), true),
|
v.ir.BitFieldExtract(value, v.ir.Imm32(4), v.ir.Imm32(4), true),
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(8), v.ir.Imm32(4), true));
|
v.ir.BitFieldExtract(value, v.ir.Imm32(8), v.ir.Imm32(4), true));
|
||||||
case TextureType::CUBE:
|
case TextureLoadType::CUBE:
|
||||||
case TextureType::ARRAY_CUBE:
|
case TextureLoadType::ARRAY_CUBE:
|
||||||
throw NotImplementedException("Illegal offset on CUBE sample");
|
throw NotImplementedException("Illegal offset on CUBE sample");
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid texture type {}", type);
|
throw NotImplementedException("Invalid texture type {}", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
void TextureLoadImpl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<49, 1, u64> nodep;
|
BitField<49, 1, u64> nodep;
|
||||||
@@ -102,7 +105,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
|||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<8, 8, IR::Reg> coord_reg;
|
BitField<8, 8, IR::Reg> coord_reg;
|
||||||
BitField<20, 8, IR::Reg> meta_reg;
|
BitField<20, 8, IR::Reg> meta_reg;
|
||||||
BitField<28, 3, TextureType> type;
|
BitField<28, 3, TextureLoadType> type;
|
||||||
BitField<31, 4, u64> mask;
|
BitField<31, 4, u64> mask;
|
||||||
BitField<36, 13, u64> cbuf_offset;
|
BitField<36, 13, u64> cbuf_offset;
|
||||||
} const tld{insn};
|
} const tld{insn};
|
||||||
@@ -152,11 +155,11 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
|||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
void TranslatorVisitor::TLD(u64 insn) {
|
void TranslatorVisitor::TLD(u64 insn) {
|
||||||
Impl(*this, insn, false);
|
TextureLoadImpl(*this, insn, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TranslatorVisitor::TLD_b(u64 insn) {
|
void TranslatorVisitor::TLD_b(u64 insn) {
|
||||||
Impl(*this, insn, true);
|
TextureLoadImpl(*this, insn, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Shader::Maxwell
|
} // namespace Shader::Maxwell
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -10,38 +13,14 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class Precision : u64 {
|
enum class TextureLoadSwizzledPrecision : u64 {
|
||||||
F16,
|
F16,
|
||||||
F32,
|
F32,
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr unsigned R = 1;
|
union EncodinTLS {
|
||||||
constexpr unsigned G = 2;
|
|
||||||
constexpr unsigned B = 4;
|
|
||||||
constexpr unsigned A = 8;
|
|
||||||
|
|
||||||
constexpr std::array RG_LUT{
|
|
||||||
R, //
|
|
||||||
G, //
|
|
||||||
B, //
|
|
||||||
A, //
|
|
||||||
R | G, //
|
|
||||||
R | A, //
|
|
||||||
G | A, //
|
|
||||||
B | A, //
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr std::array RGBA_LUT{
|
|
||||||
R | G | B, //
|
|
||||||
R | G | A, //
|
|
||||||
R | B | A, //
|
|
||||||
G | B | A, //
|
|
||||||
R | G | B | A, //
|
|
||||||
};
|
|
||||||
|
|
||||||
union Encoding {
|
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<59, 1, Precision> precision;
|
BitField<59, 1, TextureLoadSwizzledPrecision> precision;
|
||||||
BitField<54, 1, u64> aoffi;
|
BitField<54, 1, u64> aoffi;
|
||||||
BitField<53, 1, u64> lod;
|
BitField<53, 1, u64> lod;
|
||||||
BitField<55, 1, u64> ms;
|
BitField<55, 1, u64> ms;
|
||||||
@@ -55,20 +34,20 @@ union Encoding {
|
|||||||
BitField<53, 4, u64> encoding;
|
BitField<53, 4, u64> encoding;
|
||||||
};
|
};
|
||||||
|
|
||||||
void CheckAlignment(IR::Reg reg, size_t alignment) {
|
void CheckAlignmentTLS(IR::Reg reg, size_t alignment) {
|
||||||
if (!IR::IsAligned(reg, alignment)) {
|
if (!IR::IsAligned(reg, alignment)) {
|
||||||
throw NotImplementedException("Unaligned source register {}", reg);
|
throw NotImplementedException("Unaligned source register {}", reg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg reg) {
|
IR::Value MakeLoadOffset(TranslatorVisitor& v, IR::Reg reg) {
|
||||||
const IR::U32 value{v.X(reg)};
|
const IR::U32 value{v.X(reg)};
|
||||||
return v.ir.CompositeConstruct(v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true),
|
return v.ir.CompositeConstruct(v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true),
|
||||||
v.ir.BitFieldExtract(value, v.ir.Imm32(4), v.ir.Imm32(4), true));
|
v.ir.BitFieldExtract(value, v.ir.Imm32(4), v.ir.Imm32(4), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
IR::Value SampleTLS(TranslatorVisitor& v, u64 insn) {
|
||||||
const Encoding tlds{insn};
|
const EncodinTLS tlds{insn};
|
||||||
const IR::U32 handle{v.ir.Imm32(static_cast<u32>(tlds.cbuf_offset * 4))};
|
const IR::U32 handle{v.ir.Imm32(static_cast<u32>(tlds.cbuf_offset * 4))};
|
||||||
const IR::Reg reg_a{tlds.src_reg_a};
|
const IR::Reg reg_a{tlds.src_reg_a};
|
||||||
const IR::Reg reg_b{tlds.src_reg_b};
|
const IR::Reg reg_b{tlds.src_reg_b};
|
||||||
@@ -92,56 +71,81 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
|||||||
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_b));
|
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_b));
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTLS(reg_a, 2);
|
||||||
texture_type = Shader::TextureType::Color2D;
|
texture_type = Shader::TextureType::Color2D;
|
||||||
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1));
|
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1));
|
||||||
offsets = MakeOffset(v, reg_b);
|
offsets = MakeLoadOffset(v, reg_b);
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTLS(reg_a, 2);
|
||||||
texture_type = Shader::TextureType::Color2D;
|
texture_type = Shader::TextureType::Color2D;
|
||||||
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1));
|
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1));
|
||||||
lod = v.X(reg_b);
|
lod = v.X(reg_b);
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTLS(reg_a, 2);
|
||||||
texture_type = Shader::TextureType::Color2D;
|
texture_type = Shader::TextureType::Color2D;
|
||||||
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1));
|
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1));
|
||||||
multisample = v.X(reg_b);
|
multisample = v.X(reg_b);
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTLS(reg_a, 2);
|
||||||
texture_type = Shader::TextureType::Color3D;
|
texture_type = Shader::TextureType::Color3D;
|
||||||
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1), v.X(reg_b));
|
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1), v.X(reg_b));
|
||||||
break;
|
break;
|
||||||
case 8: {
|
case 8: {
|
||||||
CheckAlignment(reg_b, 2);
|
CheckAlignmentTLS(reg_b, 2);
|
||||||
const IR::U32 array{v.ir.BitFieldExtract(v.X(reg_a), v.ir.Imm32(0), v.ir.Imm32(16))};
|
const IR::U32 array{v.ir.BitFieldExtract(v.X(reg_a), v.ir.Imm32(0), v.ir.Imm32(16))};
|
||||||
texture_type = Shader::TextureType::ColorArray2D;
|
texture_type = Shader::TextureType::ColorArray2D;
|
||||||
coords = v.ir.CompositeConstruct(v.X(reg_b), v.X(reg_b + 1), array);
|
coords = v.ir.CompositeConstruct(v.X(reg_b), v.X(reg_b + 1), array);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 12:
|
case 12:
|
||||||
CheckAlignment(reg_a, 2);
|
CheckAlignmentTLS(reg_a, 2);
|
||||||
CheckAlignment(reg_b, 2);
|
CheckAlignmentTLS(reg_b, 2);
|
||||||
texture_type = Shader::TextureType::Color2D;
|
texture_type = Shader::TextureType::Color2D;
|
||||||
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1));
|
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1));
|
||||||
lod = v.X(reg_b);
|
lod = v.X(reg_b);
|
||||||
offsets = MakeOffset(v, reg_b + 1);
|
offsets = MakeLoadOffset(v, reg_b + 1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw NotImplementedException("Illegal encoding {}", tlds.encoding.Value());
|
throw NotImplementedException("Illegal encoding {}", tlds.encoding.Value());
|
||||||
}
|
}
|
||||||
IR::TextureInstInfo info{};
|
IR::TextureInstInfo info{};
|
||||||
if (tlds.precision == Precision::F16) {
|
if (tlds.precision == TextureLoadSwizzledPrecision::F16) {
|
||||||
info.relaxed_precision.Assign(1);
|
info.relaxed_precision.Assign(1);
|
||||||
}
|
}
|
||||||
info.type.Assign(texture_type);
|
info.type.Assign(texture_type);
|
||||||
return v.ir.ImageFetch(handle, coords, offsets, lod, multisample, info);
|
return v.ir.ImageFetch(handle, coords, offsets, lod, multisample, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned Swizzle(u64 insn) {
|
unsigned LoadSwizzle(u64 insn) {
|
||||||
const Encoding tlds{insn};
|
#define R 1
|
||||||
|
#define G 2
|
||||||
|
#define B 4
|
||||||
|
#define A 8
|
||||||
|
static constexpr std::array<unsigned, 8> RG_LUT{
|
||||||
|
R, //
|
||||||
|
G, //
|
||||||
|
B, //
|
||||||
|
A, //
|
||||||
|
R | G, //
|
||||||
|
R | A, //
|
||||||
|
G | A, //
|
||||||
|
B | A, //
|
||||||
|
};
|
||||||
|
static constexpr std::array<unsigned, 5> RGBA_LUT{
|
||||||
|
R | G | B, //
|
||||||
|
R | G | A, //
|
||||||
|
R | B | A, //
|
||||||
|
G | B | A, //
|
||||||
|
R | G | B | A, //
|
||||||
|
};
|
||||||
|
#undef R
|
||||||
|
#undef G
|
||||||
|
#undef B
|
||||||
|
#undef A
|
||||||
|
const EncodinTLS tlds{insn};
|
||||||
const size_t encoding{tlds.swizzle};
|
const size_t encoding{tlds.swizzle};
|
||||||
if (tlds.dest_reg_b == IR::Reg::RZ) {
|
if (tlds.dest_reg_b == IR::Reg::RZ) {
|
||||||
if (encoding >= RG_LUT.size()) {
|
if (encoding >= RG_LUT.size()) {
|
||||||
@@ -156,73 +160,73 @@ unsigned Swizzle(u64 insn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::F32 Extract(TranslatorVisitor& v, const IR::Value& sample, unsigned component) {
|
IR::F32 LoadExtract(TranslatorVisitor& v, const IR::Value& sample, unsigned component) {
|
||||||
return IR::F32{v.ir.CompositeExtract(sample, component)};
|
return IR::F32{v.ir.CompositeExtract(sample, component)};
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Reg RegStoreComponent32(u64 insn, unsigned index) {
|
IR::Reg LoadRegStoreComponent32(u64 insn, unsigned index) {
|
||||||
const Encoding tlds{insn};
|
const EncodinTLS tlds{insn};
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
return tlds.dest_reg_a;
|
return tlds.dest_reg_a;
|
||||||
case 1:
|
case 1:
|
||||||
CheckAlignment(tlds.dest_reg_a, 2);
|
CheckAlignmentTLS(tlds.dest_reg_a, 2);
|
||||||
return tlds.dest_reg_a + 1;
|
return tlds.dest_reg_a + 1;
|
||||||
case 2:
|
case 2:
|
||||||
return tlds.dest_reg_b;
|
return tlds.dest_reg_b;
|
||||||
case 3:
|
case 3:
|
||||||
CheckAlignment(tlds.dest_reg_b, 2);
|
CheckAlignmentTLS(tlds.dest_reg_b, 2);
|
||||||
return tlds.dest_reg_b + 1;
|
return tlds.dest_reg_b + 1;
|
||||||
}
|
}
|
||||||
throw LogicError("Invalid store index {}", index);
|
throw LogicError("Invalid store index {}", index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Store32(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
void Store32TLS(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||||
const unsigned swizzle{Swizzle(insn)};
|
const unsigned swizzle{LoadSwizzle(insn)};
|
||||||
unsigned store_index{0};
|
unsigned store_index{0};
|
||||||
for (unsigned component = 0; component < 4; ++component) {
|
for (unsigned component = 0; component < 4; ++component) {
|
||||||
if (((swizzle >> component) & 1) == 0) {
|
if (((swizzle >> component) & 1) == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const IR::Reg dest{RegStoreComponent32(insn, store_index)};
|
const IR::Reg dest{LoadRegStoreComponent32(insn, store_index)};
|
||||||
v.F(dest, Extract(v, sample, component));
|
v.F(dest, LoadExtract(v, sample, component));
|
||||||
++store_index;
|
++store_index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U32 Pack(TranslatorVisitor& v, const IR::F32& lhs, const IR::F32& rhs) {
|
IR::U32 PackTLS(TranslatorVisitor& v, const IR::F32& lhs, const IR::F32& rhs) {
|
||||||
return v.ir.PackHalf2x16(v.ir.CompositeConstruct(lhs, rhs));
|
return v.ir.PackHalf2x16(v.ir.CompositeConstruct(lhs, rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Store16(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
void Store16TLS(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||||
const unsigned swizzle{Swizzle(insn)};
|
const unsigned swizzle{LoadSwizzle(insn)};
|
||||||
unsigned store_index{0};
|
unsigned store_index{0};
|
||||||
std::array<IR::F32, 4> swizzled;
|
std::array<IR::F32, 4> swizzled;
|
||||||
for (unsigned component = 0; component < 4; ++component) {
|
for (unsigned component = 0; component < 4; ++component) {
|
||||||
if (((swizzle >> component) & 1) == 0) {
|
if (((swizzle >> component) & 1) == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
swizzled[store_index] = Extract(v, sample, component);
|
swizzled[store_index] = LoadExtract(v, sample, component);
|
||||||
++store_index;
|
++store_index;
|
||||||
}
|
}
|
||||||
const IR::F32 zero{v.ir.Imm32(0.0f)};
|
const IR::F32 zero{v.ir.Imm32(0.0f)};
|
||||||
const Encoding tlds{insn};
|
const EncodinTLS tlds{insn};
|
||||||
switch (store_index) {
|
switch (store_index) {
|
||||||
case 1:
|
case 1:
|
||||||
v.X(tlds.dest_reg_a, Pack(v, swizzled[0], zero));
|
v.X(tlds.dest_reg_a, PackTLS(v, swizzled[0], zero));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
case 4:
|
case 4:
|
||||||
v.X(tlds.dest_reg_a, Pack(v, swizzled[0], swizzled[1]));
|
v.X(tlds.dest_reg_a, PackTLS(v, swizzled[0], swizzled[1]));
|
||||||
switch (store_index) {
|
switch (store_index) {
|
||||||
case 2:
|
case 2:
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
v.X(tlds.dest_reg_b, Pack(v, swizzled[2], zero));
|
v.X(tlds.dest_reg_b, PackTLS(v, swizzled[2], zero));
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
v.X(tlds.dest_reg_b, Pack(v, swizzled[2], swizzled[3]));
|
v.X(tlds.dest_reg_b, PackTLS(v, swizzled[2], swizzled[3]));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -231,11 +235,11 @@ void Store16(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
|||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
void TranslatorVisitor::TLDS(u64 insn) {
|
void TranslatorVisitor::TLDS(u64 insn) {
|
||||||
const IR::Value sample{Sample(*this, insn)};
|
const IR::Value sample{SampleTLS(*this, insn)};
|
||||||
if (Encoding{insn}.precision == Precision::F32) {
|
if (EncodinTLS{insn}.precision == TextureLoadSwizzledPrecision::F32) {
|
||||||
Store32(*this, insn, sample);
|
Store32TLS(*this, insn, sample);
|
||||||
} else {
|
} else {
|
||||||
Store16(*this, insn, sample);
|
Store16TLS(*this, insn, sample);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace Shader::Maxwell
|
} // namespace Shader::Maxwell
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -9,7 +12,7 @@
|
|||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
enum class TextureType : u64 {
|
enum class TextureMipmapLevelType : u64 {
|
||||||
_1D,
|
_1D,
|
||||||
ARRAY_1D,
|
ARRAY_1D,
|
||||||
_2D,
|
_2D,
|
||||||
@@ -20,53 +23,53 @@ enum class TextureType : u64 {
|
|||||||
ARRAY_CUBE,
|
ARRAY_CUBE,
|
||||||
};
|
};
|
||||||
|
|
||||||
Shader::TextureType GetType(TextureType type) {
|
Shader::TextureType GetType(TextureMipmapLevelType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TextureType::_1D:
|
case TextureMipmapLevelType::_1D:
|
||||||
return Shader::TextureType::Color1D;
|
return Shader::TextureType::Color1D;
|
||||||
case TextureType::ARRAY_1D:
|
case TextureMipmapLevelType::ARRAY_1D:
|
||||||
return Shader::TextureType::ColorArray1D;
|
return Shader::TextureType::ColorArray1D;
|
||||||
case TextureType::_2D:
|
case TextureMipmapLevelType::_2D:
|
||||||
return Shader::TextureType::Color2D;
|
return Shader::TextureType::Color2D;
|
||||||
case TextureType::ARRAY_2D:
|
case TextureMipmapLevelType::ARRAY_2D:
|
||||||
return Shader::TextureType::ColorArray2D;
|
return Shader::TextureType::ColorArray2D;
|
||||||
case TextureType::_3D:
|
case TextureMipmapLevelType::_3D:
|
||||||
return Shader::TextureType::Color3D;
|
return Shader::TextureType::Color3D;
|
||||||
case TextureType::ARRAY_3D:
|
case TextureMipmapLevelType::ARRAY_3D:
|
||||||
throw NotImplementedException("3D array texture type");
|
throw NotImplementedException("3D array texture type");
|
||||||
case TextureType::CUBE:
|
case TextureMipmapLevelType::CUBE:
|
||||||
return Shader::TextureType::ColorCube;
|
return Shader::TextureType::ColorCube;
|
||||||
case TextureType::ARRAY_CUBE:
|
case TextureMipmapLevelType::ARRAY_CUBE:
|
||||||
return Shader::TextureType::ColorArrayCube;
|
return Shader::TextureType::ColorArrayCube;
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid texture type {}", type);
|
throw NotImplementedException("Invalid texture type {}", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureType type) {
|
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureMipmapLevelType type) {
|
||||||
// The ISA reads an array component here, but this is not needed on high level shading languages
|
// The ISA reads an array component here, but this is not needed on high level shading languages
|
||||||
// We are dropping this information.
|
// We are dropping this information.
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TextureType::_1D:
|
case TextureMipmapLevelType::_1D:
|
||||||
return v.F(reg);
|
return v.F(reg);
|
||||||
case TextureType::ARRAY_1D:
|
case TextureMipmapLevelType::ARRAY_1D:
|
||||||
return v.F(reg + 1);
|
return v.F(reg + 1);
|
||||||
case TextureType::_2D:
|
case TextureMipmapLevelType::_2D:
|
||||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1));
|
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1));
|
||||||
case TextureType::ARRAY_2D:
|
case TextureMipmapLevelType::ARRAY_2D:
|
||||||
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2));
|
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2));
|
||||||
case TextureType::_3D:
|
case TextureMipmapLevelType::_3D:
|
||||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
||||||
case TextureType::ARRAY_3D:
|
case TextureMipmapLevelType::ARRAY_3D:
|
||||||
throw NotImplementedException("3D array texture type");
|
throw NotImplementedException("3D array texture type");
|
||||||
case TextureType::CUBE:
|
case TextureMipmapLevelType::CUBE:
|
||||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
||||||
case TextureType::ARRAY_CUBE:
|
case TextureMipmapLevelType::ARRAY_CUBE:
|
||||||
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2), v.F(reg + 3));
|
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2), v.F(reg + 3));
|
||||||
}
|
}
|
||||||
throw NotImplementedException("Invalid texture type {}", type);
|
throw NotImplementedException("Invalid texture type {}", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
void TextureMipmapLevelImpl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<49, 1, u64> nodep;
|
BitField<49, 1, u64> nodep;
|
||||||
@@ -74,7 +77,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
|||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<8, 8, IR::Reg> coord_reg;
|
BitField<8, 8, IR::Reg> coord_reg;
|
||||||
BitField<20, 8, IR::Reg> meta_reg;
|
BitField<20, 8, IR::Reg> meta_reg;
|
||||||
BitField<28, 3, TextureType> type;
|
BitField<28, 3, TextureMipmapLevelType> type;
|
||||||
BitField<31, 4, u64> mask;
|
BitField<31, 4, u64> mask;
|
||||||
BitField<36, 13, u64> cbuf_offset;
|
BitField<36, 13, u64> cbuf_offset;
|
||||||
} const tmml{insn};
|
} const tmml{insn};
|
||||||
@@ -113,11 +116,11 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
|||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
void TranslatorVisitor::TMML(u64 insn) {
|
void TranslatorVisitor::TMML(u64 insn) {
|
||||||
Impl(*this, insn, false);
|
TextureMipmapLevelImpl(*this, insn, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TranslatorVisitor::TMML_b(u64 insn) {
|
void TranslatorVisitor::TMML_b(u64 insn) {
|
||||||
Impl(*this, insn, true);
|
TextureMipmapLevelImpl(*this, insn, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Shader::Maxwell
|
} // namespace Shader::Maxwell
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -9,24 +12,24 @@
|
|||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
enum class Mode : u64 {
|
enum class TextureQueryMode : u64 {
|
||||||
Dimension = 1,
|
Dimension = 1,
|
||||||
TextureType = 2,
|
TextureType = 2,
|
||||||
SamplePos = 5,
|
SamplePos = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
IR::Value Query(TranslatorVisitor& v, const IR::U32& handle, Mode mode, IR::Reg src_reg, u64 mask) {
|
IR::Value Query(TranslatorVisitor& v, const IR::U32& handle, TextureQueryMode mode, IR::Reg src_reg, u64 mask) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case Mode::Dimension: {
|
case TextureQueryMode::Dimension: {
|
||||||
const bool needs_num_mips{((mask >> 3) & 1) != 0};
|
const bool needs_num_mips{((mask >> 3) & 1) != 0};
|
||||||
const IR::U1 skip_mips{v.ir.Imm1(!needs_num_mips)};
|
const IR::U1 skip_mips{v.ir.Imm1(!needs_num_mips)};
|
||||||
const IR::U32 lod{v.X(src_reg)};
|
const IR::U32 lod{v.X(src_reg)};
|
||||||
return v.ir.ImageQueryDimension(handle, lod, skip_mips);
|
return v.ir.ImageQueryDimension(handle, lod, skip_mips);
|
||||||
}
|
}
|
||||||
case Mode::TextureType:
|
case TextureQueryMode::TextureType:
|
||||||
case Mode::SamplePos:
|
case TextureQueryMode::SamplePos:
|
||||||
default:
|
default:
|
||||||
throw NotImplementedException("Mode {}", mode);
|
throw NotImplementedException("TextureQueryMode {}", mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +39,7 @@ void Impl(TranslatorVisitor& v, u64 insn, std::optional<u32> cbuf_offset) {
|
|||||||
BitField<49, 1, u64> nodep;
|
BitField<49, 1, u64> nodep;
|
||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<8, 8, IR::Reg> src_reg;
|
BitField<8, 8, IR::Reg> src_reg;
|
||||||
BitField<22, 3, Mode> mode;
|
BitField<22, 3, TextureQueryMode> mode;
|
||||||
BitField<31, 4, u64> mask;
|
BitField<31, 4, u64> mask;
|
||||||
} const txq{insn};
|
} const txq{insn};
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -6,7 +9,7 @@
|
|||||||
|
|
||||||
namespace Shader::Optimization {
|
namespace Shader::Optimization {
|
||||||
namespace {
|
namespace {
|
||||||
IR::Opcode Replace(IR::Opcode op) {
|
IR::Opcode ReplaceFP16ToFP32(IR::Opcode op) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case IR::Opcode::FPAbs16:
|
case IR::Opcode::FPAbs16:
|
||||||
return IR::Opcode::FPAbs32;
|
return IR::Opcode::FPAbs32;
|
||||||
@@ -131,7 +134,7 @@ IR::Opcode Replace(IR::Opcode op) {
|
|||||||
void LowerFp16ToFp32(IR::Program& program) {
|
void LowerFp16ToFp32(IR::Program& program) {
|
||||||
for (IR::Block* const block : program.blocks) {
|
for (IR::Block* const block : program.blocks) {
|
||||||
for (IR::Inst& inst : block->Instructions()) {
|
for (IR::Inst& inst : block->Instructions()) {
|
||||||
inst.ReplaceOpcode(Replace(inst.GetOpcode()));
|
inst.ReplaceOpcode(ReplaceFP16ToFP32(inst.GetOpcode()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user