Compare commits
4 commits
master
...
fix-fibers
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91bba6825d | ||
|
|
6d9ba6af39 | ||
|
|
387dd95404 | ||
|
|
0c77f965db |
14 changed files with 350 additions and 2402 deletions
|
|
@ -183,8 +183,7 @@ option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
|
||||||
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
|
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
|
||||||
set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries")
|
set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries")
|
||||||
|
|
||||||
# FreeBSD doesn't have a cubeb port yet, vendoring it isn't required (it's optional anyways)
|
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
||||||
cmake_dependent_option(ENABLE_CUBEB "Enables the cubeb audio backend" ON "NOT PLATFORM_FREEBSD" OFF)
|
|
||||||
|
|
||||||
set(EXT_DEFAULT OFF)
|
set(EXT_DEFAULT OFF)
|
||||||
if (MSVC OR ANDROID)
|
if (MSVC OR ANDROID)
|
||||||
|
|
@ -199,8 +198,7 @@ cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from source" "${PL
|
||||||
# sirit
|
# sirit
|
||||||
option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${EXT_DEFAULT})
|
option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${EXT_DEFAULT})
|
||||||
|
|
||||||
# Re-allow on FreeBSD once its on mainline ports
|
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "NOT ANDROID" OFF)
|
||||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR PLATFORM_LINUX OR APPLE" OFF)
|
|
||||||
|
|
||||||
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT WIN32 OR NOT ARCHITECTURE_arm64" OFF)
|
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT WIN32 OR NOT ARCHITECTURE_arm64" OFF)
|
||||||
mark_as_advanced(FORCE ENABLE_OPENGL)
|
mark_as_advanced(FORCE ENABLE_OPENGL)
|
||||||
|
|
@ -477,6 +475,8 @@ if (YUZU_USE_CPM)
|
||||||
target_compile_options(boost_icl INTERFACE -Wno-shadow)
|
target_compile_options(boost_icl INTERFACE -Wno-shadow)
|
||||||
target_compile_options(boost_asio INTERFACE -Wno-conversion -Wno-implicit-fallthrough)
|
target_compile_options(boost_asio INTERFACE -Wno-conversion -Wno-implicit-fallthrough)
|
||||||
endif()
|
endif()
|
||||||
|
elseif (PLATFORM_LINUX OR APPLE)
|
||||||
|
find_package(Boost 1.57.0 REQUIRED headers context system fiber)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# fmt
|
# fmt
|
||||||
|
|
@ -539,7 +539,11 @@ else()
|
||||||
find_package(zstd 1.5 REQUIRED MODULE)
|
find_package(zstd 1.5 REQUIRED MODULE)
|
||||||
|
|
||||||
# wow
|
# wow
|
||||||
find_package(Boost 1.57.0 CONFIG REQUIRED OPTIONAL_COMPONENTS headers context system fiber)
|
if (PLATFORM_LINUX OR APPLE)
|
||||||
|
find_package(Boost 1.57.0 REQUIRED headers context system fiber)
|
||||||
|
else()
|
||||||
|
find_package(Boost 1.57.0 REQUIRED)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR ANDROID)
|
if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR ANDROID)
|
||||||
find_package(gamemode 1.7 MODULE)
|
find_package(gamemode 1.7 MODULE)
|
||||||
|
|
|
||||||
|
|
@ -258,6 +258,10 @@ else()
|
||||||
target_link_libraries(common PUBLIC Boost::headers)
|
target_link_libraries(common PUBLIC Boost::headers)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (TARGET Boost::context)
|
||||||
|
target_link_libraries(common PUBLIC Boost::context)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (lz4_ADDED)
|
if (lz4_ADDED)
|
||||||
target_include_directories(common PRIVATE ${lz4_SOURCE_DIR}/lib)
|
target_include_directories(common PRIVATE ${lz4_SOURCE_DIR}/lib)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|
@ -5,47 +8,87 @@
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/fiber.h"
|
#include "common/fiber.h"
|
||||||
#define MCO_USE_VMEM_ALLOCATOR
|
#include "common/virtual_buffer.h"
|
||||||
#define MINICORO_IMPL
|
|
||||||
#include "common/minicoro.h"
|
#include <boost/context/detail/fcontext.hpp>
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
|
constexpr std::size_t default_stack_size = 512 * 1024;
|
||||||
|
|
||||||
struct Fiber::FiberImpl {
|
struct Fiber::FiberImpl {
|
||||||
FiberImpl() {}
|
FiberImpl() : stack{default_stack_size}, rewind_stack{default_stack_size} {}
|
||||||
|
|
||||||
|
VirtualBuffer<u8> stack;
|
||||||
|
VirtualBuffer<u8> rewind_stack;
|
||||||
|
|
||||||
std::mutex guard;
|
std::mutex guard;
|
||||||
bool released{};
|
|
||||||
bool is_thread_fiber{};
|
|
||||||
Fiber* next_fiber{};
|
|
||||||
Fiber** next_fiber_ptr;
|
|
||||||
std::function<void()> entry_point;
|
std::function<void()> entry_point;
|
||||||
|
std::function<void()> rewind_point;
|
||||||
|
std::shared_ptr<Fiber> previous_fiber;
|
||||||
|
bool is_thread_fiber{};
|
||||||
|
bool released{};
|
||||||
|
|
||||||
mco_coro* context;
|
u8* stack_limit{};
|
||||||
|
u8* rewind_stack_limit{};
|
||||||
|
boost::context::detail::fcontext_t context{};
|
||||||
|
boost::context::detail::fcontext_t rewind_context{};
|
||||||
};
|
};
|
||||||
|
|
||||||
Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {
|
void Fiber::SetRewindPoint(std::function<void()>&& rewind_func) {
|
||||||
impl->is_thread_fiber = true;
|
impl->rewind_point = std::move(rewind_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fiber::Start(boost::context::detail::transfer_t& transfer) {
|
||||||
|
ASSERT(impl->previous_fiber != nullptr);
|
||||||
|
impl->previous_fiber->impl->context = transfer.fctx;
|
||||||
|
impl->previous_fiber->impl->guard.unlock();
|
||||||
|
impl->previous_fiber.reset();
|
||||||
|
impl->entry_point();
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transfer) {
|
||||||
|
ASSERT(impl->context != nullptr);
|
||||||
|
impl->context = impl->rewind_context;
|
||||||
|
impl->rewind_context = nullptr;
|
||||||
|
u8* tmp = impl->stack_limit;
|
||||||
|
impl->stack_limit = impl->rewind_stack_limit;
|
||||||
|
impl->rewind_stack_limit = tmp;
|
||||||
|
impl->rewind_point();
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) {
|
||||||
|
auto* fiber = static_cast<Fiber*>(transfer.data);
|
||||||
|
fiber->Start(transfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) {
|
||||||
|
auto* fiber = static_cast<Fiber*>(transfer.data);
|
||||||
|
fiber->OnRewind(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Fiber::Fiber(std::function<void()>&& entry_point_func) : impl{std::make_unique<FiberImpl>()} {
|
Fiber::Fiber(std::function<void()>&& entry_point_func) : impl{std::make_unique<FiberImpl>()} {
|
||||||
impl->entry_point = std::move(entry_point_func);
|
impl->entry_point = std::move(entry_point_func);
|
||||||
auto desc = mco_desc_init(
|
impl->stack_limit = impl->stack.data();
|
||||||
[](mco_coro* coro) { reinterpret_cast<Fiber*>(coro->user_data)->impl->entry_point(); }, 0);
|
impl->rewind_stack_limit = impl->rewind_stack.data();
|
||||||
desc.user_data = this;
|
u8* stack_base = impl->stack_limit + default_stack_size;
|
||||||
mco_result res = mco_create(&impl->context, &desc);
|
impl->context =
|
||||||
ASSERT(res == MCO_SUCCESS);
|
boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
|
||||||
|
|
||||||
Fiber::~Fiber() {
|
Fiber::~Fiber() {
|
||||||
if (impl->released) {
|
if (impl->released) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DestroyPre();
|
// Make sure the Fiber is not being used
|
||||||
if (impl->is_thread_fiber) {
|
const bool locked = impl->guard.try_lock();
|
||||||
DestroyThreadFiber();
|
ASSERT_MSG(locked, "Destroying a fiber that's still running");
|
||||||
} else {
|
if (locked) {
|
||||||
DestroyWorkFiber();
|
impl->guard.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,66 +97,42 @@ void Fiber::Exit() {
|
||||||
if (!impl->is_thread_fiber) {
|
if (!impl->is_thread_fiber) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DestroyPre();
|
|
||||||
DestroyThreadFiber();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Fiber::DestroyPre() {
|
|
||||||
// Make sure the Fiber is not being used
|
|
||||||
const bool locked = impl->guard.try_lock();
|
|
||||||
ASSERT_MSG(locked, "Destroying a fiber that's still running");
|
|
||||||
if (locked) {
|
|
||||||
impl->guard.unlock();
|
impl->guard.unlock();
|
||||||
}
|
|
||||||
impl->released = true;
|
impl->released = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fiber::DestroyWorkFiber() {
|
void Fiber::Rewind() {
|
||||||
mco_result res = mco_destroy(impl->context);
|
ASSERT(impl->rewind_point);
|
||||||
ASSERT(res == MCO_SUCCESS);
|
ASSERT(impl->rewind_context == nullptr);
|
||||||
}
|
u8* stack_base = impl->rewind_stack_limit + default_stack_size;
|
||||||
|
impl->rewind_context =
|
||||||
void Fiber::DestroyThreadFiber() {
|
boost::context::detail::make_fcontext(stack_base, impl->stack.size(), RewindStartFunc);
|
||||||
if (*impl->next_fiber_ptr) {
|
boost::context::detail::jump_fcontext(impl->rewind_context, this);
|
||||||
*impl->next_fiber_ptr = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fiber::YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to) {
|
void Fiber::YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to) {
|
||||||
|
to.impl->guard.lock();
|
||||||
|
to.impl->previous_fiber = weak_from.lock();
|
||||||
|
|
||||||
|
auto transfer = boost::context::detail::jump_fcontext(to.impl->context, &to);
|
||||||
|
|
||||||
|
// "from" might no longer be valid if the thread was killed
|
||||||
if (auto from = weak_from.lock()) {
|
if (auto from = weak_from.lock()) {
|
||||||
if (!from->impl->is_thread_fiber) {
|
if (from->impl->previous_fiber == nullptr) {
|
||||||
// Set next fiber
|
ASSERT_MSG(false, "previous_fiber is nullptr!");
|
||||||
from->impl->next_fiber = &to;
|
return;
|
||||||
// Yield from thread
|
|
||||||
if (!from->impl->released) {
|
|
||||||
from->impl->guard.unlock();
|
|
||||||
mco_yield(from->impl->context);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
from->impl->guard.lock();
|
|
||||||
// Keep running next fiber until they've ran out
|
|
||||||
auto& next_fiber_ptr = from->impl->next_fiber_ptr;
|
|
||||||
next_fiber_ptr = &from->impl->next_fiber;
|
|
||||||
*next_fiber_ptr = &to;
|
|
||||||
for ([[maybe_unused]] unsigned round = 0; *next_fiber_ptr; round++) {
|
|
||||||
auto next = *next_fiber_ptr;
|
|
||||||
*next_fiber_ptr = nullptr;
|
|
||||||
next_fiber_ptr = &next->impl->next_fiber;
|
|
||||||
// Stop if new thread is thread fiber
|
|
||||||
if (next->impl->is_thread_fiber)
|
|
||||||
break;
|
|
||||||
// Resume new thread
|
|
||||||
next->impl->guard.lock();
|
|
||||||
mco_result res = mco_resume(next->impl->context);
|
|
||||||
ASSERT(res == MCO_SUCCESS);
|
|
||||||
}
|
|
||||||
from->impl->guard.unlock();
|
|
||||||
}
|
}
|
||||||
|
from->impl->previous_fiber->impl->context = transfer.fctx;
|
||||||
|
from->impl->previous_fiber->impl->guard.unlock();
|
||||||
|
from->impl->previous_fiber.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
|
std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
|
||||||
return std::shared_ptr<Fiber>{new Fiber()};
|
std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()};
|
||||||
|
fiber->impl->guard.lock();
|
||||||
|
fiber->impl->is_thread_fiber = true;
|
||||||
|
return fiber;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|
@ -6,7 +9,9 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "common/minicoro.h"
|
namespace boost::context::detail {
|
||||||
|
struct transfer_t;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
|
|
@ -36,18 +41,25 @@ public:
|
||||||
Fiber(Fiber&&) = default;
|
Fiber(Fiber&&) = default;
|
||||||
Fiber& operator=(Fiber&&) = default;
|
Fiber& operator=(Fiber&&) = default;
|
||||||
|
|
||||||
|
/// Yields control from Fiber 'from' to Fiber 'to'
|
||||||
|
/// Fiber 'from' must be the currently running fiber.
|
||||||
static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to);
|
static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to);
|
||||||
[[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
|
[[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
|
||||||
|
|
||||||
|
void SetRewindPoint(std::function<void()>&& rewind_func);
|
||||||
|
|
||||||
|
void Rewind();
|
||||||
|
|
||||||
/// Only call from main thread's fiber
|
/// Only call from main thread's fiber
|
||||||
void Exit();
|
void Exit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Fiber();
|
Fiber();
|
||||||
|
|
||||||
void DestroyPre();
|
void OnRewind(boost::context::detail::transfer_t& transfer);
|
||||||
void DestroyWorkFiber();
|
void Start(boost::context::detail::transfer_t& transfer);
|
||||||
void DestroyThreadFiber();
|
static void FiberStartFunc(boost::context::detail::transfer_t transfer);
|
||||||
|
static void RewindStartFunc(boost::context::detail::transfer_t transfer);
|
||||||
|
|
||||||
struct FiberImpl;
|
struct FiberImpl;
|
||||||
std::unique_ptr<FiberImpl> impl;
|
std::unique_ptr<FiberImpl> impl;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,3 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
* Copyright (c) 2022 MerryMage
|
* Copyright (c) 2022 MerryMage
|
||||||
* SPDX-License-Identifier: 0BSD
|
* SPDX-License-Identifier: 0BSD
|
||||||
|
|
@ -569,49 +566,37 @@ void EmitIR<IR::Opcode::FPVectorRecipStepFused64>(oaknut::CodeGenerator& code, E
|
||||||
EmitThreeOpArranged<64>(code, ctx, inst, [&](auto Vresult, auto Va, auto Vb) { code.FRECPS(Vresult, Va, Vb); });
|
EmitThreeOpArranged<64>(code, ctx, inst, [&](auto Vresult, auto Va, auto Vb) { code.FRECPS(Vresult, Va, Vb); });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Assembly thunk "parameters" are in template parameters
|
|
||||||
/// TODO: we have space for a 5th parameter? :)
|
|
||||||
template<typename FPT, FP::RoundingMode rounding_mode, bool exact>
|
|
||||||
static void EmitIRVectorRoundInt16Thunk(VectorArray<FPT>& output, const VectorArray<FPT>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
|
|
||||||
for (size_t i = 0; i < output.size(); ++i)
|
|
||||||
output[i] = FPT(FP::FPRoundInt<FPT>(input[i], fpcr, rounding_mode, exact, fpsr));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void EmitIR<IR::Opcode::FPVectorRoundInt16>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::FPVectorRoundInt16>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
const auto rounding = FP::RoundingMode(inst->GetArg(1).GetU8());
|
const auto rounding = static_cast<FP::RoundingMode>(inst->GetArg(1).GetU8());
|
||||||
const bool exact = inst->GetArg(2).GetU1();
|
const bool exact = inst->GetArg(2).GetU1();
|
||||||
// Don't even think about making this a LUT -- it's bad
|
|
||||||
using FPT = u16; // Yes it's u16, no fsize madness
|
using rounding_list = mp::list<
|
||||||
switch (rounding) {
|
mp::lift_value<FP::RoundingMode::ToNearest_TieEven>,
|
||||||
case FP::RoundingMode::ToNearest_TieEven:
|
mp::lift_value<FP::RoundingMode::TowardsPlusInfinity>,
|
||||||
exact
|
mp::lift_value<FP::RoundingMode::TowardsMinusInfinity>,
|
||||||
? EmitTwoOpFallback<3>(code, ctx, inst, EmitIRVectorRoundInt16Thunk<FPT, FP::RoundingMode::ToNearest_TieEven, true>)
|
mp::lift_value<FP::RoundingMode::TowardsZero>,
|
||||||
: EmitTwoOpFallback<3>(code, ctx, inst, EmitIRVectorRoundInt16Thunk<FPT, FP::RoundingMode::ToNearest_TieEven, false>);
|
mp::lift_value<FP::RoundingMode::ToNearest_TieAwayFromZero>>;
|
||||||
break;
|
using exact_list = mp::list<std::true_type, std::false_type>;
|
||||||
case FP::RoundingMode::TowardsPlusInfinity:
|
|
||||||
exact
|
static const auto lut = Common::GenerateLookupTableFromList(
|
||||||
? EmitTwoOpFallback<3>(code, ctx, inst, EmitIRVectorRoundInt16Thunk<FPT, FP::RoundingMode::TowardsPlusInfinity, true>)
|
[]<typename I>(I) {
|
||||||
: EmitTwoOpFallback<3>(code, ctx, inst, EmitIRVectorRoundInt16Thunk<FPT, FP::RoundingMode::TowardsPlusInfinity, false>);
|
using FPT = u16;
|
||||||
break;
|
return std::pair{
|
||||||
case FP::RoundingMode::TowardsMinusInfinity:
|
mp::lower_to_tuple_v<I>,
|
||||||
exact
|
Common::FptrCast(
|
||||||
? EmitTwoOpFallback<3>(code, ctx, inst, EmitIRVectorRoundInt16Thunk<FPT, FP::RoundingMode::TowardsMinusInfinity, true>)
|
[](VectorArray<FPT>& output, const VectorArray<FPT>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
|
||||||
: EmitTwoOpFallback<3>(code, ctx, inst, EmitIRVectorRoundInt16Thunk<FPT, FP::RoundingMode::TowardsMinusInfinity, false>);
|
constexpr FP::RoundingMode rounding_mode = mp::get<0, I>::value;
|
||||||
break;
|
constexpr bool exact = mp::get<1, I>::value;
|
||||||
case FP::RoundingMode::TowardsZero:
|
|
||||||
exact
|
for (size_t i = 0; i < output.size(); ++i) {
|
||||||
? EmitTwoOpFallback<3>(code, ctx, inst, EmitIRVectorRoundInt16Thunk<FPT, FP::RoundingMode::TowardsZero, true>)
|
output[i] = static_cast<FPT>(FP::FPRoundInt<FPT>(input[i], fpcr, rounding_mode, exact, fpsr));
|
||||||
: EmitTwoOpFallback<3>(code, ctx, inst, EmitIRVectorRoundInt16Thunk<FPT, FP::RoundingMode::TowardsZero, false>);
|
|
||||||
break;
|
|
||||||
case FP::RoundingMode::ToNearest_TieAwayFromZero:
|
|
||||||
exact
|
|
||||||
? EmitTwoOpFallback<3>(code, ctx, inst, EmitIRVectorRoundInt16Thunk<FPT, FP::RoundingMode::ToNearest_TieAwayFromZero, true>)
|
|
||||||
: EmitTwoOpFallback<3>(code, ctx, inst, EmitIRVectorRoundInt16Thunk<FPT, FP::RoundingMode::ToNearest_TieAwayFromZero, false>);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
}
|
||||||
|
})};
|
||||||
|
},
|
||||||
|
mp::cartesian_product<rounding_list, exact_list>{});
|
||||||
|
|
||||||
|
EmitTwoOpFallback<3>(code, ctx, inst, lut.at(std::make_tuple(rounding, exact)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
|
||||||
|
|
@ -1071,42 +1071,57 @@ void EmitX64::EmitFPRecipStepFused64(EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitFPRecipStepFused<64>(code, ctx, inst);
|
EmitFPRecipStepFused<64>(code, ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief An assembly thunk for the general rounding of FP
|
static void EmitFPRound(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, size_t fsize) {
|
||||||
/// Conciously making this be a template, because the cost of comparing "fsize" for every
|
const auto rounding_mode = static_cast<FP::RoundingMode>(inst->GetArg(1).GetU8());
|
||||||
/// round is not worth it. Remember we are making only 3 copies (u16,u32,u64)
|
const bool exact = inst->GetArg(2).GetU1();
|
||||||
/// Extra args layout:
|
const auto round_imm = ConvertRoundingModeToX64Immediate(rounding_mode);
|
||||||
/// 0-7 rounding_mode
|
|
||||||
/// 8-15 exact (!= 0)
|
if (fsize != 16 && code.HasHostFeature(HostFeature::SSE41) && round_imm && !exact) {
|
||||||
template<typename FPT>
|
if (fsize == 64) {
|
||||||
static u64 EmitFPRoundThunk(u64 input, FP::FPSR& fpsr, FP::FPCR fpcr, u32 extra_args) {
|
FPTwoOp<64>(code, ctx, inst, [&](Xbyak::Xmm result) {
|
||||||
auto const exact = ((extra_args >> 16) & 0xff) != 0;
|
code.roundsd(result, result, *round_imm);
|
||||||
auto const rounding_mode = FP::RoundingMode((extra_args >> 8) & 0xff);
|
});
|
||||||
return FP::FPRoundInt<FPT>(FPT(input), fpcr, rounding_mode, exact, fpsr);
|
} else {
|
||||||
|
FPTwoOp<32>(code, ctx, inst, [&](Xbyak::Xmm result) {
|
||||||
|
code.roundss(result, result, *round_imm);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EmitFPRound(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, size_t fsize) {
|
return;
|
||||||
auto const rounding_mode = FP::RoundingMode(inst->GetArg(1).GetU8());
|
}
|
||||||
bool const exact = inst->GetArg(2).GetU1();
|
|
||||||
auto const round_imm = ConvertRoundingModeToX64Immediate(rounding_mode);
|
using fsize_list = mp::list<mp::lift_value<size_t(16)>,
|
||||||
if (fsize != 16 && code.HasHostFeature(HostFeature::SSE41) && round_imm && !exact) {
|
mp::lift_value<size_t(32)>,
|
||||||
fsize == 64
|
mp::lift_value<size_t(64)>>;
|
||||||
? FPTwoOp<64>(code, ctx, inst, [&](Xbyak::Xmm result) { code.roundsd(result, result, *round_imm); })
|
using rounding_list = mp::list<
|
||||||
: FPTwoOp<32>(code, ctx, inst, [&](Xbyak::Xmm result) { code.roundss(result, result, *round_imm); });
|
mp::lift_value<FP::RoundingMode::ToNearest_TieEven>,
|
||||||
} else {
|
mp::lift_value<FP::RoundingMode::TowardsPlusInfinity>,
|
||||||
|
mp::lift_value<FP::RoundingMode::TowardsMinusInfinity>,
|
||||||
|
mp::lift_value<FP::RoundingMode::TowardsZero>,
|
||||||
|
mp::lift_value<FP::RoundingMode::ToNearest_TieAwayFromZero>>;
|
||||||
|
using exact_list = mp::list<std::true_type, std::false_type>;
|
||||||
|
|
||||||
|
static const auto lut = Common::GenerateLookupTableFromList(
|
||||||
|
[]<typename I>(I) {
|
||||||
|
return std::pair{
|
||||||
|
mp::lower_to_tuple_v<I>,
|
||||||
|
Common::FptrCast(
|
||||||
|
[](u64 input, FP::FPSR& fpsr, FP::FPCR fpcr) {
|
||||||
|
constexpr size_t fsize = mp::get<0, I>::value;
|
||||||
|
constexpr FP::RoundingMode rounding_mode = mp::get<1, I>::value;
|
||||||
|
constexpr bool exact = mp::get<2, I>::value;
|
||||||
|
using InputSize = mcl::unsigned_integer_of_size<fsize>;
|
||||||
|
|
||||||
|
return FP::FPRoundInt<InputSize>(static_cast<InputSize>(input), fpcr, rounding_mode, exact, fpsr);
|
||||||
|
})};
|
||||||
|
},
|
||||||
|
mp::cartesian_product<fsize_list, rounding_list, exact_list>{});
|
||||||
|
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
// See EmitFPRoundThunk
|
|
||||||
auto const extra_args = u32(rounding_mode) | (u32(exact) << 8);
|
|
||||||
ctx.reg_alloc.HostCall(inst, args[0]);
|
ctx.reg_alloc.HostCall(inst, args[0]);
|
||||||
code.lea(code.ABI_PARAM2, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]);
|
code.lea(code.ABI_PARAM2, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]);
|
||||||
code.mov(code.ABI_PARAM3.cvt32(), ctx.FPCR().Value());
|
code.mov(code.ABI_PARAM3.cvt32(), ctx.FPCR().Value());
|
||||||
code.mov(code.ABI_PARAM4.cvt32(), extra_args);
|
code.CallFunction(lut.at(std::make_tuple(fsize, rounding_mode, exact)));
|
||||||
switch (fsize) {
|
|
||||||
case 64: code.CallFunction(EmitFPRoundThunk<u64>); break;
|
|
||||||
case 32: code.CallFunction(EmitFPRoundThunk<u32>); break;
|
|
||||||
case 16: code.CallFunction(EmitFPRoundThunk<u16>); break;
|
|
||||||
default: UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitFPRoundInt16(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitFPRoundInt16(EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
|
@ -1606,29 +1621,12 @@ void EmitX64::EmitFPDoubleToSingle(EmitContext& ctx, IR::Inst* inst) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Thunk used in assembly
|
|
||||||
/// The extra args is conformed as follows:
|
|
||||||
/// 0-7 fbits
|
|
||||||
/// 8-15 rounding
|
|
||||||
/// 16-23 isize
|
|
||||||
/// 24-31 unsigned_ (!= 0)
|
|
||||||
/// Better than spamming thousands of templates aye?
|
|
||||||
template<size_t fsize>
|
|
||||||
static u64 EmitFPToFixedThunk(u64 input, FP::FPSR& fpsr, FP::FPCR fpcr, u32 extra_args) {
|
|
||||||
using FPT = mcl::unsigned_integer_of_size<fsize>;
|
|
||||||
auto const unsigned_ = ((extra_args >> 24) & 0xff) != 0;
|
|
||||||
auto const isize = ((extra_args >> 16) & 0xff);
|
|
||||||
auto const rounding = FP::RoundingMode((extra_args >> 8) & 0xff);
|
|
||||||
auto const fbits = ((extra_args >> 0) & 0xff);
|
|
||||||
return FP::FPToFixed<FPT>(isize, FPT(input), fbits, unsigned_, fpcr, rounding, fpsr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<size_t fsize, bool unsigned_, size_t isize>
|
template<size_t fsize, bool unsigned_, size_t isize>
|
||||||
static void EmitFPToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
static void EmitFPToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
const size_t fbits = args[1].GetImmediateU8();
|
const size_t fbits = args[1].GetImmediateU8();
|
||||||
const auto rounding_mode = FP::RoundingMode(args[2].GetImmediateU8());
|
const auto rounding_mode = static_cast<FP::RoundingMode>(args[2].GetImmediateU8());
|
||||||
|
|
||||||
if constexpr (fsize != 16) {
|
if constexpr (fsize != 16) {
|
||||||
const auto round_imm = ConvertRoundingModeToX64Immediate(rounding_mode);
|
const auto round_imm = ConvertRoundingModeToX64Immediate(rounding_mode);
|
||||||
|
|
@ -1734,14 +1732,34 @@ static void EmitFPToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// See EmitFPToFixedThunk
|
|
||||||
auto const extra_args = (u32(unsigned_) << 24) | (u32(isize) << 16)
|
using fbits_list = mp::lift_sequence<std::make_index_sequence<isize + 1>>;
|
||||||
| (u32(rounding_mode) << 8) | (u32(fbits));
|
using rounding_list = mp::list<
|
||||||
|
mp::lift_value<FP::RoundingMode::ToNearest_TieEven>,
|
||||||
|
mp::lift_value<FP::RoundingMode::TowardsPlusInfinity>,
|
||||||
|
mp::lift_value<FP::RoundingMode::TowardsMinusInfinity>,
|
||||||
|
mp::lift_value<FP::RoundingMode::TowardsZero>,
|
||||||
|
mp::lift_value<FP::RoundingMode::ToNearest_TieAwayFromZero>>;
|
||||||
|
|
||||||
|
static const auto lut = Common::GenerateLookupTableFromList(
|
||||||
|
[]<typename I>(I) {
|
||||||
|
return std::pair{
|
||||||
|
mp::lower_to_tuple_v<I>,
|
||||||
|
Common::FptrCast(
|
||||||
|
[](u64 input, FP::FPSR& fpsr, FP::FPCR fpcr) {
|
||||||
|
constexpr size_t fbits = mp::get<0, I>::value;
|
||||||
|
constexpr FP::RoundingMode rounding_mode = mp::get<1, I>::value;
|
||||||
|
using FPT = mcl::unsigned_integer_of_size<fsize>;
|
||||||
|
|
||||||
|
return FP::FPToFixed<FPT>(isize, static_cast<FPT>(input), fbits, unsigned_, fpcr, rounding_mode, fpsr);
|
||||||
|
})};
|
||||||
|
},
|
||||||
|
mp::cartesian_product<fbits_list, rounding_list>{});
|
||||||
|
|
||||||
ctx.reg_alloc.HostCall(inst, args[0]);
|
ctx.reg_alloc.HostCall(inst, args[0]);
|
||||||
code.lea(code.ABI_PARAM2, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]);
|
code.lea(code.ABI_PARAM2, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]);
|
||||||
code.mov(code.ABI_PARAM3.cvt32(), ctx.FPCR().Value());
|
code.mov(code.ABI_PARAM3.cvt32(), ctx.FPCR().Value());
|
||||||
code.mov(code.ABI_PARAM4.cvt32(), extra_args);
|
code.CallFunction(lut.at(std::make_tuple(fbits, rounding_mode)));
|
||||||
code.CallFunction(EmitFPToFixedThunk<fsize>);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitFPDoubleToFixedS16(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitFPDoubleToFixedS16(EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
|
|
||||||
|
|
@ -439,9 +439,9 @@ void EmitThreeOpVectorOperation(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
ctx.reg_alloc.DefineValue(inst, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename Lambda>
|
||||||
void EmitTwoOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xbyak::Xmm result, Xbyak::Xmm arg1, F lambda, bool fpcr_controlled) {
|
void EmitTwoOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xbyak::Xmm result, Xbyak::Xmm arg1, Lambda lambda, bool fpcr_controlled) {
|
||||||
const auto fn = static_cast<mcl::equivalent_function_type<F>*>(lambda);
|
const auto fn = static_cast<mcl::equivalent_function_type<Lambda>*>(lambda);
|
||||||
|
|
||||||
const u32 fpcr = ctx.FPCR(fpcr_controlled).Value();
|
const u32 fpcr = ctx.FPCR(fpcr_controlled).Value();
|
||||||
|
|
||||||
|
|
@ -459,8 +459,8 @@ void EmitTwoOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xbyak
|
||||||
code.add(rsp, stack_space + ABI_SHADOW_SPACE);
|
code.add(rsp, stack_space + ABI_SHADOW_SPACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t fpcr_controlled_arg_index = 1, typename F>
|
template<size_t fpcr_controlled_arg_index = 1, typename Lambda>
|
||||||
void EmitTwoOpFallback(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, F lambda) {
|
void EmitTwoOpFallback(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Lambda lambda) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
const Xbyak::Xmm arg1 = ctx.reg_alloc.UseXmm(args[0]);
|
const Xbyak::Xmm arg1 = ctx.reg_alloc.UseXmm(args[0]);
|
||||||
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
|
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
|
||||||
|
|
@ -665,14 +665,8 @@ void EmitX64::EmitFPVectorEqual64(EmitContext& ctx, IR::Inst* inst) {
|
||||||
ctx.reg_alloc.DefineValue(inst, a);
|
ctx.reg_alloc.DefineValue(inst, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<FP::RoundingMode rounding_mode>
|
|
||||||
static void EmitFPVectorFromHalf32Thunk(VectorArray<u32>& output, const VectorArray<u16>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
|
|
||||||
for (size_t i = 0; i < output.size(); ++i)
|
|
||||||
output[i] = FP::FPConvert<u32, u16>(input[i], fpcr, rounding_mode, fpsr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitX64::EmitFPVectorFromHalf32(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitFPVectorFromHalf32(EmitContext& ctx, IR::Inst* inst) {
|
||||||
const auto rounding_mode = FP::RoundingMode(inst->GetArg(1).GetU8());
|
const auto rounding_mode = static_cast<FP::RoundingMode>(inst->GetArg(1).GetU8());
|
||||||
const bool fpcr_controlled = inst->GetArg(2).GetU1();
|
const bool fpcr_controlled = inst->GetArg(2).GetU1();
|
||||||
|
|
||||||
if (code.HasHostFeature(HostFeature::F16C) && !ctx.FPCR().AHP() && !ctx.FPCR().FZ16()) {
|
if (code.HasHostFeature(HostFeature::F16C) && !ctx.FPCR().AHP() && !ctx.FPCR().FZ16()) {
|
||||||
|
|
@ -685,27 +679,32 @@ void EmitX64::EmitFPVectorFromHalf32(EmitContext& ctx, IR::Inst* inst) {
|
||||||
ForceToDefaultNaN<32>(code, ctx.FPCR(fpcr_controlled), result);
|
ForceToDefaultNaN<32>(code, ctx.FPCR(fpcr_controlled), result);
|
||||||
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
ctx.reg_alloc.DefineValue(inst, result);
|
||||||
} else {
|
return;
|
||||||
switch (rounding_mode) {
|
|
||||||
case FP::RoundingMode::ToNearest_TieEven:
|
|
||||||
EmitTwoOpFallback<2>(code, ctx, inst, EmitFPVectorFromHalf32Thunk<FP::RoundingMode::ToNearest_TieEven>);
|
|
||||||
break;
|
|
||||||
case FP::RoundingMode::TowardsPlusInfinity:
|
|
||||||
EmitTwoOpFallback<2>(code, ctx, inst, EmitFPVectorFromHalf32Thunk<FP::RoundingMode::TowardsPlusInfinity>);
|
|
||||||
break;
|
|
||||||
case FP::RoundingMode::TowardsMinusInfinity:
|
|
||||||
EmitTwoOpFallback<2>(code, ctx, inst, EmitFPVectorFromHalf32Thunk<FP::RoundingMode::TowardsMinusInfinity>);
|
|
||||||
break;
|
|
||||||
case FP::RoundingMode::TowardsZero:
|
|
||||||
EmitTwoOpFallback<2>(code, ctx, inst, EmitFPVectorFromHalf32Thunk<FP::RoundingMode::TowardsZero>);
|
|
||||||
break;
|
|
||||||
case FP::RoundingMode::ToNearest_TieAwayFromZero:
|
|
||||||
EmitTwoOpFallback<2>(code, ctx, inst, EmitFPVectorFromHalf32Thunk<FP::RoundingMode::ToNearest_TieAwayFromZero>);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using rounding_list = mp::list<
|
||||||
|
mp::lift_value<FP::RoundingMode::ToNearest_TieEven>,
|
||||||
|
mp::lift_value<FP::RoundingMode::TowardsPlusInfinity>,
|
||||||
|
mp::lift_value<FP::RoundingMode::TowardsMinusInfinity>,
|
||||||
|
mp::lift_value<FP::RoundingMode::TowardsZero>,
|
||||||
|
mp::lift_value<FP::RoundingMode::ToNearest_TieAwayFromZero>>;
|
||||||
|
|
||||||
|
static const auto lut = Common::GenerateLookupTableFromList(
|
||||||
|
[]<typename I>(I) {
|
||||||
|
return std::pair{
|
||||||
|
mp::lower_to_tuple_v<I>,
|
||||||
|
Common::FptrCast(
|
||||||
|
[](VectorArray<u32>& output, const VectorArray<u16>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
|
||||||
|
constexpr FP::RoundingMode rounding_mode = mp::get<0, I>::value;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < output.size(); ++i) {
|
||||||
|
output[i] = FP::FPConvert<u32, u16>(input[i], fpcr, rounding_mode, fpsr);
|
||||||
}
|
}
|
||||||
|
})};
|
||||||
|
},
|
||||||
|
mp::cartesian_product<rounding_list>{});
|
||||||
|
|
||||||
|
EmitTwoOpFallback<2>(code, ctx, inst, lut.at(std::make_tuple(rounding_mode)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitFPVectorFromSignedFixed32(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitFPVectorFromSignedFixed32(EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
|
@ -1682,26 +1681,25 @@ void EmitX64::EmitFPVectorRecipStepFused64(EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitRecipStepFused<64>(code, ctx, inst);
|
EmitRecipStepFused<64>(code, ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename FPT, FP::RoundingMode rounding_mode, bool exact>
|
|
||||||
static void EmitFPVectorRoundIntThunk(VectorArray<FPT>& output, const VectorArray<FPT>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
|
|
||||||
for (size_t i = 0; i < output.size(); ++i)
|
|
||||||
output[i] = FPT(FP::FPRoundInt<FPT>(input[i], fpcr, rounding_mode, exact, fpsr));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<size_t fsize>
|
template<size_t fsize>
|
||||||
void EmitFPVectorRoundInt(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
void EmitFPVectorRoundInt(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
const auto rounding = FP::RoundingMode(inst->GetArg(1).GetU8());
|
const auto rounding = static_cast<FP::RoundingMode>(inst->GetArg(1).GetU8());
|
||||||
const bool exact = inst->GetArg(2).GetU1();
|
const bool exact = inst->GetArg(2).GetU1();
|
||||||
|
|
||||||
if constexpr (fsize != 16) {
|
if constexpr (fsize != 16) {
|
||||||
if (code.HasHostFeature(HostFeature::SSE41) && rounding != FP::RoundingMode::ToNearest_TieAwayFromZero && !exact) {
|
if (code.HasHostFeature(HostFeature::SSE41) && rounding != FP::RoundingMode::ToNearest_TieAwayFromZero && !exact) {
|
||||||
const u8 round_imm = [&]() -> u8 {
|
const u8 round_imm = [&]() -> u8 {
|
||||||
switch (rounding) {
|
switch (rounding) {
|
||||||
case FP::RoundingMode::ToNearest_TieEven: return 0b00;
|
case FP::RoundingMode::ToNearest_TieEven:
|
||||||
case FP::RoundingMode::TowardsPlusInfinity: return 0b10;
|
return 0b00;
|
||||||
case FP::RoundingMode::TowardsMinusInfinity: return 0b01;
|
case FP::RoundingMode::TowardsPlusInfinity:
|
||||||
case FP::RoundingMode::TowardsZero: return 0b11;
|
return 0b10;
|
||||||
default: UNREACHABLE();
|
case FP::RoundingMode::TowardsMinusInfinity:
|
||||||
|
return 0b01;
|
||||||
|
case FP::RoundingMode::TowardsZero:
|
||||||
|
return 0b11;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
|
@ -1713,37 +1711,32 @@ void EmitFPVectorRoundInt(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not make a LUT out of this, let the compiler do it's thing
|
using rounding_list = mp::list<
|
||||||
using FPT = mcl::unsigned_integer_of_size<fsize>;
|
mp::lift_value<FP::RoundingMode::ToNearest_TieEven>,
|
||||||
switch (rounding) {
|
mp::lift_value<FP::RoundingMode::TowardsPlusInfinity>,
|
||||||
case FP::RoundingMode::ToNearest_TieEven:
|
mp::lift_value<FP::RoundingMode::TowardsMinusInfinity>,
|
||||||
exact
|
mp::lift_value<FP::RoundingMode::TowardsZero>,
|
||||||
? EmitTwoOpFallback<3>(code, ctx, inst, EmitFPVectorRoundIntThunk<FPT, FP::RoundingMode::ToNearest_TieEven, true>)
|
mp::lift_value<FP::RoundingMode::ToNearest_TieAwayFromZero>>;
|
||||||
: EmitTwoOpFallback<3>(code, ctx, inst, EmitFPVectorRoundIntThunk<FPT, FP::RoundingMode::ToNearest_TieEven, false>);
|
using exact_list = mp::list<std::true_type, std::false_type>;
|
||||||
break;
|
|
||||||
case FP::RoundingMode::TowardsPlusInfinity:
|
static const auto lut = Common::GenerateLookupTableFromList(
|
||||||
exact
|
[]<typename I>(I) {
|
||||||
? EmitTwoOpFallback<3>(code, ctx, inst, EmitFPVectorRoundIntThunk<FPT, FP::RoundingMode::TowardsPlusInfinity, true>)
|
using FPT = mcl::unsigned_integer_of_size<fsize>; // WORKAROUND: For issue 678 on MSVC
|
||||||
: EmitTwoOpFallback<3>(code, ctx, inst, EmitFPVectorRoundIntThunk<FPT, FP::RoundingMode::TowardsPlusInfinity, false>);
|
return std::pair{
|
||||||
break;
|
mp::lower_to_tuple_v<I>,
|
||||||
case FP::RoundingMode::TowardsMinusInfinity:
|
Common::FptrCast(
|
||||||
exact
|
[](VectorArray<FPT>& output, const VectorArray<FPT>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
|
||||||
? EmitTwoOpFallback<3>(code, ctx, inst, EmitFPVectorRoundIntThunk<FPT, FP::RoundingMode::TowardsMinusInfinity, true>)
|
constexpr FP::RoundingMode rounding_mode = mp::get<0, I>::value;
|
||||||
: EmitTwoOpFallback<3>(code, ctx, inst, EmitFPVectorRoundIntThunk<FPT, FP::RoundingMode::TowardsMinusInfinity, false>);
|
constexpr bool exact = mp::get<1, I>::value;
|
||||||
break;
|
|
||||||
case FP::RoundingMode::TowardsZero:
|
for (size_t i = 0; i < output.size(); ++i) {
|
||||||
exact
|
output[i] = static_cast<FPT>(FP::FPRoundInt<FPT>(input[i], fpcr, rounding_mode, exact, fpsr));
|
||||||
? EmitTwoOpFallback<3>(code, ctx, inst, EmitFPVectorRoundIntThunk<FPT, FP::RoundingMode::TowardsZero, true>)
|
|
||||||
: EmitTwoOpFallback<3>(code, ctx, inst, EmitFPVectorRoundIntThunk<FPT, FP::RoundingMode::TowardsZero, false>);
|
|
||||||
break;
|
|
||||||
case FP::RoundingMode::ToNearest_TieAwayFromZero:
|
|
||||||
exact
|
|
||||||
? EmitTwoOpFallback<3>(code, ctx, inst, EmitFPVectorRoundIntThunk<FPT, FP::RoundingMode::ToNearest_TieAwayFromZero, true>)
|
|
||||||
: EmitTwoOpFallback<3>(code, ctx, inst, EmitFPVectorRoundIntThunk<FPT, FP::RoundingMode::ToNearest_TieAwayFromZero, false>);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
}
|
||||||
|
})};
|
||||||
|
},
|
||||||
|
mp::cartesian_product<rounding_list, exact_list>{});
|
||||||
|
|
||||||
|
EmitTwoOpFallback<3>(code, ctx, inst, lut.at(std::make_tuple(rounding, exact)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitFPVectorRoundInt16(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitFPVectorRoundInt16(EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
|
@ -1972,14 +1965,8 @@ void EmitX64::EmitFPVectorSub64(EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitThreeOpVectorOperation<64, DefaultIndexer>(code, ctx, inst, &Xbyak::CodeGenerator::subpd);
|
EmitThreeOpVectorOperation<64, DefaultIndexer>(code, ctx, inst, &Xbyak::CodeGenerator::subpd);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<FP::RoundingMode rounding_mode>
|
|
||||||
static void EmitFPVectorToHalf32Thunk(VectorArray<u16>& output, const VectorArray<u32>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
|
|
||||||
for (size_t i = 0; i < output.size(); ++i)
|
|
||||||
output[i] = i < input.size() ? FP::FPConvert<u16, u32>(input[i], fpcr, rounding_mode, fpsr) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitX64::EmitFPVectorToHalf32(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitFPVectorToHalf32(EmitContext& ctx, IR::Inst* inst) {
|
||||||
const auto rounding_mode = FP::RoundingMode(inst->GetArg(1).GetU8());
|
const auto rounding_mode = static_cast<FP::RoundingMode>(inst->GetArg(1).GetU8());
|
||||||
const bool fpcr_controlled = inst->GetArg(2).GetU1();
|
const bool fpcr_controlled = inst->GetArg(2).GetU1();
|
||||||
|
|
||||||
if (code.HasHostFeature(HostFeature::F16C) && !ctx.FPCR().AHP() && !ctx.FPCR().FZ16()) {
|
if (code.HasHostFeature(HostFeature::F16C) && !ctx.FPCR().AHP() && !ctx.FPCR().FZ16()) {
|
||||||
|
|
@ -1989,38 +1976,40 @@ void EmitX64::EmitFPVectorToHalf32(EmitContext& ctx, IR::Inst* inst) {
|
||||||
const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(args[0]);
|
const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(args[0]);
|
||||||
|
|
||||||
ForceToDefaultNaN<32>(code, ctx.FPCR(fpcr_controlled), result);
|
ForceToDefaultNaN<32>(code, ctx.FPCR(fpcr_controlled), result);
|
||||||
code.vcvtps2ph(result, result, u8(*round_imm));
|
code.vcvtps2ph(result, result, static_cast<u8>(*round_imm));
|
||||||
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
ctx.reg_alloc.DefineValue(inst, result);
|
||||||
} else {
|
return;
|
||||||
switch (rounding_mode) {
|
|
||||||
case FP::RoundingMode::ToNearest_TieEven:
|
|
||||||
EmitTwoOpFallback<2>(code, ctx, inst, EmitFPVectorToHalf32Thunk<FP::RoundingMode::ToNearest_TieEven>);
|
|
||||||
break;
|
|
||||||
case FP::RoundingMode::TowardsPlusInfinity:
|
|
||||||
EmitTwoOpFallback<2>(code, ctx, inst, EmitFPVectorToHalf32Thunk<FP::RoundingMode::TowardsPlusInfinity>);
|
|
||||||
break;
|
|
||||||
case FP::RoundingMode::TowardsMinusInfinity:
|
|
||||||
EmitTwoOpFallback<2>(code, ctx, inst, EmitFPVectorToHalf32Thunk<FP::RoundingMode::TowardsMinusInfinity>);
|
|
||||||
break;
|
|
||||||
case FP::RoundingMode::TowardsZero:
|
|
||||||
EmitTwoOpFallback<2>(code, ctx, inst, EmitFPVectorToHalf32Thunk<FP::RoundingMode::TowardsZero>);
|
|
||||||
break;
|
|
||||||
case FP::RoundingMode::ToNearest_TieAwayFromZero:
|
|
||||||
EmitTwoOpFallback<2>(code, ctx, inst, EmitFPVectorToHalf32Thunk<FP::RoundingMode::ToNearest_TieAwayFromZero>);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assembly thunk; just remember not to specialise too much otherwise i-cache death!
|
using rounding_list = mp::list<
|
||||||
// template<typename FPT, size_t fbits, FP::RoundingMode rounding_mode>
|
mp::lift_value<FP::RoundingMode::ToNearest_TieEven>,
|
||||||
// static void EmitFPVectorToFixedThunk(VectorArray<FPT>& output, const VectorArray<FPT>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
|
mp::lift_value<FP::RoundingMode::TowardsPlusInfinity>,
|
||||||
// for (size_t i = 0; i < output.size(); ++i)
|
mp::lift_value<FP::RoundingMode::TowardsMinusInfinity>,
|
||||||
// output[i] = FPT(FP::FPToFixed<FPT>(fsize, input[i], fbits, unsigned_, fpcr, rounding_mode, fpsr));
|
mp::lift_value<FP::RoundingMode::TowardsZero>,
|
||||||
// }
|
mp::lift_value<FP::RoundingMode::ToNearest_TieAwayFromZero>>;
|
||||||
|
|
||||||
|
static const auto lut = Common::GenerateLookupTableFromList(
|
||||||
|
[]<typename I>(I) {
|
||||||
|
return std::pair{
|
||||||
|
mp::lower_to_tuple_v<I>,
|
||||||
|
Common::FptrCast(
|
||||||
|
[](VectorArray<u16>& output, const VectorArray<u32>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
|
||||||
|
constexpr FP::RoundingMode rounding_mode = mp::get<0, I>::value;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < output.size(); ++i) {
|
||||||
|
if (i < input.size()) {
|
||||||
|
output[i] = FP::FPConvert<u16, u32>(input[i], fpcr, rounding_mode, fpsr);
|
||||||
|
} else {
|
||||||
|
output[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})};
|
||||||
|
},
|
||||||
|
mp::cartesian_product<rounding_list>{});
|
||||||
|
|
||||||
|
EmitTwoOpFallback<2>(code, ctx, inst, lut.at(std::make_tuple(rounding_mode)));
|
||||||
|
}
|
||||||
|
|
||||||
template<size_t fsize, bool unsigned_>
|
template<size_t fsize, bool unsigned_>
|
||||||
void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
|
@ -2119,7 +2108,7 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
FCODE(andp)(tmp, xmm0);
|
FCODE(andp)(tmp, xmm0);
|
||||||
FCODE(subp)(src, tmp);
|
FCODE(subp)(src, tmp);
|
||||||
perform_conversion(src);
|
perform_conversion(src);
|
||||||
ICODE(psll)(xmm0, u8(fsize - 1));
|
ICODE(psll)(xmm0, static_cast<u8>(fsize - 1));
|
||||||
FCODE(orp)(src, xmm0);
|
FCODE(orp)(src, xmm0);
|
||||||
|
|
||||||
// Saturate to max
|
// Saturate to max
|
||||||
|
|
@ -2127,7 +2116,7 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
using FPT = mcl::unsigned_integer_of_size<fsize>; // WORKAROUND: For issue 678 on MSVC
|
using FPT = mcl::unsigned_integer_of_size<fsize>; // WORKAROUND: For issue 678 on MSVC
|
||||||
constexpr u64 integer_max = FPT((std::numeric_limits<std::conditional_t<unsigned_, FPT, std::make_signed_t<FPT>>>::max)());
|
constexpr u64 integer_max = static_cast<FPT>((std::numeric_limits<std::conditional_t<unsigned_, FPT, std::make_signed_t<FPT>>>::max)());
|
||||||
|
|
||||||
code.movaps(xmm0, GetVectorOf<fsize, float_upper_limit_signed>(code));
|
code.movaps(xmm0, GetVectorOf<fsize, float_upper_limit_signed>(code));
|
||||||
FCODE(cmplep)(xmm0, src);
|
FCODE(cmplep)(xmm0, src);
|
||||||
|
|
@ -2149,18 +2138,22 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
mp::lift_value<FP::RoundingMode::TowardsZero>,
|
mp::lift_value<FP::RoundingMode::TowardsZero>,
|
||||||
mp::lift_value<FP::RoundingMode::ToNearest_TieAwayFromZero>>;
|
mp::lift_value<FP::RoundingMode::ToNearest_TieAwayFromZero>>;
|
||||||
|
|
||||||
static const auto lut = Common::GenerateLookupTableFromList([]<typename I>(I) {
|
static const auto lut = Common::GenerateLookupTableFromList(
|
||||||
|
[]<typename I>(I) {
|
||||||
using FPT = mcl::unsigned_integer_of_size<fsize>; // WORKAROUND: For issue 678 on MSVC
|
using FPT = mcl::unsigned_integer_of_size<fsize>; // WORKAROUND: For issue 678 on MSVC
|
||||||
return std::pair{
|
return std::pair{
|
||||||
mp::lower_to_tuple_v<I>,
|
mp::lower_to_tuple_v<I>,
|
||||||
Common::FptrCast([](VectorArray<FPT>& output, const VectorArray<FPT>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
|
Common::FptrCast(
|
||||||
|
[](VectorArray<FPT>& output, const VectorArray<FPT>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
|
||||||
constexpr size_t fbits = mp::get<0, I>::value;
|
constexpr size_t fbits = mp::get<0, I>::value;
|
||||||
constexpr FP::RoundingMode rounding_mode = mp::get<1, I>::value;
|
constexpr FP::RoundingMode rounding_mode = mp::get<1, I>::value;
|
||||||
for (size_t i = 0; i < output.size(); ++i)
|
|
||||||
output[i] = FPT(FP::FPToFixed<FPT>(fsize, input[i], fbits, unsigned_, fpcr, rounding_mode, fpsr));
|
for (size_t i = 0; i < output.size(); ++i) {
|
||||||
})
|
output[i] = static_cast<FPT>(FP::FPToFixed<FPT>(fsize, input[i], fbits, unsigned_, fpcr, rounding_mode, fpsr));
|
||||||
};
|
}
|
||||||
}, mp::cartesian_product<fbits_list, rounding_list>{});
|
})};
|
||||||
|
},
|
||||||
|
mp::cartesian_product<fbits_list, rounding_list>{});
|
||||||
|
|
||||||
EmitTwoOpFallback<3>(code, ctx, inst, lut.at(std::make_tuple(fbits, rounding)));
|
EmitTwoOpFallback<3>(code, ctx, inst, lut.at(std::make_tuple(fbits, rounding)));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
* Copyright (c) 2018 MerryMage
|
* Copyright (c) 2018 MerryMage
|
||||||
* SPDX-License-Identifier: 0BSD
|
* SPDX-License-Identifier: 0BSD
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,9 @@ inline auto GenerateLookupTableFromList(Function f, mcl::mp::list<Values...>) {
|
||||||
using PairT = std::common_type_t<std::invoke_result_t<Function, Values>...>;
|
using PairT = std::common_type_t<std::invoke_result_t<Function, Values>...>;
|
||||||
#endif
|
#endif
|
||||||
using MapT = mcl::mp::apply<std::map, PairT>;
|
using MapT = mcl::mp::apply<std::map, PairT>;
|
||||||
|
|
||||||
static_assert(mcl::is_instance_of_template_v<std::pair, PairT>);
|
static_assert(mcl::is_instance_of_template_v<std::pair, PairT>);
|
||||||
|
|
||||||
const std::initializer_list<PairT> pair_array{f(Values{})...};
|
const std::initializer_list<PairT> pair_array{f(Values{})...};
|
||||||
return MapT(pair_array.begin(), pair_array.end());
|
return MapT(pair_array.begin(), pair_array.end());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2018 yuzu Emulator Project
|
# SPDX-FileCopyrightText: 2018 yuzu Emulator Project
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|
@ -86,7 +83,7 @@ if (ENABLE_LIBUSB)
|
||||||
drivers/gc_adapter.h
|
drivers/gc_adapter.h
|
||||||
)
|
)
|
||||||
target_link_libraries(input_common PRIVATE libusb::usb)
|
target_link_libraries(input_common PRIVATE libusb::usb)
|
||||||
target_compile_definitions(input_common PRIVATE ENABLE_LIBUSB)
|
target_compile_definitions(input_common PRIVATE HAVE_LIBUSB)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
create_target_directory_groups(input_common)
|
create_target_directory_groups(input_common)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|
@ -22,7 +19,7 @@
|
||||||
#include "input_common/input_poller.h"
|
#include "input_common/input_poller.h"
|
||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
|
|
||||||
#ifdef ENABLE_LIBUSB
|
#ifdef HAVE_LIBUSB
|
||||||
#include "input_common/drivers/gc_adapter.h"
|
#include "input_common/drivers/gc_adapter.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL2
|
||||||
|
|
@ -79,7 +76,7 @@ struct InputSubsystem::Impl {
|
||||||
RegisterEngine("keyboard", keyboard);
|
RegisterEngine("keyboard", keyboard);
|
||||||
RegisterEngine("mouse", mouse);
|
RegisterEngine("mouse", mouse);
|
||||||
RegisterEngine("touch", touch_screen);
|
RegisterEngine("touch", touch_screen);
|
||||||
#ifdef ENABLE_LIBUSB
|
#ifdef HAVE_LIBUSB
|
||||||
RegisterEngine("gcpad", gcadapter);
|
RegisterEngine("gcpad", gcadapter);
|
||||||
#endif
|
#endif
|
||||||
RegisterEngine("cemuhookudp", udp_client);
|
RegisterEngine("cemuhookudp", udp_client);
|
||||||
|
|
@ -113,7 +110,7 @@ struct InputSubsystem::Impl {
|
||||||
UnregisterEngine(keyboard);
|
UnregisterEngine(keyboard);
|
||||||
UnregisterEngine(mouse);
|
UnregisterEngine(mouse);
|
||||||
UnregisterEngine(touch_screen);
|
UnregisterEngine(touch_screen);
|
||||||
#ifdef ENABLE_LIBUSB
|
#ifdef HAVE_LIBUSB
|
||||||
UnregisterEngine(gcadapter);
|
UnregisterEngine(gcadapter);
|
||||||
#endif
|
#endif
|
||||||
UnregisterEngine(udp_client);
|
UnregisterEngine(udp_client);
|
||||||
|
|
@ -148,7 +145,7 @@ struct InputSubsystem::Impl {
|
||||||
auto android_devices = android->GetInputDevices();
|
auto android_devices = android->GetInputDevices();
|
||||||
devices.insert(devices.end(), android_devices.begin(), android_devices.end());
|
devices.insert(devices.end(), android_devices.begin(), android_devices.end());
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_LIBUSB
|
#ifdef HAVE_LIBUSB
|
||||||
auto gcadapter_devices = gcadapter->GetInputDevices();
|
auto gcadapter_devices = gcadapter->GetInputDevices();
|
||||||
devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end());
|
devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end());
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -181,7 +178,7 @@ struct InputSubsystem::Impl {
|
||||||
return android;
|
return android;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_LIBUSB
|
#ifdef HAVE_LIBUSB
|
||||||
if (engine == gcadapter->GetEngineName()) {
|
if (engine == gcadapter->GetEngineName()) {
|
||||||
return gcadapter;
|
return gcadapter;
|
||||||
}
|
}
|
||||||
|
|
@ -266,7 +263,7 @@ struct InputSubsystem::Impl {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_LIBUSB
|
#ifdef HAVE_LIBUSB
|
||||||
if (engine == gcadapter->GetEngineName()) {
|
if (engine == gcadapter->GetEngineName()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -297,7 +294,7 @@ struct InputSubsystem::Impl {
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
android->BeginConfiguration();
|
android->BeginConfiguration();
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_LIBUSB
|
#ifdef HAVE_LIBUSB
|
||||||
gcadapter->BeginConfiguration();
|
gcadapter->BeginConfiguration();
|
||||||
#endif
|
#endif
|
||||||
udp_client->BeginConfiguration();
|
udp_client->BeginConfiguration();
|
||||||
|
|
@ -313,7 +310,7 @@ struct InputSubsystem::Impl {
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
android->EndConfiguration();
|
android->EndConfiguration();
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_LIBUSB
|
#ifdef HAVE_LIBUSB
|
||||||
gcadapter->EndConfiguration();
|
gcadapter->EndConfiguration();
|
||||||
#endif
|
#endif
|
||||||
udp_client->EndConfiguration();
|
udp_client->EndConfiguration();
|
||||||
|
|
@ -346,7 +343,7 @@ struct InputSubsystem::Impl {
|
||||||
std::shared_ptr<VirtualAmiibo> virtual_amiibo;
|
std::shared_ptr<VirtualAmiibo> virtual_amiibo;
|
||||||
std::shared_ptr<VirtualGamepad> virtual_gamepad;
|
std::shared_ptr<VirtualGamepad> virtual_gamepad;
|
||||||
|
|
||||||
#ifdef ENABLE_LIBUSB
|
#ifdef HAVE_LIBUSB
|
||||||
std::shared_ptr<GCAdapter> gcadapter;
|
std::shared_ptr<GCAdapter> gcadapter;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,11 +78,11 @@ IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, Type type) {
|
||||||
case Type::_1D:
|
case Type::_1D:
|
||||||
case Type::_1D_BUFFER:
|
case Type::_1D_BUFFER:
|
||||||
return v.X(reg);
|
return v.X(reg);
|
||||||
case Type::_1D_ARRAY:
|
case Type::ARRAY_1D:
|
||||||
return v.ir.CompositeConstruct(v.X(reg), array(1));
|
return v.ir.CompositeConstruct(v.X(reg), array(1));
|
||||||
case Type::_2D:
|
case Type::_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 Type::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 Type::_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));
|
||||||
|
|
|
||||||
|
|
@ -243,7 +243,7 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shader_backend == Settings::ShaderBackend::Glsl && is_nvidia) {
|
if (shader_backend == Settings::ShaderBackend::Glsl && is_nvidia) {
|
||||||
const std::string driver_version = version.substr(13);
|
const std::string_view driver_version = version.substr(13);
|
||||||
const int version_major =
|
const int version_major =
|
||||||
std::atoi(driver_version.substr(0, driver_version.find(".")).data());
|
std::atoi(driver_version.substr(0, driver_version.find(".")).data());
|
||||||
if (version_major >= 495) {
|
if (version_major >= 495) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue