mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-08-27 20:56:25 +00:00
Merge pull request #23 from dolphin-emu/master
[pull] master from dolphin-emu:master
This commit is contained in:
commit
4d48aed93d
45 changed files with 298 additions and 112 deletions
|
@ -173,7 +173,7 @@ float4 SharpBilinearSample(float3 uvw, float gamma)
|
||||||
float2 texel = uvw.xy * source_size;
|
float2 texel = uvw.xy * source_size;
|
||||||
float2 texel_floored = floor(texel);
|
float2 texel_floored = floor(texel);
|
||||||
float2 s = fract(texel);
|
float2 s = fract(texel);
|
||||||
float scale = ceil(max(target_size.x * inverted_source_size.x, target_size.y * inverted_source_size.y));
|
float scale = max(floor(max(target_size.x * inverted_source_size.x, target_size.y * inverted_source_size.y)), 1.f);
|
||||||
float region_range = 0.5 - (0.5 / scale);
|
float region_range = 0.5 - (0.5 / scale);
|
||||||
|
|
||||||
// Figure out where in the texel to sample to get correct pre-scaled bilinear.
|
// Figure out where in the texel to sample to get correct pre-scaled bilinear.
|
||||||
|
|
|
@ -9,8 +9,11 @@
|
||||||
package org.dolphinemu.dolphinemu.features
|
package org.dolphinemu.dolphinemu.features
|
||||||
|
|
||||||
import android.annotation.TargetApi
|
import android.annotation.TargetApi
|
||||||
|
import android.content.res.AssetFileDescriptor
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.database.MatrixCursor
|
import android.database.MatrixCursor
|
||||||
|
import android.graphics.Point
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.CancellationSignal
|
import android.os.CancellationSignal
|
||||||
import android.os.ParcelFileDescriptor
|
import android.os.ParcelFileDescriptor
|
||||||
|
@ -27,7 +30,7 @@ class DocumentProvider : DocumentsProvider() {
|
||||||
private var rootDirectory: File? = null
|
private var rootDirectory: File? = null
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
public const val ROOT_ID = "root"
|
const val ROOT_ID = "root"
|
||||||
|
|
||||||
private val DEFAULT_ROOT_PROJECTION = arrayOf(
|
private val DEFAULT_ROOT_PROJECTION = arrayOf(
|
||||||
DocumentsContract.Root.COLUMN_ROOT_ID,
|
DocumentsContract.Root.COLUMN_ROOT_ID,
|
||||||
|
@ -93,6 +96,8 @@ class DocumentProvider : DocumentsProvider() {
|
||||||
appendDocument(file, result)
|
appendDocument(file, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
result.setNotificationUri(context!!.contentResolver, DocumentsContract.buildChildDocumentsUri(
|
||||||
|
"${context!!.packageName}.user", parentDocumentId))
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +112,16 @@ class DocumentProvider : DocumentsProvider() {
|
||||||
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode))
|
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun openDocumentThumbnail(
|
||||||
|
documentId: String,
|
||||||
|
sizeHint: Point,
|
||||||
|
signal: CancellationSignal
|
||||||
|
): AssetFileDescriptor {
|
||||||
|
val file = documentIdToPath(documentId)
|
||||||
|
val pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY)
|
||||||
|
return AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH)
|
||||||
|
}
|
||||||
|
|
||||||
override fun createDocument(
|
override fun createDocument(
|
||||||
parentDocumentId: String,
|
parentDocumentId: String,
|
||||||
mimeType: String,
|
mimeType: String,
|
||||||
|
@ -121,6 +136,7 @@ class DocumentProvider : DocumentsProvider() {
|
||||||
} else {
|
} else {
|
||||||
file.createNewFile()
|
file.createNewFile()
|
||||||
}
|
}
|
||||||
|
refreshDocument(parentDocumentId)
|
||||||
return pathToDocumentId(file)
|
return pathToDocumentId(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +144,9 @@ class DocumentProvider : DocumentsProvider() {
|
||||||
rootDirectory ?: return
|
rootDirectory ?: return
|
||||||
|
|
||||||
val file = documentIdToPath(documentId)
|
val file = documentIdToPath(documentId)
|
||||||
|
val fileParent = file.parentFile
|
||||||
file.deleteRecursively()
|
file.deleteRecursively()
|
||||||
|
refreshDocument(pathToDocumentId(fileParent!!))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun renameDocument(documentId: String, displayName: String): String? {
|
override fun renameDocument(documentId: String, displayName: String): String? {
|
||||||
|
@ -137,9 +155,19 @@ class DocumentProvider : DocumentsProvider() {
|
||||||
val file = documentIdToPath(documentId)
|
val file = documentIdToPath(documentId)
|
||||||
val dest = findFileNameForNewFile(File(file.parentFile, displayName))
|
val dest = findFileNameForNewFile(File(file.parentFile, displayName))
|
||||||
file.renameTo(dest)
|
file.renameTo(dest)
|
||||||
|
refreshDocument(pathToDocumentId(file.parentFile!!))
|
||||||
return pathToDocumentId(dest)
|
return pathToDocumentId(dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun refreshDocument(parentDocumentId: String) {
|
||||||
|
val parentUri: Uri =
|
||||||
|
DocumentsContract.buildChildDocumentsUri(
|
||||||
|
"${context!!.packageName}.user",
|
||||||
|
parentDocumentId
|
||||||
|
)
|
||||||
|
context!!.contentResolver.notifyChange(parentUri, null)
|
||||||
|
}
|
||||||
|
|
||||||
override fun isChildDocument(parentDocumentId: String, documentId: String): Boolean
|
override fun isChildDocument(parentDocumentId: String, documentId: String): Boolean
|
||||||
= documentId.startsWith(parentDocumentId)
|
= documentId.startsWith(parentDocumentId)
|
||||||
|
|
||||||
|
@ -161,6 +189,10 @@ class DocumentProvider : DocumentsProvider() {
|
||||||
} else {
|
} else {
|
||||||
file.name
|
file.name
|
||||||
}
|
}
|
||||||
|
val mimeType = getTypeForFile(file)
|
||||||
|
if (file.exists() && mimeType.startsWith("image/")) {
|
||||||
|
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL
|
||||||
|
}
|
||||||
cursor.newRow().apply {
|
cursor.newRow().apply {
|
||||||
add(DocumentsContract.Document.COLUMN_DOCUMENT_ID, pathToDocumentId(file))
|
add(DocumentsContract.Document.COLUMN_DOCUMENT_ID, pathToDocumentId(file))
|
||||||
add(DocumentsContract.Document.COLUMN_MIME_TYPE, getTypeForFile(file))
|
add(DocumentsContract.Document.COLUMN_MIME_TYPE, getTypeForFile(file))
|
||||||
|
|
|
@ -73,7 +73,7 @@ public:
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int bit = std::countr_zero(m_val);
|
int bit = std::countr_zero(m_val);
|
||||||
m_val &= ~(1 << bit);
|
m_val &= ~(IntTy{1} << bit);
|
||||||
m_bit = bit;
|
m_bit = bit;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -98,15 +98,15 @@ public:
|
||||||
constexpr BitSet(std::initializer_list<int> init)
|
constexpr BitSet(std::initializer_list<int> init)
|
||||||
{
|
{
|
||||||
for (int bit : init)
|
for (int bit : init)
|
||||||
m_val |= (IntTy)1 << bit;
|
m_val |= IntTy{1} << bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static BitSet AllTrue(size_t count)
|
constexpr static BitSet AllTrue(size_t count)
|
||||||
{
|
{
|
||||||
return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1));
|
return BitSet(count == sizeof(IntTy) * 8 ? ~IntTy{0} : ((IntTy{1} << count) - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref operator[](size_t bit) { return Ref(this, (IntTy)1 << bit); }
|
Ref operator[](size_t bit) { return Ref(this, IntTy{1} << bit); }
|
||||||
constexpr const Ref operator[](size_t bit) const { return (*const_cast<BitSet*>(this))[bit]; }
|
constexpr const Ref operator[](size_t bit) const { return (*const_cast<BitSet*>(this))[bit]; }
|
||||||
constexpr bool operator==(BitSet other) const { return m_val == other.m_val; }
|
constexpr bool operator==(BitSet other) const { return m_val == other.m_val; }
|
||||||
constexpr bool operator!=(BitSet other) const { return m_val != other.m_val; }
|
constexpr bool operator!=(BitSet other) const { return m_val != other.m_val; }
|
||||||
|
|
|
@ -10,7 +10,10 @@
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#define strerror_r(err, buf, len) strerror_s(buf, len, err)
|
#define strerror_r(err, buf, len) strerror_s(buf, len, err)
|
||||||
|
|
||||||
|
#include "Common/StringUtil.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Common
|
namespace Common
|
||||||
|
@ -59,11 +62,11 @@ std::string GetLastErrorString()
|
||||||
// Like GetLastErrorString() but if you have already queried the error code.
|
// Like GetLastErrorString() but if you have already queried the error code.
|
||||||
std::string GetWin32ErrorString(DWORD error_code)
|
std::string GetWin32ErrorString(DWORD error_code)
|
||||||
{
|
{
|
||||||
char error_message[BUFFER_SIZE];
|
wchar_t error_message[BUFFER_SIZE];
|
||||||
|
|
||||||
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, error_code,
|
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, error_code,
|
||||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), error_message, BUFFER_SIZE, nullptr);
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), error_message, BUFFER_SIZE, nullptr);
|
||||||
return std::string(error_message);
|
return WStringToUTF8(error_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtains a full path to the specified module.
|
// Obtains a full path to the specified module.
|
||||||
|
|
|
@ -426,7 +426,7 @@ size_t StringUTF8CodePointCount(std::string_view str)
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
std::wstring CPToUTF16(u32 code_page, std::string_view input)
|
static std::wstring CPToUTF16(u32 code_page, std::string_view input)
|
||||||
{
|
{
|
||||||
auto const size =
|
auto const size =
|
||||||
MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0);
|
MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0);
|
||||||
|
@ -444,7 +444,7 @@ std::wstring CPToUTF16(u32 code_page, std::string_view input)
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string UTF16ToCP(u32 code_page, std::wstring_view input)
|
static std::string UTF16ToCP(u32 code_page, std::wstring_view input)
|
||||||
{
|
{
|
||||||
if (input.empty())
|
if (input.empty())
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -950,6 +950,7 @@ struct ReverbPB
|
||||||
// Base address of the circular buffer in MRAM.
|
// Base address of the circular buffer in MRAM.
|
||||||
u16 circular_buffer_base_h;
|
u16 circular_buffer_base_h;
|
||||||
u16 circular_buffer_base_l;
|
u16 circular_buffer_base_l;
|
||||||
|
DEFINE_32BIT_ACCESSOR(circular_buffer_base, CircularBufferBase)
|
||||||
|
|
||||||
struct Destination
|
struct Destination
|
||||||
{
|
{
|
||||||
|
@ -990,7 +991,7 @@ void ZeldaAudioRenderer::PrepareFrame()
|
||||||
0xB820);
|
0xB820);
|
||||||
AddBuffersWithVolume(m_buf_front_left_reverb.data(), m_buf_back_right_reverb.data() + 0x28, 0x28,
|
AddBuffersWithVolume(m_buf_front_left_reverb.data(), m_buf_back_right_reverb.data() + 0x28, 0x28,
|
||||||
0xB820);
|
0xB820);
|
||||||
AddBuffersWithVolume(m_buf_front_right_reverb.data(), m_buf_back_left_reverb.data() + 0x28, 0x28,
|
AddBuffersWithVolume(m_buf_front_right_reverb.data(), m_buf_back_right_reverb.data() + 0x28, 0x28,
|
||||||
0x7FFF);
|
0x7FFF);
|
||||||
m_buf_back_left_reverb.fill(0);
|
m_buf_back_left_reverb.fill(0);
|
||||||
m_buf_back_right_reverb.fill(0);
|
m_buf_back_right_reverb.fill(0);
|
||||||
|
@ -1059,8 +1060,7 @@ void ZeldaAudioRenderer::ApplyReverb(bool post_rendering)
|
||||||
|
|
||||||
u16 mram_buffer_idx = m_reverb_pb_frames_count[rpb_idx];
|
u16 mram_buffer_idx = m_reverb_pb_frames_count[rpb_idx];
|
||||||
|
|
||||||
u32 mram_addr = ((rpb.circular_buffer_base_h << 16) | rpb.circular_buffer_base_l) +
|
u32 mram_addr = rpb.GetCircularBufferBase() + mram_buffer_idx * 0x50 * sizeof(s16);
|
||||||
mram_buffer_idx * 0x50 * sizeof(s16);
|
|
||||||
s16* mram_ptr = (s16*)HLEMemory_Get_Pointer(mram_addr);
|
s16* mram_ptr = (s16*)HLEMemory_Get_Pointer(mram_addr);
|
||||||
|
|
||||||
if (!post_rendering)
|
if (!post_rendering)
|
||||||
|
@ -1217,11 +1217,9 @@ void ZeldaAudioRenderer::AddVoice(u16 voice_id)
|
||||||
|
|
||||||
// Compute reverb volume and ramp deltas.
|
// Compute reverb volume and ramp deltas.
|
||||||
s16 reverb_volumes[4], reverb_volume_deltas[4];
|
s16 reverb_volumes[4], reverb_volume_deltas[4];
|
||||||
s16 reverb_volume_factor =
|
|
||||||
(vpb.dolby_volume_current * vpb.dolby_reverb_factor) >> (shift_factor - 1);
|
|
||||||
for (size_t i = 0; i < 4; ++i)
|
for (size_t i = 0; i < 4; ++i)
|
||||||
{
|
{
|
||||||
reverb_volumes[i] = (quadrant_volumes[i] * reverb_volume_factor) >> shift_factor;
|
reverb_volumes[i] = (quadrant_volumes[i] * vpb.dolby_reverb_factor) >> shift_factor;
|
||||||
reverb_volume_deltas[i] = (volume_deltas[i] * vpb.dolby_reverb_factor) >> shift_factor;
|
reverb_volume_deltas[i] = (volume_deltas[i] * vpb.dolby_reverb_factor) >> shift_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -577,8 +577,11 @@ void EmulationKernel::AddStaticDevices()
|
||||||
}
|
}
|
||||||
if (HasFeature(features, Feature::KD))
|
if (HasFeature(features, Feature::KD))
|
||||||
{
|
{
|
||||||
AddDevice(std::make_unique<NetKDRequestDevice>(*this, "/dev/net/kd/request"));
|
constexpr auto time_device_name = "/dev/net/kd/time";
|
||||||
AddDevice(std::make_unique<NetKDTimeDevice>(*this, "/dev/net/kd/time"));
|
AddDevice(std::make_unique<NetKDTimeDevice>(*this, time_device_name));
|
||||||
|
const auto time_device =
|
||||||
|
std::static_pointer_cast<NetKDTimeDevice>(GetDeviceByName(time_device_name));
|
||||||
|
AddDevice(std::make_unique<NetKDRequestDevice>(*this, "/dev/net/kd/request", time_device));
|
||||||
}
|
}
|
||||||
if (HasFeature(features, Feature::NCD))
|
if (HasFeature(features, Feature::NCD))
|
||||||
{
|
{
|
||||||
|
|
|
@ -153,9 +153,10 @@ s32 NWC24MakeUserID(u64* nwc24_id, u32 hollywood_id, u16 id_ctr, HardwareModel h
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
NetKDRequestDevice::NetKDRequestDevice(EmulationKernel& ios, const std::string& device_name)
|
NetKDRequestDevice::NetKDRequestDevice(EmulationKernel& ios, const std::string& device_name,
|
||||||
|
const std::shared_ptr<NetKDTimeDevice>& time_device)
|
||||||
: EmulationDevice(ios, device_name), m_config{ios.GetFS()}, m_dl_list{ios.GetFS()},
|
: EmulationDevice(ios, device_name), m_config{ios.GetFS()}, m_dl_list{ios.GetFS()},
|
||||||
m_send_list{ios.GetFS()}, m_friend_list{ios.GetFS()}
|
m_send_list{ios.GetFS()}, m_friend_list{ios.GetFS()}, m_time_device{time_device}
|
||||||
{
|
{
|
||||||
// Enable all NWC24 permissions
|
// Enable all NWC24 permissions
|
||||||
m_scheduler_buffer[1] = Common::swap32(-1);
|
m_scheduler_buffer[1] = Common::swap32(-1);
|
||||||
|
@ -190,6 +191,8 @@ NetKDRequestDevice::~NetKDRequestDevice()
|
||||||
}
|
}
|
||||||
|
|
||||||
m_scheduler_timer_thread.join();
|
m_scheduler_timer_thread.join();
|
||||||
|
m_scheduler_work_queue.Shutdown();
|
||||||
|
m_work_queue.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetKDRequestDevice::Update()
|
void NetKDRequestDevice::Update()
|
||||||
|
@ -441,9 +444,7 @@ NWC24::ErrorCode NetKDRequestDevice::DetermineDownloadTask(u16* entry_index,
|
||||||
// As the scheduler does not tell us which entry to download, we must determine that.
|
// As the scheduler does not tell us which entry to download, we must determine that.
|
||||||
// A correct entry is one that hasn't been downloaded the longest compared to other entries.
|
// A correct entry is one that hasn't been downloaded the longest compared to other entries.
|
||||||
// We first need current UTC.
|
// We first need current UTC.
|
||||||
const auto time_device =
|
const u64 current_utc = m_time_device->GetAdjustedUTC();
|
||||||
std::static_pointer_cast<NetKDTimeDevice>(GetIOS()->GetDeviceByName("/dev/net/kd/time"));
|
|
||||||
const u64 current_utc = time_device->GetAdjustedUTC();
|
|
||||||
u64 lowest_timestamp = std::numeric_limits<u64>::max();
|
u64 lowest_timestamp = std::numeric_limits<u64>::max();
|
||||||
|
|
||||||
for (u16 i = 0; i < static_cast<u16>(NWC24::NWC24Dl::MAX_ENTRIES); i++)
|
for (u16 i = 0; i < static_cast<u16>(NWC24::NWC24Dl::MAX_ENTRIES); i++)
|
||||||
|
@ -493,9 +494,7 @@ NWC24::ErrorCode NetKDRequestDevice::DetermineSubtask(u16 entry_index,
|
||||||
if (m_dl_list.IsSubtaskDownloadDisabled(entry_index))
|
if (m_dl_list.IsSubtaskDownloadDisabled(entry_index))
|
||||||
return NWC24::WC24_ERR_DISABLED;
|
return NWC24::WC24_ERR_DISABLED;
|
||||||
|
|
||||||
const auto time_device =
|
const u64 current_utc = m_time_device->GetAdjustedUTC();
|
||||||
std::static_pointer_cast<NetKDTimeDevice>(GetIOS()->GetDeviceByName("/dev/net/kd/time"));
|
|
||||||
const u64 current_utc = time_device->GetAdjustedUTC();
|
|
||||||
for (u8 i = 0; i < 32; i++)
|
for (u8 i = 0; i < 32; i++)
|
||||||
{
|
{
|
||||||
if (!m_dl_list.IsValidSubtask(entry_index, i))
|
if (!m_dl_list.IsValidSubtask(entry_index, i))
|
||||||
|
@ -645,9 +644,7 @@ NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index,
|
||||||
{
|
{
|
||||||
bool success = false;
|
bool success = false;
|
||||||
Common::ScopeGuard state_guard([&] {
|
Common::ScopeGuard state_guard([&] {
|
||||||
const auto time_device =
|
const u64 current_utc = m_time_device->GetAdjustedUTC();
|
||||||
std::static_pointer_cast<NetKDTimeDevice>(GetIOS()->GetDeviceByName("/dev/net/kd/time"));
|
|
||||||
const u64 current_utc = time_device->GetAdjustedUTC();
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
// Set the next download time to the dl_margin
|
// Set the next download time to the dl_margin
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
#include "Core/IOS/Network/KD/Mail/WC24Send.h"
|
#include "Core/IOS/Network/KD/Mail/WC24Send.h"
|
||||||
#include "Core/IOS/Network/KD/NWC24Config.h"
|
#include "Core/IOS/Network/KD/NWC24Config.h"
|
||||||
#include "Core/IOS/Network/KD/NWC24DL.h"
|
#include "Core/IOS/Network/KD/NWC24DL.h"
|
||||||
|
#include "Core/IOS/Network/KD/NetKDTime.h"
|
||||||
|
|
||||||
namespace IOS::HLE
|
namespace IOS::HLE
|
||||||
{
|
{
|
||||||
|
@ -26,7 +28,8 @@ namespace IOS::HLE
|
||||||
class NetKDRequestDevice : public EmulationDevice
|
class NetKDRequestDevice : public EmulationDevice
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NetKDRequestDevice(EmulationKernel& ios, const std::string& device_name);
|
NetKDRequestDevice(EmulationKernel& ios, const std::string& device_name,
|
||||||
|
const std::shared_ptr<NetKDTimeDevice>& time_device);
|
||||||
IPCReply HandleNWC24DownloadNowEx(const IOCtlRequest& request);
|
IPCReply HandleNWC24DownloadNowEx(const IOCtlRequest& request);
|
||||||
NWC24::ErrorCode KDDownload(const u16 entry_index, const std::optional<u8> subtask_id);
|
NWC24::ErrorCode KDDownload(const u16 entry_index, const std::optional<u8> subtask_id);
|
||||||
IPCReply HandleNWC24CheckMailNow(const IOCtlRequest& request);
|
IPCReply HandleNWC24CheckMailNow(const IOCtlRequest& request);
|
||||||
|
@ -114,6 +117,7 @@ private:
|
||||||
std::queue<AsyncReply> m_async_replies;
|
std::queue<AsyncReply> m_async_replies;
|
||||||
u32 m_error_count = 0;
|
u32 m_error_count = 0;
|
||||||
std::array<u32, 256> m_scheduler_buffer{};
|
std::array<u32, 256> m_scheduler_buffer{};
|
||||||
|
std::shared_ptr<NetKDTimeDevice> m_time_device;
|
||||||
// TODO: Maybe move away from Common::HttpRequest?
|
// TODO: Maybe move away from Common::HttpRequest?
|
||||||
Common::HttpRequest m_http{std::chrono::minutes{1}};
|
Common::HttpRequest m_http{std::chrono::minutes{1}};
|
||||||
u32 m_download_span = 2;
|
u32 m_download_span = 2;
|
||||||
|
|
|
@ -221,6 +221,9 @@ void Jit64AsmRoutineManager::Generate()
|
||||||
ABI_CallFunction(JitTrampoline);
|
ABI_CallFunction(JitTrampoline);
|
||||||
ABI_PopRegistersAndAdjustStack({}, 0);
|
ABI_PopRegistersAndAdjustStack({}, 0);
|
||||||
|
|
||||||
|
// If jitting triggered an ISI exception, MSR.DR may have changed
|
||||||
|
MOV(64, R(RMEM), PPCSTATE(mem_ptr));
|
||||||
|
|
||||||
JMP(dispatcher_no_check, Jump::Near);
|
JMP(dispatcher_no_check, Jump::Near);
|
||||||
|
|
||||||
SetJumpTarget(bail);
|
SetJumpTarget(bail);
|
||||||
|
|
|
@ -939,7 +939,6 @@ void JitArm64::dcbz(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(bJITLoadStoreOff);
|
JITDISABLE(bJITLoadStoreOff);
|
||||||
FALLBACK_IF(m_low_dcbz_hack);
|
|
||||||
|
|
||||||
int a = inst.RA, b = inst.RB;
|
int a = inst.RA, b = inst.RB;
|
||||||
|
|
||||||
|
|
|
@ -243,8 +243,9 @@ void Arm64GPRCache::FlushRegister(size_t index, bool maintain_state, ARM64Reg tm
|
||||||
|
|
||||||
void Arm64GPRCache::FlushRegisters(BitSet32 regs, bool maintain_state, ARM64Reg tmp_reg)
|
void Arm64GPRCache::FlushRegisters(BitSet32 regs, bool maintain_state, ARM64Reg tmp_reg)
|
||||||
{
|
{
|
||||||
for (int i : regs)
|
for (auto iter = regs.begin(); iter != regs.end(); ++iter)
|
||||||
{
|
{
|
||||||
|
const int i = *iter;
|
||||||
ASSERT_MSG(DYNA_REC, m_guest_registers[GUEST_GPR_OFFSET + i].GetType() != RegType::Discarded,
|
ASSERT_MSG(DYNA_REC, m_guest_registers[GUEST_GPR_OFFSET + i].GetType() != RegType::Discarded,
|
||||||
"Attempted to flush discarded register");
|
"Attempted to flush discarded register");
|
||||||
|
|
||||||
|
@ -269,7 +270,7 @@ void Arm64GPRCache::FlushRegisters(BitSet32 regs, bool maintain_state, ARM64Reg
|
||||||
reg1.Flush();
|
reg1.Flush();
|
||||||
reg2.Flush();
|
reg2.Flush();
|
||||||
}
|
}
|
||||||
++i;
|
++iter;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,7 +177,12 @@ void JitArm64::GenerateAsm()
|
||||||
// Call JIT
|
// Call JIT
|
||||||
ResetStack();
|
ResetStack();
|
||||||
ABI_CallFunction(&JitTrampoline, this, DISPATCHER_PC);
|
ABI_CallFunction(&JitTrampoline, this, DISPATCHER_PC);
|
||||||
|
|
||||||
LDR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc));
|
LDR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc));
|
||||||
|
|
||||||
|
// If jitting triggered an ISI exception, MSR.DR may have changed
|
||||||
|
EmitUpdateMembase();
|
||||||
|
|
||||||
B(dispatcher_no_check);
|
B(dispatcher_no_check);
|
||||||
|
|
||||||
SetJumpTarget(bail);
|
SetJumpTarget(bail);
|
||||||
|
|
|
@ -1343,7 +1343,8 @@ static TLBLookupResult LookupTLBPageAddress(PowerPC::PowerPCState& ppc_state,
|
||||||
u32* paddr, bool* wi)
|
u32* paddr, bool* wi)
|
||||||
{
|
{
|
||||||
const u32 tag = vpa >> HW_PAGE_INDEX_SHIFT;
|
const u32 tag = vpa >> HW_PAGE_INDEX_SHIFT;
|
||||||
TLBEntry& tlbe = ppc_state.tlb[IsOpcodeFlag(flag)][tag & HW_PAGE_INDEX_MASK];
|
const size_t tlb_index = IsOpcodeFlag(flag) ? PowerPC::INST_TLB_INDEX : PowerPC::DATA_TLB_INDEX;
|
||||||
|
TLBEntry& tlbe = ppc_state.tlb[tlb_index][tag & HW_PAGE_INDEX_MASK];
|
||||||
|
|
||||||
if (tlbe.tag[0] == tag && tlbe.vsid[0] == vsid)
|
if (tlbe.tag[0] == tag && tlbe.vsid[0] == vsid)
|
||||||
{
|
{
|
||||||
|
@ -1401,7 +1402,8 @@ static void UpdateTLBEntry(PowerPC::PowerPCState& ppc_state, const XCheckTLBFlag
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const u32 tag = address >> HW_PAGE_INDEX_SHIFT;
|
const u32 tag = address >> HW_PAGE_INDEX_SHIFT;
|
||||||
TLBEntry& tlbe = ppc_state.tlb[IsOpcodeFlag(flag)][tag & HW_PAGE_INDEX_MASK];
|
const size_t tlb_index = IsOpcodeFlag(flag) ? PowerPC::INST_TLB_INDEX : PowerPC::DATA_TLB_INDEX;
|
||||||
|
TLBEntry& tlbe = ppc_state.tlb[tlb_index][tag & HW_PAGE_INDEX_MASK];
|
||||||
const u32 index = tlbe.recent == 0 && tlbe.tag[0] != TLBEntry::INVALID_TAG;
|
const u32 index = tlbe.recent == 0 && tlbe.tag[0] != TLBEntry::INVALID_TAG;
|
||||||
tlbe.recent = index;
|
tlbe.recent = index;
|
||||||
tlbe.paddr[index] = pte2.RPN << HW_PAGE_INDEX_SHIFT;
|
tlbe.paddr[index] = pte2.RPN << HW_PAGE_INDEX_SHIFT;
|
||||||
|
@ -1414,8 +1416,8 @@ void MMU::InvalidateTLBEntry(u32 address)
|
||||||
{
|
{
|
||||||
const u32 entry_index = (address >> HW_PAGE_INDEX_SHIFT) & HW_PAGE_INDEX_MASK;
|
const u32 entry_index = (address >> HW_PAGE_INDEX_SHIFT) & HW_PAGE_INDEX_MASK;
|
||||||
|
|
||||||
m_ppc_state.tlb[0][entry_index].Invalidate();
|
m_ppc_state.tlb[PowerPC::DATA_TLB_INDEX][entry_index].Invalidate();
|
||||||
m_ppc_state.tlb[1][entry_index].Invalidate();
|
m_ppc_state.tlb[PowerPC::INST_TLB_INDEX][entry_index].Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Page Address Translation
|
// Page Address Translation
|
||||||
|
|
|
@ -53,6 +53,8 @@ enum class CoreMode
|
||||||
constexpr size_t TLB_SIZE = 128;
|
constexpr size_t TLB_SIZE = 128;
|
||||||
constexpr size_t NUM_TLBS = 2;
|
constexpr size_t NUM_TLBS = 2;
|
||||||
constexpr size_t TLB_WAYS = 2;
|
constexpr size_t TLB_WAYS = 2;
|
||||||
|
constexpr size_t DATA_TLB_INDEX = 0;
|
||||||
|
constexpr size_t INST_TLB_INDEX = 1;
|
||||||
|
|
||||||
struct TLBEntry
|
struct TLBEntry
|
||||||
{
|
{
|
||||||
|
|
|
@ -184,7 +184,10 @@ void GeneralWidget::SaveSettings()
|
||||||
{
|
{
|
||||||
// Video Backend
|
// Video Backend
|
||||||
const auto current_backend = m_backend_combo->currentData().toString().toStdString();
|
const auto current_backend = m_backend_combo->currentData().toString().toStdString();
|
||||||
if (Config::Get(Config::MAIN_GFX_BACKEND) != current_backend)
|
if (Config::Get(Config::MAIN_GFX_BACKEND) == current_backend)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Config::GetActiveLayerForConfig(Config::MAIN_GFX_BACKEND) == Config::LayerType::Base)
|
||||||
{
|
{
|
||||||
auto warningMessage = VideoBackendBase::GetAvailableBackends()[m_backend_combo->currentIndex()]
|
auto warningMessage = VideoBackendBase::GetAvailableBackends()[m_backend_combo->currentIndex()]
|
||||||
->GetWarningMessage();
|
->GetWarningMessage();
|
||||||
|
@ -205,8 +208,10 @@ void GeneralWidget::SaveSettings()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit BackendChanged(QString::fromStdString(current_backend));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Config::SetBaseOrCurrent(Config::MAIN_GFX_BACKEND, current_backend);
|
||||||
|
emit BackendChanged(QString::fromStdString(current_backend));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeneralWidget::OnEmulationStateChanged(bool running)
|
void GeneralWidget::OnEmulationStateChanged(bool running)
|
||||||
|
@ -217,6 +222,10 @@ void GeneralWidget::OnEmulationStateChanged(bool running)
|
||||||
|
|
||||||
const bool supports_adapters = !g_Config.backend_info.Adapters.empty();
|
const bool supports_adapters = !g_Config.backend_info.Adapters.empty();
|
||||||
m_adapter_combo->setEnabled(!running && supports_adapters);
|
m_adapter_combo->setEnabled(!running && supports_adapters);
|
||||||
|
|
||||||
|
std::string current_backend = m_backend_combo->currentData().toString().toStdString();
|
||||||
|
if (Config::Get(Config::MAIN_GFX_BACKEND) != current_backend)
|
||||||
|
emit BackendChanged(QString::fromStdString(Config::Get(Config::MAIN_GFX_BACKEND)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeneralWidget::AddDescriptions()
|
void GeneralWidget::AddDescriptions()
|
||||||
|
|
|
@ -67,7 +67,6 @@ void GraphicsWindow::CreateMainLayout()
|
||||||
|
|
||||||
void GraphicsWindow::OnBackendChanged(const QString& backend_name)
|
void GraphicsWindow::OnBackendChanged(const QString& backend_name)
|
||||||
{
|
{
|
||||||
Config::SetBase(Config::MAIN_GFX_BACKEND, backend_name.toStdString());
|
|
||||||
VideoBackendBase::PopulateBackendInfoFromUI(m_main_window->GetWindowSystemInfo());
|
VideoBackendBase::PopulateBackendInfoFromUI(m_main_window->GetWindowSystemInfo());
|
||||||
|
|
||||||
setWindowTitle(
|
setWindowTitle(
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "DolphinQt/Config/Mapping/MappingWidget.h"
|
#include "DolphinQt/Config/Mapping/MappingWidget.h"
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QFormLayout>
|
#include <QFormLayout>
|
||||||
|
@ -25,6 +27,7 @@
|
||||||
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
||||||
#include "InputCommon/ControllerEmu/Setting/NumericSetting.h"
|
#include "InputCommon/ControllerEmu/Setting/NumericSetting.h"
|
||||||
#include "InputCommon/ControllerEmu/StickGate.h"
|
#include "InputCommon/ControllerEmu/StickGate.h"
|
||||||
|
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||||
|
|
||||||
MappingWidget::MappingWidget(MappingWindow* parent) : m_parent(parent)
|
MappingWidget::MappingWidget(MappingWindow* parent) : m_parent(parent)
|
||||||
{
|
{
|
||||||
|
@ -160,6 +163,26 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con
|
||||||
[this, group] { ShowAdvancedControlGroupDialog(group); });
|
[this, group] { ShowAdvancedControlGroupDialog(group); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (group->type == ControllerEmu::GroupType::Cursor)
|
||||||
|
{
|
||||||
|
QPushButton* mouse_button = new QPushButton(tr("Use Mouse Controlled Pointing"));
|
||||||
|
form_layout->insertRow(2, mouse_button);
|
||||||
|
connect(mouse_button, &QCheckBox::clicked, [this, group] {
|
||||||
|
std::string default_device = g_controller_interface.GetDefaultDeviceString() + ":";
|
||||||
|
const std::string controller_device = GetController()->GetDefaultDevice().ToString() + ":";
|
||||||
|
if (default_device == controller_device)
|
||||||
|
{
|
||||||
|
default_device.clear();
|
||||||
|
}
|
||||||
|
group->SetControlExpression(0, fmt::format("`{}Cursor Y-`", default_device));
|
||||||
|
group->SetControlExpression(1, fmt::format("`{}Cursor Y+`", default_device));
|
||||||
|
group->SetControlExpression(2, fmt::format("`{}Cursor X-`", default_device));
|
||||||
|
group->SetControlExpression(3, fmt::format("`{}Cursor X+`", default_device));
|
||||||
|
emit ConfigChanged();
|
||||||
|
GetController()->UpdateReferences(g_controller_interface);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return group_box;
|
return group_box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,8 @@ ControllerInterface g_controller_interface;
|
||||||
// will never interfere with game threads.
|
// will never interfere with game threads.
|
||||||
static thread_local ciface::InputChannel tls_input_channel = ciface::InputChannel::Host;
|
static thread_local ciface::InputChannel tls_input_channel = ciface::InputChannel::Host;
|
||||||
|
|
||||||
|
static thread_local bool tls_is_updating_devices = false;
|
||||||
|
|
||||||
void ControllerInterface::Initialize(const WindowSystemInfo& wsi)
|
void ControllerInterface::Initialize(const WindowSystemInfo& wsi)
|
||||||
{
|
{
|
||||||
if (m_is_init)
|
if (m_is_init)
|
||||||
|
@ -122,8 +124,8 @@ void ControllerInterface::RefreshDevices(RefreshReason reason)
|
||||||
// We lock m_devices_population_mutex here to make everything simpler.
|
// We lock m_devices_population_mutex here to make everything simpler.
|
||||||
// Multiple devices classes have their own "hotplug" thread, and can add/remove devices at any
|
// Multiple devices classes have their own "hotplug" thread, and can add/remove devices at any
|
||||||
// time, while actual writes to "m_devices" are safe, the order in which they happen is not. That
|
// time, while actual writes to "m_devices" are safe, the order in which they happen is not. That
|
||||||
// means a thread could be adding devices while we are removing them, or removing them as we are
|
// means a thread could be adding devices while we are removing them from a different thread,
|
||||||
// populating them (causing missing or duplicate devices).
|
// or removing them as we are populating them (causing missing or duplicate devices).
|
||||||
std::lock_guard lk_population(m_devices_population_mutex);
|
std::lock_guard lk_population(m_devices_population_mutex);
|
||||||
|
|
||||||
#if defined(CIFACE_USE_WIN32) && !defined(CIFACE_USE_XLIB) && !defined(CIFACE_USE_OSX)
|
#if defined(CIFACE_USE_WIN32) && !defined(CIFACE_USE_XLIB) && !defined(CIFACE_USE_OSX)
|
||||||
|
@ -271,6 +273,10 @@ bool ControllerInterface::AddDevice(std::shared_ptr<ciface::Core::Device> device
|
||||||
if (!m_is_init)
|
if (!m_is_init)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
ASSERT_MSG(CONTROLLERINTERFACE, !tls_is_updating_devices,
|
||||||
|
"Devices shouldn't be added within input update calls, there is a risk of deadlock "
|
||||||
|
"if another thread was already here");
|
||||||
|
|
||||||
std::lock_guard lk_population(m_devices_population_mutex);
|
std::lock_guard lk_population(m_devices_population_mutex);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -328,6 +334,10 @@ void ControllerInterface::RemoveDevice(std::function<bool(const ciface::Core::De
|
||||||
if (!m_is_init)
|
if (!m_is_init)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
ASSERT_MSG(CONTROLLERINTERFACE, !tls_is_updating_devices,
|
||||||
|
"Devices shouldn't be removed within input update calls, there is a risk of deadlock "
|
||||||
|
"if another thread was already here");
|
||||||
|
|
||||||
std::lock_guard lk_population(m_devices_population_mutex);
|
std::lock_guard lk_population(m_devices_population_mutex);
|
||||||
|
|
||||||
bool any_removed;
|
bool any_removed;
|
||||||
|
@ -358,29 +368,48 @@ void ControllerInterface::UpdateInput()
|
||||||
if (!m_is_init)
|
if (!m_is_init)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO: if we are an emulation input channel, we should probably always lock
|
// We add the devices to remove while we still have the "m_devices_mutex" locked.
|
||||||
// Prefer outdated values over blocking UI or CPU thread (avoids short but noticeable frame drop)
|
// This guarantees that:
|
||||||
|
// -We won't try to lock "m_devices_population_mutex" while it was already locked and waiting
|
||||||
// Lock this first to avoid deadlock with m_devices_mutex in certain cases (such as a Wii Remote
|
// for "m_devices_mutex", which would result in dead lock.
|
||||||
// getting disconnected)
|
// -We don't keep shared ptrs on devices and thus unwillingly keep them alive even if somebody
|
||||||
if (!m_devices_population_mutex.try_lock())
|
// is currently trying to remove them (and needs them destroyed on the spot).
|
||||||
return;
|
// -If somebody else destroyed them in the meantime, we'll know which ones have been destroyed.
|
||||||
|
std::vector<std::weak_ptr<ciface::Core::Device>> devices_to_remove;
|
||||||
std::lock_guard population_lock(m_devices_population_mutex, std::adopt_lock);
|
|
||||||
|
|
||||||
|
{
|
||||||
|
// TODO: if we are an emulation input channel, we should probably always lock.
|
||||||
|
// Prefer outdated values over blocking UI or CPU thread (this avoids short but noticeable frame
|
||||||
|
// drops)
|
||||||
if (!m_devices_mutex.try_lock())
|
if (!m_devices_mutex.try_lock())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::lock_guard lk(m_devices_mutex, std::adopt_lock);
|
std::lock_guard lk_devices(m_devices_mutex, std::adopt_lock);
|
||||||
|
|
||||||
|
tls_is_updating_devices = true;
|
||||||
|
|
||||||
for (auto& backend : m_input_backends)
|
for (auto& backend : m_input_backends)
|
||||||
backend->UpdateInput();
|
backend->UpdateInput(devices_to_remove);
|
||||||
|
|
||||||
for (const auto& d : m_devices)
|
for (const auto& d : m_devices)
|
||||||
{
|
{
|
||||||
// Theoretically we could avoid updating input on devices that don't have any references to
|
// Theoretically we could avoid updating input on devices that don't have any references to
|
||||||
// them, but in practice a few devices types could break in different ways, so we don't
|
// them, but in practice a few devices types could break in different ways, so we don't
|
||||||
d->UpdateInput();
|
if (d->UpdateInput() == ciface::Core::DeviceRemoval::Remove)
|
||||||
|
devices_to_remove.push_back(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
tls_is_updating_devices = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devices_to_remove.size() > 0)
|
||||||
|
{
|
||||||
|
RemoveDevice([&](const ciface::Core::Device* device) {
|
||||||
|
return std::any_of(devices_to_remove.begin(), devices_to_remove.end(),
|
||||||
|
[device](const std::weak_ptr<ciface::Core::Device>& d) {
|
||||||
|
return d.lock().get() == device;
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,6 @@ private:
|
||||||
|
|
||||||
std::list<std::function<void()>> m_devices_changed_callbacks;
|
std::list<std::function<void()>> m_devices_changed_callbacks;
|
||||||
mutable std::recursive_mutex m_devices_population_mutex;
|
mutable std::recursive_mutex m_devices_population_mutex;
|
||||||
mutable std::mutex m_pre_population_mutex;
|
|
||||||
mutable std::mutex m_callbacks_mutex;
|
mutable std::mutex m_callbacks_mutex;
|
||||||
std::atomic<bool> m_is_init;
|
std::atomic<bool> m_is_init;
|
||||||
// This is now always protected by m_devices_population_mutex, so
|
// This is now always protected by m_devices_population_mutex, so
|
||||||
|
|
|
@ -36,6 +36,12 @@ constexpr ControlState BATTERY_INPUT_MAX_VALUE = 100.0;
|
||||||
|
|
||||||
namespace Core
|
namespace Core
|
||||||
{
|
{
|
||||||
|
enum class DeviceRemoval
|
||||||
|
{
|
||||||
|
Remove,
|
||||||
|
Keep,
|
||||||
|
};
|
||||||
|
|
||||||
class Device
|
class Device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -118,7 +124,7 @@ public:
|
||||||
virtual std::string GetName() const = 0;
|
virtual std::string GetName() const = 0;
|
||||||
virtual std::string GetSource() const = 0;
|
virtual std::string GetSource() const = 0;
|
||||||
std::string GetQualifiedName() const;
|
std::string GetQualifiedName() const;
|
||||||
virtual void UpdateInput() {}
|
virtual DeviceRemoval UpdateInput() { return DeviceRemoval::Keep; }
|
||||||
|
|
||||||
// May be overridden to implement hotplug removal.
|
// May be overridden to implement hotplug removal.
|
||||||
// Currently handled on a per-backend basis but this could change.
|
// Currently handled on a per-backend basis but this could change.
|
||||||
|
@ -242,7 +248,8 @@ public:
|
||||||
std::recursive_mutex& GetDevicesMutex() const { return m_devices_mutex; }
|
std::recursive_mutex& GetDevicesMutex() const { return m_devices_mutex; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Exclusively needed when reading/writing "m_devices"
|
// Exclusively needed when reading/writing the "m_devices" array.
|
||||||
|
// Not needed when individually readring/writing a single device ptr.
|
||||||
mutable std::recursive_mutex m_devices_mutex;
|
mutable std::recursive_mutex m_devices_mutex;
|
||||||
std::vector<std::shared_ptr<Device>> m_devices;
|
std::vector<std::shared_ptr<Device>> m_devices;
|
||||||
};
|
};
|
||||||
|
|
|
@ -222,7 +222,7 @@ bool Joystick::IsValid() const
|
||||||
return SUCCEEDED(m_device->Acquire());
|
return SUCCEEDED(m_device->Acquire());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Joystick::UpdateInput()
|
Core::DeviceRemoval Joystick::UpdateInput()
|
||||||
{
|
{
|
||||||
HRESULT hr = 0;
|
HRESULT hr = 0;
|
||||||
|
|
||||||
|
@ -261,6 +261,8 @@ void Joystick::UpdateInput()
|
||||||
// try reacquire if input lost
|
// try reacquire if input lost
|
||||||
if (DIERR_INPUTLOST == hr || DIERR_NOTACQUIRED == hr)
|
if (DIERR_INPUTLOST == hr || DIERR_NOTACQUIRED == hr)
|
||||||
m_device->Acquire();
|
m_device->Acquire();
|
||||||
|
|
||||||
|
return Core::DeviceRemoval::Keep;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get name
|
// get name
|
||||||
|
|
|
@ -57,7 +57,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void UpdateInput() override;
|
Core::DeviceRemoval UpdateInput() override;
|
||||||
|
|
||||||
Joystick(const LPDIRECTINPUTDEVICE8 device);
|
Joystick(const LPDIRECTINPUTDEVICE8 device);
|
||||||
~Joystick();
|
~Joystick();
|
||||||
|
|
|
@ -205,7 +205,7 @@ void KeyboardMouse::UpdateCursorInput()
|
||||||
m_state_in.cursor.y = (ControlState(point.y) / win_height * 2 - 1) * window_scale.y;
|
m_state_in.cursor.y = (ControlState(point.y) / win_height * 2 - 1) * window_scale.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyboardMouse::UpdateInput()
|
Core::DeviceRemoval KeyboardMouse::UpdateInput()
|
||||||
{
|
{
|
||||||
UpdateCursorInput();
|
UpdateCursorInput();
|
||||||
|
|
||||||
|
@ -254,6 +254,8 @@ void KeyboardMouse::UpdateInput()
|
||||||
else
|
else
|
||||||
INFO_LOG_FMT(CONTROLLERINTERFACE, "Keyboard device failed to re-acquire, we'll retry later");
|
INFO_LOG_FMT(CONTROLLERINTERFACE, "Keyboard device failed to re-acquire, we'll retry later");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Core::DeviceRemoval::Keep;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string KeyboardMouse::GetName() const
|
std::string KeyboardMouse::GetName() const
|
||||||
|
|
|
@ -94,7 +94,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void UpdateInput() override;
|
Core::DeviceRemoval UpdateInput() override;
|
||||||
|
|
||||||
KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, const LPDIRECTINPUTDEVICE8 mo_device);
|
KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, const LPDIRECTINPUTDEVICE8 mo_device);
|
||||||
~KeyboardMouse();
|
~KeyboardMouse();
|
||||||
|
|
|
@ -128,7 +128,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void UpdateInput() override;
|
Core::DeviceRemoval UpdateInput() override;
|
||||||
|
|
||||||
Device(std::string name, int index, std::string server_address, u16 server_port, u32 client_uid);
|
Device(std::string name, int index, std::string server_address, u16 server_port, u32 client_uid);
|
||||||
|
|
||||||
|
@ -614,7 +614,7 @@ std::string Device::GetSource() const
|
||||||
return std::string(DUALSHOCKUDP_SOURCE_NAME);
|
return std::string(DUALSHOCKUDP_SOURCE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::UpdateInput()
|
Core::DeviceRemoval Device::UpdateInput()
|
||||||
{
|
{
|
||||||
// Regularly tell the UDP server to feed us controller data
|
// Regularly tell the UDP server to feed us controller data
|
||||||
const auto now = SteadyClock::now();
|
const auto now = SteadyClock::now();
|
||||||
|
@ -660,6 +660,8 @@ void Device::UpdateInput()
|
||||||
m_prev_touch_valid = true;
|
m_prev_touch_valid = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Core::DeviceRemoval::Keep;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<int> Device::GetPreferredId() const
|
std::optional<int> Device::GetPreferredId() const
|
||||||
|
|
|
@ -12,7 +12,7 @@ InputBackend::InputBackend(ControllerInterface* controller_interface)
|
||||||
|
|
||||||
InputBackend::~InputBackend() = default;
|
InputBackend::~InputBackend() = default;
|
||||||
|
|
||||||
void InputBackend::UpdateInput()
|
void InputBackend::UpdateInput(std::vector<std::weak_ptr<ciface::Core::Device>>& devices_to_remove)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,19 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class ControllerInterface;
|
class ControllerInterface;
|
||||||
|
|
||||||
namespace ciface
|
namespace ciface
|
||||||
{
|
{
|
||||||
|
|
||||||
|
namespace Core
|
||||||
|
{
|
||||||
|
class Device;
|
||||||
|
}
|
||||||
|
|
||||||
class InputBackend
|
class InputBackend
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -15,7 +24,9 @@ public:
|
||||||
virtual ~InputBackend();
|
virtual ~InputBackend();
|
||||||
|
|
||||||
virtual void PopulateDevices() = 0;
|
virtual void PopulateDevices() = 0;
|
||||||
virtual void UpdateInput();
|
// Do NOT directly add/remove devices within here,
|
||||||
|
// just add them to the removal list if necessary.
|
||||||
|
virtual void UpdateInput(std::vector<std::weak_ptr<ciface::Core::Device>>& devices_to_remove);
|
||||||
|
|
||||||
ControllerInterface& GetControllerInterface();
|
ControllerInterface& GetControllerInterface();
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ PipeDevice::~PipeDevice()
|
||||||
close(m_fd);
|
close(m_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PipeDevice::UpdateInput()
|
Core::DeviceRemoval PipeDevice::UpdateInput()
|
||||||
{
|
{
|
||||||
// Read any pending characters off the pipe. If we hit a newline,
|
// Read any pending characters off the pipe. If we hit a newline,
|
||||||
// then dequeue a command off the front of m_buf and parse it.
|
// then dequeue a command off the front of m_buf and parse it.
|
||||||
|
@ -105,6 +105,7 @@ void PipeDevice::UpdateInput()
|
||||||
m_buf.erase(0, newline + 1);
|
m_buf.erase(0, newline + 1);
|
||||||
newline = m_buf.find("\n");
|
newline = m_buf.find("\n");
|
||||||
}
|
}
|
||||||
|
return Core::DeviceRemoval::Keep;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PipeDevice::AddAxis(const std::string& name, double value)
|
void PipeDevice::AddAxis(const std::string& name, double value)
|
||||||
|
|
|
@ -29,7 +29,7 @@ public:
|
||||||
PipeDevice(int fd, const std::string& name);
|
PipeDevice(int fd, const std::string& name);
|
||||||
~PipeDevice();
|
~PipeDevice();
|
||||||
|
|
||||||
void UpdateInput() override;
|
Core::DeviceRemoval UpdateInput() override;
|
||||||
std::string GetName() const override { return m_name; }
|
std::string GetName() const override { return m_name; }
|
||||||
std::string GetSource() const override { return "Pipe"; }
|
std::string GetSource() const override { return "Pipe"; }
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void UpdateInput() override;
|
Core::DeviceRemoval UpdateInput() override;
|
||||||
|
|
||||||
explicit KeyboardAndMouse(void* view);
|
explicit KeyboardAndMouse(void* view);
|
||||||
~KeyboardAndMouse() override;
|
~KeyboardAndMouse() override;
|
||||||
|
|
|
@ -236,7 +236,7 @@ void KeyboardAndMouse::MainThreadInitialization(void* view)
|
||||||
m_window_pos_observer = [[DolWindowPositionObserver alloc] initWithView:cocoa_view];
|
m_window_pos_observer = [[DolWindowPositionObserver alloc] initWithView:cocoa_view];
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyboardAndMouse::UpdateInput()
|
Core::DeviceRemoval KeyboardAndMouse::UpdateInput()
|
||||||
{
|
{
|
||||||
NSRect bounds = [m_window_pos_observer frame];
|
NSRect bounds = [m_window_pos_observer frame];
|
||||||
|
|
||||||
|
@ -268,6 +268,8 @@ void KeyboardAndMouse::UpdateInput()
|
||||||
m_cursor.x = (loc.x / window_width * 2 - 1.0) * window_scale.x;
|
m_cursor.x = (loc.x / window_width * 2 - 1.0) * window_scale.x;
|
||||||
m_cursor.y = (loc.y / window_height * 2 - 1.0) * -window_scale.y;
|
m_cursor.y = (loc.y / window_height * 2 - 1.0) * -window_scale.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Core::DeviceRemoval::Keep;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string KeyboardAndMouse::GetName() const
|
std::string KeyboardAndMouse::GetName() const
|
||||||
|
|
|
@ -18,6 +18,11 @@
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace ciface::Core
|
||||||
|
{
|
||||||
|
class Device;
|
||||||
|
}
|
||||||
|
|
||||||
namespace ciface::SDL
|
namespace ciface::SDL
|
||||||
{
|
{
|
||||||
static std::string GetJoystickName(int index)
|
static std::string GetJoystickName(int index)
|
||||||
|
@ -35,7 +40,7 @@ public:
|
||||||
InputBackend(ControllerInterface* controller_interface);
|
InputBackend(ControllerInterface* controller_interface);
|
||||||
~InputBackend();
|
~InputBackend();
|
||||||
void PopulateDevices() override;
|
void PopulateDevices() override;
|
||||||
void UpdateInput() override;
|
void UpdateInput(std::vector<std::weak_ptr<ciface::Core::Device>>& devices_to_remove) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OpenAndAddDevice(int index);
|
void OpenAndAddDevice(int index);
|
||||||
|
@ -637,7 +642,7 @@ void Joystick::Motor::SetState(ControlState state)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void InputBackend::UpdateInput()
|
void InputBackend::UpdateInput(std::vector<std::weak_ptr<ciface::Core::Device>>& devices_to_remove)
|
||||||
{
|
{
|
||||||
SDL_JoystickUpdate();
|
SDL_JoystickUpdate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ public:
|
||||||
Device(hid_device* device);
|
Device(hid_device* device);
|
||||||
std::string GetName() const final override;
|
std::string GetName() const final override;
|
||||||
std::string GetSource() const final override;
|
std::string GetSource() const final override;
|
||||||
void UpdateInput() override;
|
Core::DeviceRemoval UpdateInput() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
hid_device* m_device;
|
hid_device* m_device;
|
||||||
|
@ -279,7 +279,7 @@ std::string Device::GetSource() const
|
||||||
return std::string(STEAMDECK_SOURCE_NAME);
|
return std::string(STEAMDECK_SOURCE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::UpdateInput()
|
Core::DeviceRemoval Device::UpdateInput()
|
||||||
{
|
{
|
||||||
// As of a certain mid-2023 update to the Steam client,
|
// As of a certain mid-2023 update to the Steam client,
|
||||||
// Steam will disable gyro data if gyro is not mapped in Steam Input.
|
// Steam will disable gyro data if gyro is not mapped in Steam Input.
|
||||||
|
@ -308,16 +308,18 @@ void Device::UpdateInput()
|
||||||
}
|
}
|
||||||
// In case there were no reports available to be read, bail early.
|
// In case there were no reports available to be read, bail early.
|
||||||
if (!got_anything)
|
if (!got_anything)
|
||||||
return;
|
return Core::DeviceRemoval::Keep;
|
||||||
|
|
||||||
if (rpt.major_ver != 0x01 || rpt.minor_ver != 0x00 || rpt.report_type != 0x09 ||
|
if (rpt.major_ver != 0x01 || rpt.minor_ver != 0x00 || rpt.report_type != 0x09 ||
|
||||||
rpt.report_sz != sizeof(rpt))
|
rpt.report_sz != sizeof(rpt))
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(CONTROLLERINTERFACE, "Steam Deck bad report");
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "Steam Deck bad report");
|
||||||
return;
|
return Core::DeviceRemoval::Keep;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_latest_input = rpt;
|
m_latest_input = rpt;
|
||||||
|
|
||||||
|
return Core::DeviceRemoval::Keep;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ciface::SteamDeck
|
} // namespace ciface::SteamDeck
|
||||||
|
|
|
@ -490,7 +490,7 @@ private:
|
||||||
|
|
||||||
std::string GetSource() const override { return std::string(SOURCE_NAME); }
|
std::string GetSource() const override { return std::string(SOURCE_NAME); }
|
||||||
|
|
||||||
void UpdateInput() override
|
Core::DeviceRemoval UpdateInput() override
|
||||||
{
|
{
|
||||||
// IRawGameController:
|
// IRawGameController:
|
||||||
static_assert(sizeof(bool) == sizeof(ButtonValueType));
|
static_assert(sizeof(bool) == sizeof(ButtonValueType));
|
||||||
|
@ -527,6 +527,8 @@ private:
|
||||||
// IGameControllerBatteryInfo:
|
// IGameControllerBatteryInfo:
|
||||||
if (!UpdateBatteryLevel())
|
if (!UpdateBatteryLevel())
|
||||||
DEBUG_LOG_FMT(CONTROLLERINTERFACE, "WGInput: UpdateBatteryLevel failed.");
|
DEBUG_LOG_FMT(CONTROLLERINTERFACE, "WGInput: UpdateBatteryLevel failed.");
|
||||||
|
|
||||||
|
return Core::DeviceRemoval::Keep;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateMotors()
|
void UpdateMotors()
|
||||||
|
|
|
@ -1395,14 +1395,10 @@ void Device::UpdateRumble()
|
||||||
QueueReport(OutputReportRumble{});
|
QueueReport(OutputReportRumble{});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::UpdateInput()
|
Core::DeviceRemoval Device::UpdateInput()
|
||||||
{
|
{
|
||||||
if (!m_wiimote->IsConnected())
|
if (!m_wiimote->IsConnected())
|
||||||
{
|
return Core::DeviceRemoval::Remove;
|
||||||
g_controller_interface.RemoveDevice(
|
|
||||||
[this](const Core::Device* device) { return device == this; });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateRumble();
|
UpdateRumble();
|
||||||
RunTasks();
|
RunTasks();
|
||||||
|
@ -1413,6 +1409,8 @@ void Device::UpdateInput()
|
||||||
ProcessInputReport(report);
|
ProcessInputReport(report);
|
||||||
RunTasks();
|
RunTasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Core::DeviceRemoval::Keep;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::MotionPlusState::ProcessData(const WiimoteEmu::MotionPlus::DataFormat& data)
|
void Device::MotionPlusState::ProcessData(const WiimoteEmu::MotionPlus::DataFormat& data)
|
||||||
|
|
|
@ -35,7 +35,7 @@ public:
|
||||||
std::string GetSource() const override;
|
std::string GetSource() const override;
|
||||||
int GetSortPriority() const override;
|
int GetSortPriority() const override;
|
||||||
|
|
||||||
void UpdateInput() override;
|
Core::DeviceRemoval UpdateInput() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using Clock = std::chrono::steady_clock;
|
using Clock = std::chrono::steady_clock;
|
||||||
|
|
|
@ -264,7 +264,7 @@ std::string Device::GetSource() const
|
||||||
return "XInput";
|
return "XInput";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::UpdateInput()
|
Core::DeviceRemoval Device::UpdateInput()
|
||||||
{
|
{
|
||||||
PXInputGetState(m_index, &m_state_in);
|
PXInputGetState(m_index, &m_state_in);
|
||||||
|
|
||||||
|
@ -286,6 +286,8 @@ void Device::UpdateInput()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Core::DeviceRemoval::Keep;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::UpdateMotors()
|
void Device::UpdateMotors()
|
||||||
|
|
|
@ -33,7 +33,7 @@ public:
|
||||||
std::optional<int> GetPreferredId() const override;
|
std::optional<int> GetPreferredId() const override;
|
||||||
int GetSortPriority() const override { return -2; }
|
int GetSortPriority() const override { return -2; }
|
||||||
|
|
||||||
void UpdateInput() override;
|
Core::DeviceRemoval UpdateInput() override;
|
||||||
|
|
||||||
void UpdateMotors();
|
void UpdateMotors();
|
||||||
|
|
||||||
|
|
|
@ -275,7 +275,7 @@ void KeyboardMouse::UpdateCursor(bool should_center_mouse)
|
||||||
m_state.cursor.y = (win_y / win_height * 2 - 1) * window_scale.y;
|
m_state.cursor.y = (win_y / win_height * 2 - 1) * window_scale.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyboardMouse::UpdateInput()
|
Core::DeviceRemoval KeyboardMouse::UpdateInput()
|
||||||
{
|
{
|
||||||
XFlush(m_display);
|
XFlush(m_display);
|
||||||
|
|
||||||
|
@ -369,6 +369,8 @@ void KeyboardMouse::UpdateInput()
|
||||||
|
|
||||||
if (update_keyboard)
|
if (update_keyboard)
|
||||||
XQueryKeymap(m_display, m_state.keyboard.data());
|
XQueryKeymap(m_display, m_state.keyboard.data());
|
||||||
|
|
||||||
|
return Core::DeviceRemoval::Keep;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string KeyboardMouse::GetName() const
|
std::string KeyboardMouse::GetName() const
|
||||||
|
|
|
@ -111,7 +111,7 @@ private:
|
||||||
void UpdateCursor(bool should_center_mouse);
|
void UpdateCursor(bool should_center_mouse);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void UpdateInput() override;
|
Core::DeviceRemoval UpdateInput() override;
|
||||||
|
|
||||||
KeyboardMouse(Window window, int opcode, int pointer_deviceid, int keyboard_deviceid,
|
KeyboardMouse(Window window, int opcode, int pointer_deviceid, int keyboard_deviceid,
|
||||||
double scroll_increment);
|
double scroll_increment);
|
||||||
|
|
|
@ -674,7 +674,7 @@ void InputBackend::RemoveDevnodeObject(const std::string& node)
|
||||||
m_devnode_objects.erase(node);
|
m_devnode_objects.erase(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void evdevDevice::UpdateInput()
|
Core::DeviceRemoval evdevDevice::UpdateInput()
|
||||||
{
|
{
|
||||||
// Run through all evdev events
|
// Run through all evdev events
|
||||||
// libevdev will keep track of the actual controller state internally which can be queried
|
// libevdev will keep track of the actual controller state internally which can be queried
|
||||||
|
@ -691,6 +691,7 @@ void evdevDevice::UpdateInput()
|
||||||
rc = libevdev_next_event(node.device, LIBEVDEV_READ_FLAG_NORMAL, &ev);
|
rc = libevdev_next_event(node.device, LIBEVDEV_READ_FLAG_NORMAL, &ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return Core::DeviceRemoval::Keep;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool evdevDevice::IsValid() const
|
bool evdevDevice::IsValid() const
|
||||||
|
|
|
@ -72,7 +72,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void UpdateInput() override;
|
Core::DeviceRemoval UpdateInput() override;
|
||||||
bool IsValid() const override;
|
bool IsValid() const override;
|
||||||
|
|
||||||
evdevDevice(InputBackend* input_backend);
|
evdevDevice(InputBackend* input_backend);
|
||||||
|
|
|
@ -19,6 +19,26 @@ TCShaderUid GetShaderUid(EFBCopyFormat dst_format, bool is_depth_copy, bool is_i
|
||||||
TCShaderUid out;
|
TCShaderUid out;
|
||||||
|
|
||||||
UidData* const uid_data = out.GetUidData();
|
UidData* const uid_data = out.GetUidData();
|
||||||
|
if (g_ActiveConfig.bForceTrueColor)
|
||||||
|
{
|
||||||
|
// Increase the precision of EFB copies where it's likely to be safe.
|
||||||
|
switch (dst_format)
|
||||||
|
{
|
||||||
|
case EFBCopyFormat::RGB565:
|
||||||
|
// HACK: XFB is RGB8.
|
||||||
|
// Don't blindly do this in other places though,
|
||||||
|
// the enum value is used to identify XFB copies.
|
||||||
|
// The important thing here is that we need alpha = 1.
|
||||||
|
dst_format = EFBCopyFormat::XFB;
|
||||||
|
break;
|
||||||
|
case EFBCopyFormat::RGB5A3:
|
||||||
|
dst_format = EFBCopyFormat::RGBA8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Let's not touch the other formats for now, seems risky.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
uid_data->dst_format = dst_format;
|
uid_data->dst_format = dst_format;
|
||||||
uid_data->efb_has_alpha = bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24;
|
uid_data->efb_has_alpha = bpmem.zcontrol.pixel_format == PixelFormat::RGBA6_Z24;
|
||||||
uid_data->is_depth_copy = is_depth_copy;
|
uid_data->is_depth_copy = is_depth_copy;
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
// Copyright 2014 Dolphin Emulator Project
|
// Copyright 2014 Dolphin Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include "Common/BitSet.h"
|
#include "Common/BitSet.h"
|
||||||
|
@ -29,23 +32,39 @@ TEST(BitSet, BitGetSet)
|
||||||
|
|
||||||
TEST(BitSet, Count)
|
TEST(BitSet, Count)
|
||||||
{
|
{
|
||||||
u32 random_numbers[] = {0x2cb0b5f3, 0x81ab32a6, 0xd9030dc5, 0x325ffe26, 0xb2fcaee3,
|
constexpr std::array<std::pair<u32, u32>, 20> random_32bit_number_bitcount_pairs = {
|
||||||
0x4ccf188a, 0xf8be36dc, 0xb2fcecd5, 0xb750c2e5, 0x31d19074,
|
{{0x2cb0b5f3, 17}, {0x81ab32a6, 14}, {0xd9030dc5, 14}, {0x325ffe26, 19}, {0xb2fcaee3, 20},
|
||||||
0xf267644a, 0xac00a719, 0x6d45f19b, 0xf7e91c5b, 0xf687e694,
|
{0x4ccf188a, 14}, {0xf8be36dc, 20}, {0xb2fcecd5, 20}, {0xb750c2e5, 16}, {0x31d19074, 13},
|
||||||
0x9057c24e, 0x5eb65c39, 0x85d3038b, 0x101f4e66, 0xc202d136};
|
{0xf267644a, 16}, {0xac00a719, 12}, {0x6d45f19b, 18}, {0xf7e91c5b, 20}, {0xf687e694, 18},
|
||||||
u32 counts[] = {17, 14, 14, 19, 20, 14, 20, 20, 16, 13, 16, 12, 18, 20, 18, 14, 18, 14, 14, 12};
|
{0x9057c24e, 14}, {0x5eb65c39, 18}, {0x85d3038b, 14}, {0x101f4e66, 14}, {0xc202d136, 12}}};
|
||||||
for (size_t i = 0; i < 20; i++)
|
for (const auto& [number, bitcount] : random_32bit_number_bitcount_pairs)
|
||||||
{
|
{
|
||||||
EXPECT_EQ(counts[i], BitSet32(random_numbers[i]).Count());
|
const auto bitset = BitSet32(number);
|
||||||
|
EXPECT_EQ(bitset.Count(), bitcount);
|
||||||
|
u32 iterating_count = 0;
|
||||||
|
for (auto iter = bitset.begin(); iter != bitset.end(); ++iter)
|
||||||
|
++iterating_count;
|
||||||
|
EXPECT_EQ(iterating_count, bitcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 random_numbers_64[] = {0xf86cd6f6ef09d7d4ULL, 0x6f2d8533255ead3cULL, 0x9da7941e0e52b345ULL,
|
constexpr std::array<std::pair<u64, u32>, 9> random_64bit_number_bitcount_pairs = {
|
||||||
0x06e4189be67d2b17ULL, 0x3eb0681f65cb6d25ULL, 0xccab8a7c74a51203ULL,
|
{{0xf86cd6f6ef09d7d4ULL, 39},
|
||||||
0x09d470516694c64bULL, 0x38cd077e075c778fULL, 0xd69ebfa6355ebfdeULL};
|
{0x6f2d8533255ead3cULL, 34},
|
||||||
u32 counts_64[] = {39, 34, 31, 32, 33, 29, 27, 35, 43};
|
{0x9da7941e0e52b345ULL, 31},
|
||||||
for (size_t i = 0; i < 9; i++)
|
{0x06e4189be67d2b17ULL, 32},
|
||||||
|
{0x3eb0681f65cb6d25ULL, 33},
|
||||||
|
{0xccab8a7c74a51203ULL, 29},
|
||||||
|
{0x09d470516694c64bULL, 27},
|
||||||
|
{0x38cd077e075c778fULL, 35},
|
||||||
|
{0xd69ebfa6355ebfdeULL, 43}}};
|
||||||
|
for (const auto& [number, bitcount] : random_64bit_number_bitcount_pairs)
|
||||||
{
|
{
|
||||||
EXPECT_EQ(counts_64[i], BitSet64(random_numbers_64[i]).Count());
|
const auto bitset = BitSet64(number);
|
||||||
|
EXPECT_EQ(bitset.Count(), bitcount);
|
||||||
|
u32 iterating_count = 0;
|
||||||
|
for (auto iter = bitset.begin(); iter != bitset.end(); ++iter)
|
||||||
|
++iterating_count;
|
||||||
|
EXPECT_EQ(iterating_count, bitcount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue