mirror of
https://github.com/BillyOutlast/aps3e.git
synced 2026-07-01 13:20:07 -04:00
sync
This commit is contained in:
@@ -216,7 +216,7 @@ public:
|
||||
|
||||
// Apply patch (returns the number of entries applied)
|
||||
void apply(std::vector<u32>& applied_total, const std::string& name, std::function<u8*(u32, u32)> mem_translate, u32 filesz = -1, u32 min_addr = 0);
|
||||
|
||||
|
||||
// Deallocate memory used by patches
|
||||
void unload(const std::string& name);
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "cond.h"
|
||||
#include "sync.h"
|
||||
|
||||
// use constants, increase signal space
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <util/types.hpp>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// Patch utilities specific to PPU code
|
||||
|
||||
@@ -84,9 +84,8 @@ public:
|
||||
transactional_storage& operator=(const transactional_storage&) = delete;
|
||||
|
||||
transactional_storage(transactional_storage&& other)
|
||||
: pool(std::move(other.pool))
|
||||
{
|
||||
pool = std::move(other.pool);
|
||||
|
||||
std::unique_lock lock_other{other.current_mutex};
|
||||
const std::shared_ptr<T> other_current = other.current;
|
||||
other.current = nullptr;
|
||||
|
||||
@@ -38,11 +38,17 @@ void fmt_class_string<CellAudioInError>::format(std::string& out, u64 arg)
|
||||
struct avconf_manager
|
||||
{
|
||||
shared_mutex mutex;
|
||||
std::vector<CellAudioInDeviceInfo> devices;
|
||||
|
||||
struct device_info
|
||||
{
|
||||
CellAudioInDeviceInfo info {};
|
||||
std::string full_device_name; // The device name may be too long for CellAudioInDeviceInfo, so we additionally save the full name.
|
||||
};
|
||||
std::vector<device_info> devices;
|
||||
CellAudioInDeviceMode inDeviceMode = CELL_AUDIO_IN_SINGLE_DEVICE_MODE; // TODO: use somewhere
|
||||
|
||||
void copy_device_info(u32 num, vm::ptr<CellAudioInDeviceInfo> info) const;
|
||||
std::optional<CellAudioInDeviceInfo> get_device_info(vm::cptr<char> name) const;
|
||||
std::optional<device_info> get_device_info(vm::cptr<char> name) const;
|
||||
|
||||
avconf_manager();
|
||||
|
||||
@@ -62,78 +68,89 @@ avconf_manager::avconf_manager()
|
||||
switch (g_cfg.audio.microphone_type)
|
||||
{
|
||||
case microphone_handler::standard:
|
||||
{
|
||||
for (u32 index = 0; index < mic_list.size(); index++)
|
||||
{
|
||||
devices.emplace_back();
|
||||
|
||||
devices[curindex].portType = CELL_AUDIO_IN_PORT_USB;
|
||||
devices[curindex].availableModeCount = 1;
|
||||
devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
devices[curindex].deviceId = 0xE11CC0DE + curindex;
|
||||
devices[curindex].type = 0xC0DEE11C;
|
||||
devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2;
|
||||
devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
devices[curindex].deviceNumber = curindex;
|
||||
strcpy_trunc(devices[curindex].name, mic_list[index]);
|
||||
device_info device {};
|
||||
device.info.portType = CELL_AUDIO_IN_PORT_USB;
|
||||
device.info.availableModeCount = 1;
|
||||
device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
device.info.deviceId = 0xE11CC0DE + curindex;
|
||||
device.info.type = 0xC0DEE11C;
|
||||
device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2;
|
||||
device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
device.info.deviceNumber = curindex;
|
||||
device.full_device_name = mic_list[index];
|
||||
strcpy_trunc(device.info.name, device.full_device_name);
|
||||
|
||||
devices.push_back(std::move(device));
|
||||
curindex++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case microphone_handler::real_singstar:
|
||||
case microphone_handler::singstar:
|
||||
{
|
||||
// Only one device for singstar device
|
||||
devices.emplace_back();
|
||||
|
||||
devices[curindex].portType = CELL_AUDIO_IN_PORT_USB;
|
||||
devices[curindex].availableModeCount = 1;
|
||||
devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
devices[curindex].deviceId = 0x00000001;
|
||||
devices[curindex].type = 0x14150000;
|
||||
devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2;
|
||||
devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
devices[curindex].deviceNumber = curindex;
|
||||
strcpy_trunc(devices[curindex].name, mic_list[0]);
|
||||
device_info device {};
|
||||
device.info.portType = CELL_AUDIO_IN_PORT_USB;
|
||||
device.info.availableModeCount = 1;
|
||||
device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
device.info.deviceId = 0x00000001;
|
||||
device.info.type = 0x14150000;
|
||||
device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2;
|
||||
device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
device.info.deviceNumber = curindex;
|
||||
device.full_device_name = mic_list[0];
|
||||
strcpy_trunc(device.info.name, device.full_device_name);
|
||||
|
||||
devices.push_back(std::move(device));
|
||||
curindex++;
|
||||
break;
|
||||
}
|
||||
case microphone_handler::rocksmith:
|
||||
devices.emplace_back();
|
||||
|
||||
devices[curindex].portType = CELL_AUDIO_IN_PORT_USB;
|
||||
devices[curindex].availableModeCount = 1;
|
||||
devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
devices[curindex].deviceId = 0x12BA00FF; // Specific to rocksmith usb input
|
||||
devices[curindex].type = 0xC0DE73C4;
|
||||
devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_1;
|
||||
devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
devices[curindex].deviceNumber = curindex;
|
||||
strcpy_trunc(devices[curindex].name, mic_list[0]);
|
||||
{
|
||||
device_info device {};
|
||||
device.info.portType = CELL_AUDIO_IN_PORT_USB;
|
||||
device.info.availableModeCount = 1;
|
||||
device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
device.info.deviceId = 0x12BA00FF; // Specific to rocksmith usb input
|
||||
device.info.type = 0xC0DE73C4;
|
||||
device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_1;
|
||||
device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
device.info.deviceNumber = curindex;
|
||||
device.full_device_name = mic_list[0];
|
||||
strcpy_trunc(device.info.name, device.full_device_name);
|
||||
|
||||
devices.push_back(std::move(device));
|
||||
curindex++;
|
||||
break;
|
||||
}
|
||||
case microphone_handler::null:
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_cfg.io.camera != camera_handler::null)
|
||||
{
|
||||
devices.emplace_back();
|
||||
|
||||
devices[curindex].portType = CELL_AUDIO_IN_PORT_USB;
|
||||
devices[curindex].availableModeCount = 1;
|
||||
devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
devices[curindex].deviceId = 0xDEADBEEF;
|
||||
devices[curindex].type = 0xBEEFDEAD;
|
||||
devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_NONE;
|
||||
devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
devices[curindex].deviceNumber = curindex;
|
||||
strcpy_trunc(devices[curindex].name, "USB Camera");
|
||||
device_info device {};
|
||||
device.info.portType = CELL_AUDIO_IN_PORT_USB;
|
||||
device.info.availableModeCount = 1;
|
||||
device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
|
||||
device.info.deviceId = 0xDEADBEEF;
|
||||
device.info.type = 0xBEEFDEAD;
|
||||
device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
|
||||
device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_NONE;
|
||||
device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
|
||||
device.info.deviceNumber = curindex;
|
||||
device.full_device_name = "USB Camera";
|
||||
strcpy_trunc(device.info.name, device.full_device_name);
|
||||
|
||||
devices.push_back(std::move(device));
|
||||
curindex++;
|
||||
}
|
||||
}
|
||||
@@ -142,14 +159,14 @@ void avconf_manager::copy_device_info(u32 num, vm::ptr<CellAudioInDeviceInfo> in
|
||||
{
|
||||
memset(info.get_ptr(), 0, sizeof(CellAudioInDeviceInfo));
|
||||
ensure(num < devices.size());
|
||||
*info = devices[num];
|
||||
*info = devices[num].info;
|
||||
}
|
||||
|
||||
std::optional<CellAudioInDeviceInfo> avconf_manager::get_device_info(vm::cptr<char> name) const
|
||||
std::optional<avconf_manager::device_info> avconf_manager::get_device_info(vm::cptr<char> name) const
|
||||
{
|
||||
for (const CellAudioInDeviceInfo& device : devices)
|
||||
for (const device_info& device : devices)
|
||||
{
|
||||
if (strncmp(device.name, name.get_ptr(), sizeof(device.name)) == 0)
|
||||
if (strncmp(device.info.name, name.get_ptr(), sizeof(device.info.name)) == 0)
|
||||
{
|
||||
return device;
|
||||
}
|
||||
@@ -220,17 +237,57 @@ error_code cellAudioInGetDeviceInfo(u32 deviceNumber, u32 deviceIndex, vm::ptr<C
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
template <bool Is_Float, bool Range_Limited>
|
||||
void convert_cursor_color(const u8* src, u8* dst, s32 num, f32 gamma)
|
||||
{
|
||||
for (s32 i = 0; i < num; i++, src += 4, dst += 4)
|
||||
{
|
||||
for (s32 c = 1; c < 4; c++)
|
||||
{
|
||||
if constexpr (Is_Float)
|
||||
{
|
||||
if constexpr (Range_Limited)
|
||||
{
|
||||
const f32 val = (src[c] / 255.0f) * 219.0f + 16.0f;
|
||||
dst[c] = static_cast<u8>(val + 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[c] = src[c];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
f32 val = std::clamp(std::pow(src[c] / 255.0f, gamma), 0.0f, 1.0f);
|
||||
|
||||
if constexpr (Range_Limited)
|
||||
{
|
||||
val = val * 219.0f + 16.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
val *= 255.0f;
|
||||
}
|
||||
|
||||
dst[c] = static_cast<u8>(val + 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error_code cellVideoOutConvertCursorColor(u32 videoOut, s32 displaybuffer_format, f32 gamma, s32 source_buffer_format, vm::ptr<void> src_addr, vm::ptr<u32> dest_addr, s32 num)
|
||||
{
|
||||
cellAvconfExt.todo("cellVideoOutConvertCursorColor(videoOut=%d, displaybuffer_format=0x%x, gamma=0x%x, source_buffer_format=0x%x, src_addr=*0x%x, dest_addr=*0x%x, num=0x%x)", videoOut,
|
||||
cellAvconfExt.warning("cellVideoOutConvertCursorColor(videoOut=%d, displaybuffer_format=0x%x, gamma=%f, source_buffer_format=0x%x, src_addr=*0x%x, dest_addr=*0x%x, num=0x%x)", videoOut,
|
||||
displaybuffer_format, gamma, source_buffer_format, src_addr, dest_addr, num);
|
||||
|
||||
if (!dest_addr || num == 0)
|
||||
if (!src_addr || !dest_addr)
|
||||
{
|
||||
return CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER;
|
||||
}
|
||||
|
||||
if (displaybuffer_format > CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT || src_addr)
|
||||
if (displaybuffer_format < 0 ||
|
||||
displaybuffer_format > CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT ||
|
||||
source_buffer_format != CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8)
|
||||
{
|
||||
return CELL_VIDEO_OUT_ERROR_PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
@@ -251,6 +308,32 @@ error_code cellVideoOutConvertCursorColor(u32 videoOut, s32 displaybuffer_format
|
||||
return error;
|
||||
}
|
||||
|
||||
const u8* src = reinterpret_cast<const u8*>(src_addr.get_ptr());
|
||||
u8* dst = reinterpret_cast<u8*>(dest_addr.get_ptr());
|
||||
|
||||
if (displaybuffer_format == CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT)
|
||||
{
|
||||
if (*rgbOutputRange == CELL_VIDEO_OUT_RGB_OUTPUT_RANGE_LIMITED)
|
||||
{
|
||||
convert_cursor_color<true, true>(src, dst, num, gamma);
|
||||
}
|
||||
else
|
||||
{
|
||||
convert_cursor_color<true, false>(src, dst, num, gamma);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*rgbOutputRange == CELL_VIDEO_OUT_RGB_OUTPUT_RANGE_LIMITED)
|
||||
{
|
||||
convert_cursor_color<false, true>(src, dst, num, gamma);
|
||||
}
|
||||
else
|
||||
{
|
||||
convert_cursor_color<false, false>(src, dst, num, gamma);
|
||||
}
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -398,8 +481,8 @@ error_code cellAudioInRegisterDevice(u64 deviceType, vm::cptr<char> name, vm::pt
|
||||
auto& av_manager = g_fxo->get<avconf_manager>();
|
||||
const std::lock_guard lock(av_manager.mutex);
|
||||
|
||||
std::optional<CellAudioInDeviceInfo> info = av_manager.get_device_info(name);
|
||||
if (!info || !memchr(info->name, '\0', sizeof(info->name)))
|
||||
std::optional<avconf_manager::device_info> device = av_manager.get_device_info(name);
|
||||
if (!device)
|
||||
{
|
||||
// TODO
|
||||
return CELL_AUDIO_IN_ERROR_DEVICE_NOT_FOUND;
|
||||
@@ -407,7 +490,7 @@ error_code cellAudioInRegisterDevice(u64 deviceType, vm::cptr<char> name, vm::pt
|
||||
|
||||
auto& mic_thr = g_fxo->get<mic_thread>();
|
||||
const std::lock_guard mic_lock(mic_thr.mutex);
|
||||
const u32 device_number = mic_thr.register_device(info->name);
|
||||
const u32 device_number = mic_thr.register_device(device->full_device_name);
|
||||
|
||||
return not_an_error(device_number);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
#include "Emu/Cell/lv2/sys_event.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Cell/timers.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
@@ -60,11 +61,6 @@ void fmt_class_string<CellCameraFormat>::format(std::string& out, u64 arg)
|
||||
});
|
||||
}
|
||||
|
||||
// Temporarily
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#endif
|
||||
|
||||
// **************
|
||||
// * Prototypes *
|
||||
// **************
|
||||
@@ -148,9 +144,44 @@ void camera_context::save(utils::serial& ar)
|
||||
return;
|
||||
}
|
||||
|
||||
GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellCamera);
|
||||
const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellCamera);
|
||||
|
||||
ar(notify_data_map, start_timestamp_us, read_mode, is_streaming, is_attached, is_open, info, attr, frame_num);
|
||||
|
||||
if (ar.is_writing() || version >= 2)
|
||||
{
|
||||
ar(is_attached_dirty);
|
||||
}
|
||||
|
||||
if (!ar.is_writing())
|
||||
{
|
||||
if (is_open)
|
||||
{
|
||||
if (!open_camera())
|
||||
{
|
||||
cellCamera.error("Failed to open camera while loading savestate");
|
||||
}
|
||||
else if (is_streaming && !start_camera())
|
||||
{
|
||||
cellCamera.error("Failed to start camera while loading savestate");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gem_camera_shared::gem_camera_shared(utils::serial& ar)
|
||||
{
|
||||
save(ar);
|
||||
}
|
||||
|
||||
void gem_camera_shared::save(utils::serial& ar)
|
||||
{
|
||||
const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellCamera);
|
||||
|
||||
if (ar.is_writing() || version >= 2)
|
||||
{
|
||||
ar(frame_timestamp_us, width, height, size, format);
|
||||
}
|
||||
}
|
||||
|
||||
static bool check_dev_num(s32 dev_num)
|
||||
@@ -366,7 +397,7 @@ error_code check_init_and_open(s32 dev_num)
|
||||
}
|
||||
|
||||
// This represents a recurring subfunction throughout libCamera
|
||||
error_code check_resolution(s32 dev_num)
|
||||
error_code check_resolution(s32 /*dev_num*/)
|
||||
{
|
||||
// TODO: Some sort of connection check maybe?
|
||||
//if (error == CELL_CAMERA_ERROR_RESOLUTION_UNKNOWN)
|
||||
@@ -377,7 +408,7 @@ error_code check_resolution(s32 dev_num)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
// This represents a oftenly used sequence in libCamera (usually the beginning of a subfunction).
|
||||
// This represents an often used sequence in libCamera (usually the beginning of a subfunction).
|
||||
// There also exist common sequences for mutex lock/unlock by the way.
|
||||
error_code check_resolution_ex(s32 dev_num)
|
||||
{
|
||||
@@ -435,7 +466,6 @@ error_code cellCameraInit()
|
||||
g_camera.attr[CELL_CAMERA_USBLOAD] = { 4 };
|
||||
break;
|
||||
}
|
||||
|
||||
case fake_camera_type::eyetoy2:
|
||||
{
|
||||
g_camera.attr[CELL_CAMERA_SATURATION] = { 64 };
|
||||
@@ -455,7 +485,6 @@ error_code cellCameraInit()
|
||||
g_camera.attr[CELL_CAMERA_AGCHIGH] = { 64 };
|
||||
break;
|
||||
}
|
||||
|
||||
case fake_camera_type::uvc1_1:
|
||||
{
|
||||
g_camera.attr[CELL_CAMERA_DEVICEID] = { 0x5ca, 0x18d0 }; // KBCR-S01MU
|
||||
@@ -463,14 +492,14 @@ error_code cellCameraInit()
|
||||
g_camera.attr[CELL_CAMERA_NUMFRAME] = { 1 }; // Amount of supported resolutions
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
cellCamera.todo("Trying to init cellCamera with un-researched camera type.");
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Some other default attributes? Need to check the actual behaviour on a real PS3.
|
||||
|
||||
g_camera.is_attached = true;
|
||||
g_camera.is_attached = g_cfg.io.camera != camera_handler::null;
|
||||
g_camera.init = 1;
|
||||
return CELL_OK;
|
||||
}
|
||||
@@ -784,26 +813,26 @@ s32 cellCameraIsAttached(s32 dev_num)
|
||||
|
||||
if (g_cfg.io.camera == camera_handler::null)
|
||||
{
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto& g_camera = g_fxo->get<camera_thread>();
|
||||
|
||||
if (!g_camera.init)
|
||||
{
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!check_dev_num(dev_num))
|
||||
{
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
vm::var<s32> type;
|
||||
|
||||
if (cellCameraGetType(dev_num, type) != CELL_OK)
|
||||
{
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::lock_guard lock(g_camera.mutex);
|
||||
@@ -816,17 +845,17 @@ s32 cellCameraIsAttached(s32 dev_num)
|
||||
// normally should be attached immediately after event queue is registered, but just to be sure
|
||||
if (!is_attached)
|
||||
{
|
||||
g_camera.send_attach_state(true);
|
||||
is_attached = g_camera.is_attached;
|
||||
g_camera.is_attached = is_attached = true;
|
||||
g_camera.is_attached_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
return is_attached;
|
||||
return is_attached ? 1 : 0;
|
||||
}
|
||||
|
||||
s32 cellCameraIsOpen(s32 dev_num)
|
||||
{
|
||||
cellCamera.notice("cellCameraIsOpen(dev_num=%d)", dev_num);
|
||||
cellCamera.trace("cellCameraIsOpen(dev_num=%d)", dev_num);
|
||||
|
||||
if (g_cfg.io.camera == camera_handler::null)
|
||||
{
|
||||
@@ -852,7 +881,7 @@ s32 cellCameraIsOpen(s32 dev_num)
|
||||
|
||||
s32 cellCameraIsStarted(s32 dev_num)
|
||||
{
|
||||
cellCamera.notice("cellCameraIsStarted(dev_num=%d)", dev_num);
|
||||
cellCamera.trace("cellCameraIsStarted(dev_num=%d)", dev_num);
|
||||
|
||||
if (g_cfg.io.camera == camera_handler::null)
|
||||
{
|
||||
@@ -1606,9 +1635,15 @@ void camera_context::operator()()
|
||||
{
|
||||
while (thread_ctrl::state() != thread_state::aborting && !Emu.IsStopped())
|
||||
{
|
||||
// send ATTACH event
|
||||
if (init && is_attached_dirty && !Emu.IsPausedOrReady())
|
||||
{
|
||||
send_attach_state(is_attached);
|
||||
}
|
||||
|
||||
const s32 fps = info.framerate;
|
||||
|
||||
if (!fps || Emu.IsPausedOrReady() || g_cfg.io.camera == camera_handler::null)
|
||||
if (!init || !fps || Emu.IsPausedOrReady() || g_cfg.io.camera == camera_handler::null)
|
||||
{
|
||||
thread_ctrl::wait_for(1000); // hack
|
||||
continue;
|
||||
@@ -1783,6 +1818,7 @@ void camera_context::reset_state()
|
||||
read_mode = CELL_CAMERA_READ_FUNCCALL;
|
||||
is_streaming = false;
|
||||
is_attached = false;
|
||||
is_attached_dirty = false;
|
||||
is_open = false;
|
||||
info.framerate = 0;
|
||||
std::memset(&attr, 0, sizeof(attr));
|
||||
@@ -1828,6 +1864,7 @@ void camera_context::send_attach_state(bool attached)
|
||||
|
||||
// We're not expected to send any events for attaching/detaching
|
||||
is_attached = attached;
|
||||
is_attached_dirty = false;
|
||||
}
|
||||
|
||||
void camera_context::set_attr(s32 attrib, u32 arg1, u32 arg2)
|
||||
@@ -1862,15 +1899,13 @@ void camera_context::set_attr(s32 attrib, u32 arg1, u32 arg2)
|
||||
|
||||
void camera_context::add_queue(u64 key, u64 source, u64 flag)
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
{
|
||||
std::lock_guard lock_data_map(mutex_notify_data_map);
|
||||
|
||||
notify_data_map[key] = { source, flag };
|
||||
}
|
||||
|
||||
// send ATTACH event - HACKY
|
||||
send_attach_state(is_attached);
|
||||
is_attached_dirty = true;
|
||||
}
|
||||
|
||||
void camera_context::remove_queue(u64 key)
|
||||
@@ -1897,7 +1932,8 @@ bool camera_context::on_handler_state(camera_handler_base::camera_handler_state
|
||||
{
|
||||
if (is_attached)
|
||||
{
|
||||
send_attach_state(false);
|
||||
is_attached = false;
|
||||
is_attached_dirty = true;
|
||||
}
|
||||
if (handler)
|
||||
{
|
||||
@@ -1938,7 +1974,8 @@ bool camera_context::on_handler_state(camera_handler_base::camera_handler_state
|
||||
if (!is_attached)
|
||||
{
|
||||
cellCamera.warning("Camera handler not attached. Sending attach event...", static_cast<int>(state));
|
||||
send_attach_state(true);
|
||||
is_attached = true;
|
||||
is_attached_dirty = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/Timer.h"
|
||||
#include "Emu/Cell/lv2/sys_memory.h"
|
||||
#include "Utilities/Thread.h"
|
||||
#include "Emu/Io/camera_handler_base.h"
|
||||
#include "Emu/Memory/vm_ptr.h"
|
||||
#include "Utilities/mutex.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
@@ -427,6 +427,7 @@ public:
|
||||
atomic_t<u8> read_mode{CELL_CAMERA_READ_FUNCCALL};
|
||||
atomic_t<bool> is_streaming{false};
|
||||
atomic_t<bool> is_attached{false};
|
||||
atomic_t<bool> is_attached_dirty{false};
|
||||
atomic_t<bool> is_open{false};
|
||||
|
||||
CellCameraInfoEx info{};
|
||||
@@ -471,6 +472,13 @@ using camera_thread = named_thread<camera_context>;
|
||||
/// Shared data between cellGem and cellCamera
|
||||
struct gem_camera_shared
|
||||
{
|
||||
gem_camera_shared() {}
|
||||
gem_camera_shared(utils::serial& ar);
|
||||
|
||||
void save(utils::serial& ar);
|
||||
|
||||
SAVESTATE_INIT_POS(7);
|
||||
|
||||
atomic_t<u64> frame_timestamp_us{}; // latest read timestamp from cellCamera (cellCameraRead(Ex))
|
||||
atomic_t<s32> width{640};
|
||||
atomic_t<s32> height{480};
|
||||
|
||||
@@ -107,13 +107,8 @@ struct cross_controller
|
||||
|
||||
void stop_thread()
|
||||
{
|
||||
if (connection_thread)
|
||||
{
|
||||
auto& thread = *connection_thread;
|
||||
thread = thread_state::aborting;
|
||||
thread();
|
||||
connection_thread.reset();
|
||||
}
|
||||
// Join thread
|
||||
connection_thread.reset();
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/RSX/Overlays/overlay_cursor.h"
|
||||
#include "Input/pad_thread.h"
|
||||
#include "Emu/Cell/lv2/sys_memory.h"
|
||||
|
||||
#ifdef HAVE_LIBEVDEV
|
||||
#include "Input/evdev_gun_handler.h"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "Emu/Io/pad_types.h"
|
||||
|
||||
#include <array>
|
||||
#include "util/types.hpp"
|
||||
|
||||
enum CellPadError : u32
|
||||
{
|
||||
@@ -42,13 +41,13 @@ enum
|
||||
|
||||
struct pad_data_internal
|
||||
{
|
||||
u16 vendor_id;
|
||||
u16 product_id;
|
||||
u32 port_status;
|
||||
u32 device_capability;
|
||||
u32 device_type;
|
||||
u32 pclass_type;
|
||||
u32 pclass_profile;
|
||||
u16 vendor_id = 0;
|
||||
u16 product_id = 0;
|
||||
u32 port_status = 0;
|
||||
u32 device_capability = 0;
|
||||
u32 device_type = 0;
|
||||
u32 pclass_type = 0;
|
||||
u32 pclass_profile = 0;
|
||||
|
||||
ENABLE_BITWISE_SERIALIZATION;
|
||||
};
|
||||
|
||||
@@ -828,13 +828,8 @@ void rec_info::stop_video_provider(bool flush)
|
||||
{
|
||||
cellRec.notice("Stopping video provider.");
|
||||
|
||||
if (video_provider_thread)
|
||||
{
|
||||
auto& thread = *video_provider_thread;
|
||||
thread = thread_state::aborting;
|
||||
thread();
|
||||
video_provider_thread.reset();
|
||||
}
|
||||
// Join thread
|
||||
video_provider_thread.reset();
|
||||
|
||||
// Flush the ringbuffer if necessary.
|
||||
// This should only happen if the video sink is not the encoder itself.
|
||||
|
||||
@@ -700,11 +700,32 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncFixed funcFixed, PFuncStat funcStat,
|
||||
PFuncFile funcFile, u32 container, u32 unk_op_flags /*TODO*/, vm::ptr<void> userdata, u32 userId, PFuncDone funcDone)
|
||||
{
|
||||
if (const auto& [ok, list] = setList.try_read(); ok)
|
||||
cellSaveData.notice("savedata_op(): setList = { .sortType=%d, .sortOrder=%d, .dirNamePrefix='%s' }", list.sortType, list.sortOrder, list.dirNamePrefix);
|
||||
if (setList)
|
||||
{
|
||||
if (const auto& [ok, list] = setList.try_read(); ok)
|
||||
{
|
||||
cellSaveData.notice("savedata_op(): setList = { .sortType=%d, .sortOrder=%d, .dirNamePrefix='%s' }", list.sortType, list.sortOrder, list.dirNamePrefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
cellSaveData.error("savedata_op(): Failed to read setList!");
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto& [ok, buf] = setBuf.try_read(); ok)
|
||||
cellSaveData.notice("savedata_op(): setBuf = { .dirListMax=%d, .fileListMax=%d, .bufSize=%d }", buf.dirListMax, buf.fileListMax, buf.bufSize);
|
||||
if (setBuf)
|
||||
{
|
||||
if (const auto& [ok, buf] = setBuf.try_read(); ok)
|
||||
{
|
||||
cellSaveData.notice("savedata_op(): setBuf = { .dirListMax=%d, .fileListMax=%d, .bufSize=%d }", buf.dirListMax, buf.fileListMax, buf.bufSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
cellSaveData.error("savedata_op(): Failed to read setBuf!");
|
||||
}
|
||||
}
|
||||
|
||||
// There is a lot going on in this function, ensure function log and past log commands have completed for ease of debugging
|
||||
logs::listener::sync_all();
|
||||
|
||||
if (const auto ecode = savedata_check_args(operation, version, dirName, errDialog, setList, setBuf, funcList, funcFixed, funcStat,
|
||||
funcFile, container, unk_op_flags, userdata, userId, funcDone))
|
||||
@@ -858,25 +879,34 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
const u32 order = setList->sortOrder;
|
||||
const u32 type = setList->sortType;
|
||||
|
||||
std::sort(save_entries.begin(), save_entries.end(), [=](const SaveDataEntry& entry1, const SaveDataEntry& entry2)
|
||||
std::sort(save_entries.begin(), save_entries.end(), [order, type](const SaveDataEntry& entry1, const SaveDataEntry& entry2) -> bool
|
||||
{
|
||||
if (order == CELL_SAVEDATA_SORTORDER_DESCENT && type == CELL_SAVEDATA_SORTTYPE_MODIFIEDTIME)
|
||||
const bool mtime_lower = entry1.mtime < entry2.mtime;
|
||||
const bool mtime_equal = entry1.mtime == entry2.mtime;
|
||||
const bool subtitle_lower = entry1.subtitle < entry2.subtitle;
|
||||
const bool subtitle_equal = entry1.subtitle == entry2.subtitle;
|
||||
const bool revert_order = order == CELL_SAVEDATA_SORTORDER_DESCENT;
|
||||
|
||||
if (type == CELL_SAVEDATA_SORTTYPE_MODIFIEDTIME)
|
||||
{
|
||||
return entry1.mtime >= entry2.mtime;
|
||||
if (mtime_equal)
|
||||
{
|
||||
return subtitle_lower != revert_order;
|
||||
}
|
||||
|
||||
return mtime_lower != revert_order;
|
||||
}
|
||||
if (order == CELL_SAVEDATA_SORTORDER_DESCENT && type == CELL_SAVEDATA_SORTTYPE_SUBTITLE)
|
||||
else if (type == CELL_SAVEDATA_SORTTYPE_SUBTITLE)
|
||||
{
|
||||
return entry1.subtitle >= entry2.subtitle;
|
||||
}
|
||||
if (order == CELL_SAVEDATA_SORTORDER_ASCENT && type == CELL_SAVEDATA_SORTTYPE_MODIFIEDTIME)
|
||||
{
|
||||
return entry1.mtime < entry2.mtime;
|
||||
}
|
||||
if (order == CELL_SAVEDATA_SORTORDER_ASCENT && type == CELL_SAVEDATA_SORTTYPE_SUBTITLE)
|
||||
{
|
||||
return entry1.subtitle < entry2.subtitle;
|
||||
if (subtitle_equal)
|
||||
{
|
||||
return mtime_lower != revert_order;
|
||||
}
|
||||
|
||||
return subtitle_lower != revert_order;
|
||||
}
|
||||
|
||||
ensure(false);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1220,7 +1220,7 @@ error_code cellVdecGetPictureExt(ppu_thread& ppu, u32 handle, vm::cptr<CellVdecP
|
||||
|
||||
if (arg4 || format->unk0 || format->unk1)
|
||||
{
|
||||
fmt::throw_exception("cellVdecGetPictureExt: Unknown arguments (arg4=*0x%x, unk0=0x%x, unk1=0x%x)", arg4, format->unk0, format->unk1);
|
||||
cellVdec.todo("cellVdecGetPictureExt: Unknown arguments (arg4=*0x%x, unk0=0x%x, unk1=0x%x)", arg4, format->unk0, format->unk1);
|
||||
}
|
||||
|
||||
vdec_frame frame;
|
||||
|
||||
@@ -4265,7 +4265,7 @@ error_code sceNpManagerGetEntitlementById(vm::cptr<char> entId, vm::ptr<SceNpEnt
|
||||
return SCE_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
return SCE_NP_ERROR_ID_NOT_FOUND;
|
||||
}
|
||||
|
||||
error_code sceNpManagerGetSigninId(vm::ptr<void> signInId)
|
||||
|
||||
@@ -59,13 +59,7 @@ struct sce_np_util_manager
|
||||
|
||||
void join_thread()
|
||||
{
|
||||
if (bandwidth_test_thread)
|
||||
{
|
||||
auto& thread = *bandwidth_test_thread;
|
||||
thread = thread_state::aborting;
|
||||
thread();
|
||||
bandwidth_test_thread.reset();
|
||||
}
|
||||
bandwidth_test_thread.reset();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ struct ppu_exec_select
|
||||
#define RETURN_(...) \
|
||||
if constexpr (Build == 0) { \
|
||||
static_cast<void>(exec); \
|
||||
if (is_debugger_present()) return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func* next_fn) { \
|
||||
if (is_debugger_present() || g_cfg.core.ppu_debug) return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func* next_fn) { \
|
||||
exec(__VA_ARGS__); \
|
||||
const auto next_op = this_op + 1; \
|
||||
const auto fn = atomic_storage<ppu_intrp_func_t>::load(next_fn->fn); \
|
||||
|
||||
@@ -5760,7 +5760,7 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module<lv2_obj>& module
|
||||
// Define some types
|
||||
const auto _func = FunctionType::get(translator.get_type<void>(), {
|
||||
translator.get_type<u8*>(), // Exec base
|
||||
translator.GetContextType()->getPointerTo(), // PPU context
|
||||
translator.get_type<u8*>(), // PPU context
|
||||
translator.get_type<u64>(), // Segment address (for PRX)
|
||||
translator.get_type<u8*>(), // Memory base
|
||||
translator.get_type<u64>(), // r0
|
||||
|
||||
@@ -340,7 +340,7 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module<lv2_obj>& info)
|
||||
|
||||
const auto ftype = FunctionType::get(get_type<void>(), {
|
||||
get_type<u8*>(), // Exec base
|
||||
GetContextType()->getPointerTo(), // PPU context
|
||||
m_ir->getPtrTy(), // PPU context
|
||||
get_type<u64>(), // Segment address (for PRX)
|
||||
get_type<u8*>(), // Memory base
|
||||
get_type<u64>(), // r0
|
||||
@@ -380,7 +380,7 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module<lv2_obj>& info)
|
||||
const auto addr_array = new GlobalVariable(*m_module, addr_array_type, false, GlobalValue::PrivateLinkage, ConstantDataArray::get(m_context, vec_addrs));
|
||||
|
||||
// Create an array of function pointers
|
||||
const auto func_table_type = ArrayType::get(ftype->getPointerTo(), functions.size());
|
||||
const auto func_table_type = ArrayType::get(m_ir->getPtrTy(), functions.size());
|
||||
const auto init_func_table = ConstantArray::get(func_table_type, functions);
|
||||
const auto func_table = new GlobalVariable(*m_module, func_table_type, false, GlobalVariable::PrivateLinkage, init_func_table);
|
||||
|
||||
@@ -407,18 +407,17 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module<lv2_obj>& info)
|
||||
const auto func_pc = ZExt(m_ir->CreateLoad(ptr_inst->getResultElementType(), ptr_inst), get_type<u64>());
|
||||
|
||||
ptr_inst = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(func_table->getValueType(), func_table, {m_ir->getInt64(0), index_value}));
|
||||
assert(ptr_inst->getResultElementType() == ftype->getPointerTo());
|
||||
assert(ptr_inst->getResultElementType() == m_ir->getPtrTy());
|
||||
|
||||
const auto faddr = m_ir->CreateLoad(ptr_inst->getResultElementType(), ptr_inst);
|
||||
const auto faddr_int = m_ir->CreatePtrToInt(faddr, get_type<uptr>());
|
||||
const auto pos_32 = m_reloc ? m_ir->CreateAdd(func_pc, m_seg0) : func_pc;
|
||||
const auto pos = m_ir->CreateShl(pos_32, 1);
|
||||
const auto ptr = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(get_type<u8>(), m_exec, pos));
|
||||
const auto ptr = m_ir->CreatePtrAdd(m_exec, pos);
|
||||
|
||||
const auto seg_base_ptr = m_ir->CreateIntToPtr(m_ir->CreateAdd(
|
||||
m_ir->CreatePtrToInt(m_exec, get_type<u64>()), m_ir->getInt64(vm::g_exec_addr_seg_offset)), m_exec->getType());
|
||||
const auto seg_base_ptr = m_ir->CreatePtrAdd(m_exec, m_ir->getInt64(vm::g_exec_addr_seg_offset));
|
||||
const auto seg_pos = m_ir->CreateLShr(pos_32, 1);
|
||||
const auto seg_ptr = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(get_type<u8>(), seg_base_ptr, seg_pos));
|
||||
const auto seg_ptr = m_ir->CreatePtrAdd(seg_base_ptr, seg_pos);
|
||||
const auto seg_val = m_ir->CreateTrunc(m_ir->CreateLShr(m_seg0, 13), get_type<u16>());
|
||||
|
||||
// Store to jumptable
|
||||
@@ -610,15 +609,14 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect)
|
||||
}
|
||||
|
||||
const auto pos = m_ir->CreateShl(indirect, 1);
|
||||
const auto ptr = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(get_type<u8>(), m_exec, pos));
|
||||
const auto ptr = m_ir->CreatePtrAdd(m_exec, pos);
|
||||
const auto val = m_ir->CreateLoad(get_type<u64>(), ptr);
|
||||
callee = FunctionCallee(type, m_ir->CreateIntToPtr(val, type->getPointerTo()));
|
||||
callee = FunctionCallee(type, m_ir->CreateIntToPtr(val, m_ir->getPtrTy()));
|
||||
|
||||
// Load new segment address
|
||||
const auto seg_base_ptr = m_ir->CreateIntToPtr(m_ir->CreateAdd(
|
||||
m_ir->CreatePtrToInt(m_exec, get_type<u64>()), m_ir->getInt64(vm::g_exec_addr_seg_offset)), m_exec->getType());
|
||||
const auto seg_base_ptr = m_ir->CreatePtrAdd(m_exec, m_ir->getInt64(vm::g_exec_addr_seg_offset));
|
||||
const auto seg_pos = m_ir->CreateLShr(indirect, 1);
|
||||
const auto seg_ptr = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(get_type<u8>(), seg_base_ptr, seg_pos));
|
||||
const auto seg_ptr = m_ir->CreatePtrAdd(seg_base_ptr, seg_pos);
|
||||
const auto seg_val = m_ir->CreateZExt(m_ir->CreateLoad(get_type<u16>(), seg_ptr), get_type<u64>());
|
||||
seg0 = m_ir->CreateShl(seg_val, 13);
|
||||
}
|
||||
@@ -824,7 +822,7 @@ void PPUTranslator::UseCondition(MDNode* hint, Value* cond)
|
||||
|
||||
llvm::Value* PPUTranslator::GetMemory(llvm::Value* addr)
|
||||
{
|
||||
return m_ir->CreateGEP(get_type<u8>(), m_base, addr);
|
||||
return m_ir->CreatePtrAdd(m_base, addr);
|
||||
}
|
||||
|
||||
void PPUTranslator::TestAborted()
|
||||
@@ -2794,8 +2792,8 @@ void PPUTranslator::MFOCRF(ppu_opcode_t op)
|
||||
else if (std::none_of(m_cr + 0, m_cr + 32, [](auto* p) { return p; }))
|
||||
{
|
||||
// MFCR (optimized)
|
||||
Value* ln0 = m_ir->CreateIntToPtr(m_ir->CreatePtrToInt(m_ir->CreateStructGEP(m_thread_type, m_thread, 99), GetType<uptr>()), GetType<u8[16]>()->getPointerTo());
|
||||
Value* ln1 = m_ir->CreateIntToPtr(m_ir->CreatePtrToInt(m_ir->CreateStructGEP(m_thread_type, m_thread, 115), GetType<uptr>()), GetType<u8[16]>()->getPointerTo());
|
||||
Value* ln0 = m_ir->CreateStructGEP(m_thread_type, m_thread, 99);
|
||||
Value* ln1 = m_ir->CreateStructGEP(m_thread_type, m_thread, 115);
|
||||
|
||||
ln0 = m_ir->CreateLoad(GetType<u8[16]>(), ln0);
|
||||
ln1 = m_ir->CreateLoad(GetType<u8[16]>(), ln1);
|
||||
@@ -5384,7 +5382,7 @@ MDNode* PPUTranslator::CheckBranchProbability(u32 bo)
|
||||
void PPUTranslator::build_interpreter()
|
||||
{
|
||||
#define BUILD_VEC_INST(i) { \
|
||||
m_function = llvm::cast<llvm::Function>(m_module->getOrInsertFunction("op_" #i, get_type<void>(), m_thread_type->getPointerTo()).getCallee()); \
|
||||
m_function = llvm::cast<llvm::Function>(m_module->getOrInsertFunction("op_" #i, get_type<void>(), m_ir->getPtrTy()).getCallee()); \
|
||||
std::fill(std::begin(m_globals), std::end(m_globals), nullptr); \
|
||||
std::fill(std::begin(m_locals), std::end(m_locals), nullptr); \
|
||||
IRBuilder<> irb(BasicBlock::Create(m_context, "__entry", m_function)); \
|
||||
|
||||
@@ -130,6 +130,18 @@ bool spu_thread::read_reg(const u32 addr, u32& value)
|
||||
return true;
|
||||
}
|
||||
|
||||
case Prxy_QueryMask_offs:
|
||||
{
|
||||
value = mfc_prxy_mask;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Prxy_QueryType_offs:
|
||||
{
|
||||
value = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
case SPU_Out_MBox_offs:
|
||||
{
|
||||
value = ch_out_mbox.pop();
|
||||
@@ -138,7 +150,29 @@ bool spu_thread::read_reg(const u32 addr, u32& value)
|
||||
|
||||
case SPU_MBox_Status_offs:
|
||||
{
|
||||
value = (ch_out_mbox.get_count() & 0xff) | ((4 - ch_in_mbox.get_count()) << 8 & 0xff00) | (ch_out_intr_mbox.get_count() << 16 & 0xff0000);
|
||||
// Load channel counts atomically
|
||||
auto counts = std::make_tuple(ch_out_mbox.get_count(), ch_in_mbox.get_count(), ch_out_intr_mbox.get_count());
|
||||
|
||||
while (true)
|
||||
{
|
||||
atomic_fence_acquire();
|
||||
|
||||
const auto counts_check = std::make_tuple(ch_out_mbox.get_count(), ch_in_mbox.get_count(), ch_out_intr_mbox.get_count());
|
||||
|
||||
if (counts_check == counts)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Update and reload
|
||||
counts = counts_check;
|
||||
}
|
||||
|
||||
const u32 out_mbox = std::get<0>(counts);
|
||||
const u32 in_mbox = 4 - std::get<1>(counts);
|
||||
const u32 intr_mbox = std::get<2>(counts);
|
||||
|
||||
value = (out_mbox & 0xff) | ((in_mbox << 8) & 0xff00) | ((intr_mbox << 16) & 0xff0000);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -345,6 +379,8 @@ bool spu_thread::test_is_problem_state_register_offset(u32 offset, bool for_read
|
||||
case MFC_QStatus_offs:
|
||||
case SPU_Out_MBox_offs:
|
||||
case SPU_MBox_Status_offs:
|
||||
case Prxy_QueryType_offs:
|
||||
case Prxy_QueryMask_offs:
|
||||
case SPU_Status_offs:
|
||||
case Prxy_TagStatus_offs:
|
||||
case SPU_NPC_offs:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4047,6 +4047,22 @@ void do_cell_atomic_128_store(u32 addr, const void* to_write)
|
||||
auto& sdata = *vm::get_super_ptr<spu_rdata_t>(addr);
|
||||
auto& res = *utils::bless<atomic_t<u128>>(vm::g_reservations + (addr & 0xff80) / 2);
|
||||
|
||||
if (std::memcmp(static_cast<const u8*>(to_write), &sdata, 16) == 0 && std::memcmp(static_cast<const u8*>(to_write) + 64, &sdata[64], 16) == 0)
|
||||
{
|
||||
const auto& write_data = *static_cast<const spu_rdata_t*>(to_write);
|
||||
const u64 at_read_time = vm::reservation_acquire(addr);
|
||||
|
||||
if (!(at_read_time & 127))
|
||||
{
|
||||
if (cmp_rdata(sdata, write_data) && at_read_time == vm::reservation_acquire(addr) && cmp_rdata(sdata, write_data))
|
||||
{
|
||||
// Write of the same data (verified atomically)
|
||||
vm::try_reservation_update(addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (u64 j = 0;; j++)
|
||||
{
|
||||
auto [_oldd, _ok] = res.fetch_op([&](u128& r)
|
||||
@@ -4636,7 +4652,7 @@ u32 evaluate_spin_optimization(std::span<u8> stats, u64 evaluate_time, const cfg
|
||||
add_count = 0;
|
||||
}
|
||||
|
||||
if (inclined_for_responsiveness && std::count(old_stats.data(), old_stats.data() + 3, 0) >= 2)
|
||||
if (stats.size() == 16 && inclined_for_responsiveness && std::count(old_stats.data(), old_stats.data() + 3, 0) >= 2)
|
||||
{
|
||||
add_count = 0;
|
||||
}
|
||||
@@ -4781,6 +4797,26 @@ bool spu_thread::process_mfc_cmd()
|
||||
return true;
|
||||
}
|
||||
|
||||
if (last_getllar != pc || last_getllar_lsa != ch_mfc_cmd.lsa)
|
||||
{
|
||||
getllar_busy_waiting_switch = umax;
|
||||
getllar_spin_count = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if LSA points to an OUT buffer on the stack from a caller - unlikely to be a loop
|
||||
if (last_getllar_lsa >= SPU_LS_SIZE - 0x10000 && last_getllar_lsa > last_getllar_gpr1)
|
||||
{
|
||||
auto cs = dump_callstack_list();
|
||||
|
||||
if (!cs.empty() && last_getllar_lsa > cs[0].second)
|
||||
{
|
||||
getllar_busy_waiting_switch = umax;
|
||||
getllar_spin_count = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
getllar_spin_count = std::min<u32>(getllar_spin_count + 1, u16{umax});
|
||||
|
||||
if (getllar_busy_waiting_switch == umax && getllar_spin_count == 4)
|
||||
@@ -4826,6 +4862,7 @@ bool spu_thread::process_mfc_cmd()
|
||||
|
||||
last_getllar = pc;
|
||||
last_getllar_gpr1 = gpr[1]._u32[3];
|
||||
last_getllar_lsa = ch_mfc_cmd.lsa;
|
||||
|
||||
if (getllar_busy_waiting_switch == 1)
|
||||
{
|
||||
@@ -6019,11 +6056,6 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||
|
||||
const usz seed = (utils::get_tsc() >> 8) % 100;
|
||||
|
||||
#ifdef __linux__
|
||||
const bool reservation_busy_waiting = false;
|
||||
#else
|
||||
const bool reservation_busy_waiting = (seed + ((raddr == spurs_addr) ? 50u : 0u)) < g_cfg.core.spu_reservation_busy_waiting_percentage;
|
||||
#endif
|
||||
usz cache_line_waiter_index = umax;
|
||||
|
||||
auto check_cache_line_waiter = [&]()
|
||||
@@ -6160,7 +6192,7 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||
{
|
||||
if (utils::has_waitpkg())
|
||||
{
|
||||
__tpause(std::min<u32>(eventstat_spin_count, 10) * 500, 0x1);
|
||||
__tpause(static_cast<u32>(std::min<u64>(eventstat_spin_count, 10) * 500), 0x1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -6173,7 +6205,7 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||
};
|
||||
|
||||
// Provide the first X64 cache line of the reservation to be tracked
|
||||
__mwaitx<check_wait_t>(std::min<u32>(eventstat_spin_count, 17) * 500, 0xf0, std::addressof(*resrv_mem), +rtime, vm::reservation_acquire(raddr));
|
||||
__mwaitx<check_wait_t>(static_cast<u32>(std::min<u64>(eventstat_spin_count, 17) * 500), 0xf0, std::addressof(*resrv_mem), +rtime, vm::reservation_acquire(raddr));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -6209,8 +6241,7 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||
}
|
||||
}
|
||||
|
||||
// Don't busy-wait with TSX - memory is sensitive
|
||||
if (g_use_rtm || !reservation_busy_waiting)
|
||||
if (true)
|
||||
{
|
||||
if (u32 work_count = g_spu_work_count)
|
||||
{
|
||||
@@ -6337,10 +6368,6 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
busy_wait();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -6814,7 +6841,7 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
|
||||
fmt::throw_exception("Unknown/illegal channel in WRCH (ch=%d [%s], value=0x%x)", ch, ch < 128 ? spu_ch_name[ch] : "???", value);
|
||||
}
|
||||
|
||||
extern void resume_spu_thread_group_from_waiting(spu_thread& spu)
|
||||
extern void resume_spu_thread_group_from_waiting(spu_thread& spu, std::array<shared_ptr<named_thread<spu_thread>>, 8>& notify_spus)
|
||||
{
|
||||
const auto group = spu.group;
|
||||
|
||||
@@ -6828,7 +6855,7 @@ extern void resume_spu_thread_group_from_waiting(spu_thread& spu)
|
||||
{
|
||||
group->run_state = SPU_THREAD_GROUP_STATUS_SUSPENDED;
|
||||
spu.state += cpu_flag::signal;
|
||||
spu.state.notify_one();
|
||||
ensure(spu.state & cpu_flag::suspend);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6846,7 +6873,7 @@ extern void resume_spu_thread_group_from_waiting(spu_thread& spu)
|
||||
thread->state -= cpu_flag::suspend;
|
||||
}
|
||||
|
||||
thread->state.notify_one();
|
||||
notify_spus[thread->index] = thread;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -802,6 +802,7 @@ public:
|
||||
u32 last_getllar = umax; // LS address of last GETLLAR (if matches current GETLLAR we can let the thread rest)
|
||||
u32 last_getllar_gpr1 = umax;
|
||||
u32 last_getllar_addr = umax;
|
||||
u32 last_getllar_lsa = umax;
|
||||
u32 getllar_spin_count = 0;
|
||||
u32 getllar_busy_waiting_switch = umax; // umax means the test needs evaluation, otherwise it's a boolean
|
||||
u64 getllar_evaluate_time = 0;
|
||||
|
||||
@@ -117,7 +117,7 @@ shared_ptr<lv2_event_queue> lv2_event_queue::find(u64 ipc_key)
|
||||
return g_fxo->get<ipc_manager<lv2_event_queue, u64>>().get(ipc_key);
|
||||
}
|
||||
|
||||
extern void resume_spu_thread_group_from_waiting(spu_thread& spu);
|
||||
extern void resume_spu_thread_group_from_waiting(spu_thread& spu, std::array<shared_ptr<named_thread<spu_thread>>, 8>& notify_spus);
|
||||
|
||||
CellError lv2_event_queue::send(lv2_event event, bool* notified_thread, lv2_event_port* port)
|
||||
{
|
||||
@@ -126,6 +126,22 @@ CellError lv2_event_queue::send(lv2_event event, bool* notified_thread, lv2_even
|
||||
*notified_thread = false;
|
||||
}
|
||||
|
||||
struct notify_spus_t
|
||||
{
|
||||
std::array<shared_ptr<named_thread<spu_thread>>, 8> spus;
|
||||
|
||||
~notify_spus_t() noexcept
|
||||
{
|
||||
for (auto& spu : spus)
|
||||
{
|
||||
if (spu && spu->state & cpu_flag::wait)
|
||||
{
|
||||
spu->state.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
} notify_spus{};
|
||||
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
if (!exists)
|
||||
@@ -199,7 +215,7 @@ CellError lv2_event_queue::send(lv2_event event, bool* notified_thread, lv2_even
|
||||
const u32 data2 = static_cast<u32>(std::get<2>(event));
|
||||
const u32 data3 = static_cast<u32>(std::get<3>(event));
|
||||
spu.ch_in_mbox.set_values(4, CELL_OK, data1, data2, data3);
|
||||
resume_spu_thread_group_from_waiting(spu);
|
||||
resume_spu_thread_group_from_waiting(spu, notify_spus.spus);
|
||||
}
|
||||
|
||||
return {};
|
||||
@@ -260,6 +276,22 @@ error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode)
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
struct notify_spus_t
|
||||
{
|
||||
std::array<shared_ptr<named_thread<spu_thread>>, 8> spus;
|
||||
|
||||
~notify_spus_t() noexcept
|
||||
{
|
||||
for (auto& spu : spus)
|
||||
{
|
||||
if (spu && spu->state & cpu_flag::wait)
|
||||
{
|
||||
spu->state.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
} notify_spus{};
|
||||
|
||||
std::vector<lv2_event> events;
|
||||
|
||||
std::unique_lock<shared_mutex> qlock;
|
||||
@@ -357,7 +389,7 @@ error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode)
|
||||
for (auto cpu = +queue->sq; cpu; cpu = cpu->next_cpu)
|
||||
{
|
||||
cpu->ch_in_mbox.set_values(1, CELL_ECANCELED);
|
||||
resume_spu_thread_group_from_waiting(*cpu);
|
||||
resume_spu_thread_group_from_waiting(*cpu, notify_spus.spus);
|
||||
}
|
||||
|
||||
atomic_storage<spu_thread*>::release(queue->sq, nullptr);
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
|
||||
// Open Flags
|
||||
enum : s32
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "Utilities/StrUtil.h"
|
||||
#include "Utilities/Thread.h"
|
||||
|
||||
#include "Emu/Cell/timers.hpp"
|
||||
#include "sys_game.h"
|
||||
|
||||
LOG_CHANNEL(sys_game);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "stdafx.h"
|
||||
#include "sys_hid.h"
|
||||
|
||||
#include "Emu/Memory/vm.h"
|
||||
#include "Emu/Memory/vm_var.h"
|
||||
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/perf_meter.hpp"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
@@ -16,6 +15,7 @@
|
||||
#include "sys_memory.h"
|
||||
|
||||
#include "util/asm.hpp"
|
||||
|
||||
#include <thread>
|
||||
|
||||
LOG_CHANNEL(sys_ppu_thread);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "sys_rwlock.h"
|
||||
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/IPC.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
|
||||
@@ -34,9 +34,10 @@ namespace vm
|
||||
}
|
||||
|
||||
// Update reservation status
|
||||
void reservation_update(u32 addr);
|
||||
void reservation_update(u32 addr);
|
||||
std::pair<bool, u64> try_reservation_update(u32 addr);
|
||||
|
||||
struct reservation_waiter_t
|
||||
struct reservation_waiter_t
|
||||
{
|
||||
u32 wait_flag = 0;
|
||||
u8 waiters_count = 0;
|
||||
|
||||
@@ -15,12 +15,12 @@ namespace utils
|
||||
{
|
||||
u128 __vectorcall atomic_load16(const void* ptr)
|
||||
{
|
||||
return std::bit_cast<u128>(_mm_load_si128((__m128i*)ptr));
|
||||
return std::bit_cast<u128>(_mm_load_si128(static_cast<const __m128i*>(ptr)));
|
||||
}
|
||||
|
||||
void __vectorcall atomic_store16(void* ptr, u128 value)
|
||||
{
|
||||
_mm_store_si128((__m128i*)ptr, std::bit_cast<__m128i>(value));
|
||||
_mm_store_si128(static_cast<__m128i*>(ptr), std::bit_cast<__m128i>(value));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -479,7 +479,7 @@ struct atomic_storage
|
||||
#endif
|
||||
|
||||
#if defined(_M_X64) && defined(_MSC_VER)
|
||||
return _interlockedbittestandset((long*)dst, bit) != 0;
|
||||
return _interlockedbittestandset(reinterpret_cast<long*>(dst), bit) != 0;
|
||||
#elif defined(ARCH_X64)
|
||||
bool result;
|
||||
__asm__ volatile ("lock btsl %2, 0(%1)\n" : "=@ccc" (result) : "r" (dst), "Ir" (bit) : "cc", "memory");
|
||||
@@ -506,7 +506,7 @@ struct atomic_storage
|
||||
#endif
|
||||
|
||||
#if defined(_M_X64) && defined(_MSC_VER)
|
||||
return _interlockedbittestandreset((long*)dst, bit) != 0;
|
||||
return _interlockedbittestandreset(reinterpret_cast<long*>(dst), bit) != 0;
|
||||
#elif defined(ARCH_X64)
|
||||
bool result;
|
||||
__asm__ volatile ("lock btrl %2, 0(%1)\n" : "=@ccc" (result) : "r" (dst), "Ir" (bit) : "cc", "memory");
|
||||
@@ -536,9 +536,9 @@ struct atomic_storage
|
||||
while (true)
|
||||
{
|
||||
// Keep trying until we actually invert desired bit
|
||||
if (!_bittest((long*)dst, bit) && !_interlockedbittestandset((long*)dst, bit))
|
||||
if (!_bittest(reinterpret_cast<const long*>(dst), bit) && !_interlockedbittestandset(reinterpret_cast<long*>(dst), bit))
|
||||
return false;
|
||||
if (_interlockedbittestandreset((long*)dst, bit))
|
||||
if (_interlockedbittestandreset(reinterpret_cast<long*>(dst), bit))
|
||||
return true;
|
||||
}
|
||||
#elif defined(ARCH_X64)
|
||||
|
||||
@@ -16,6 +16,8 @@ namespace utils
|
||||
T* result;
|
||||
__asm__("mov %0, %1" : "=r" (result) : "r" (ptr) : "memory");
|
||||
return result;
|
||||
#else
|
||||
#error "Missing utils::bless() implementation"
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
#include "util/cpu_stats.hpp"
|
||||
#include "util/sysinfo.hpp"
|
||||
#include "util/logs.hpp"
|
||||
#include "util/asm.hpp"
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "util/asm.hpp"
|
||||
#include "windows.h"
|
||||
#include "tlhelp32.h"
|
||||
#ifdef _MSC_VER
|
||||
@@ -18,8 +18,6 @@
|
||||
#include "sstream"
|
||||
#include "stdlib.h"
|
||||
#include "sys/times.h"
|
||||
#include "sys/types.h"
|
||||
#include "unistd.h"
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
@@ -34,6 +32,7 @@
|
||||
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
# include <sys/sysctl.h>
|
||||
# include <unistd.h>
|
||||
# if defined(__DragonFly__) || defined(__FreeBSD__)
|
||||
# include <sys/user.h>
|
||||
# endif
|
||||
@@ -129,20 +128,6 @@ namespace utils
|
||||
per_core_usage.resize(utils::get_thread_count());
|
||||
std::fill(per_core_usage.begin(), per_core_usage.end(), 0.0);
|
||||
|
||||
#if defined(_WIN32) || (defined(__linux__)&&!defined(__ANDROID__))
|
||||
const auto string_to_number = [](const std::string& str) -> std::pair<bool, size_t>
|
||||
{
|
||||
std::add_pointer_t<char> eval;
|
||||
const size_t number = std::strtol(str.c_str(), &eval, 10);
|
||||
|
||||
if (str.c_str() + str.size() == eval)
|
||||
{
|
||||
return { true, number };
|
||||
}
|
||||
|
||||
return { false, 0 };
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!m_cpu_cores || !m_cpu_query)
|
||||
{
|
||||
@@ -213,7 +198,7 @@ namespace utils
|
||||
}
|
||||
|
||||
#elif __linux__
|
||||
|
||||
#ifndef ANDROID
|
||||
m_previous_idle_times_per_cpu.resize(utils::get_thread_count(), 0.0);
|
||||
m_previous_total_times_per_cpu.resize(utils::get_thread_count(), 0.0);
|
||||
|
||||
@@ -459,7 +444,7 @@ namespace utils
|
||||
if (proc_dir)
|
||||
{
|
||||
// proc available, iterate through tasks and count them
|
||||
struct dirent* entry;
|
||||
const struct dirent* entry;
|
||||
while ((entry = readdir(proc_dir)) != NULL)
|
||||
{
|
||||
if (entry->d_name[0] == '.')
|
||||
|
||||
@@ -827,10 +827,7 @@ namespace utils
|
||||
}
|
||||
}
|
||||
|
||||
auto& thread = *m_thread;
|
||||
thread = thread_state::aborting;
|
||||
thread();
|
||||
|
||||
// Join thread
|
||||
m_thread.reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -207,7 +207,10 @@ namespace stx
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Winvalid-offsetof"
|
||||
#elif !defined(_MSC_VER)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
|
||||
#endif
|
||||
@@ -316,7 +319,9 @@ namespace stx
|
||||
return make_single<std::remove_reference_t<T>>(std::forward<T>(value));
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#elif !defined(_MSC_VER)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#endif
|
||||
|
||||
#include <thread>
|
||||
#include <fstream>
|
||||
|
||||
#include "util/asm.hpp"
|
||||
#include "util/fence.hpp"
|
||||
@@ -73,45 +74,46 @@ namespace Darwin_ProcessInfo
|
||||
namespace utils
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Some helpers for sanity
|
||||
const auto read_reg_dword = [](HKEY hKey, std::string_view value_name) -> std::pair<bool, DWORD>
|
||||
{
|
||||
DWORD val = 0;
|
||||
DWORD len = sizeof(val);
|
||||
if (ERROR_SUCCESS != RegQueryValueExA(hKey, value_name.data(), nullptr, nullptr, reinterpret_cast<LPBYTE>(&val), &len))
|
||||
{
|
||||
return { false, 0 };
|
||||
}
|
||||
return { true, val };
|
||||
};
|
||||
|
||||
const auto read_reg_sz = [](HKEY hKey, std::string_view value_name) -> std::pair<bool, std::string>
|
||||
{
|
||||
constexpr usz MAX_SZ_LEN = 255;
|
||||
char sz[MAX_SZ_LEN + 1] {};
|
||||
DWORD sz_len = MAX_SZ_LEN;
|
||||
|
||||
// Safety; null terminate
|
||||
sz[0] = 0;
|
||||
sz[MAX_SZ_LEN] = 0;
|
||||
|
||||
// Read string
|
||||
if (ERROR_SUCCESS != RegQueryValueExA(hKey, value_name.data(), nullptr, nullptr, reinterpret_cast<LPBYTE>(sz), &sz_len))
|
||||
{
|
||||
return { false, "" };
|
||||
}
|
||||
|
||||
// Safety, force null terminator
|
||||
if (sz_len < MAX_SZ_LEN)
|
||||
{
|
||||
sz[sz_len] = 0;
|
||||
}
|
||||
return { true, sz };
|
||||
};
|
||||
|
||||
#if !defined(ARCH_X64)
|
||||
// Alternative way to read OS version using the registry.
|
||||
static std::string get_fallback_windows_version()
|
||||
{
|
||||
// Some helpers for sanity
|
||||
const auto read_reg_dword = [](HKEY hKey, std::string_view value_name) -> std::pair<bool, DWORD>
|
||||
{
|
||||
DWORD val;
|
||||
DWORD len = sizeof(val);
|
||||
if (ERROR_SUCCESS != RegQueryValueExA(hKey, value_name.data(), nullptr, nullptr, reinterpret_cast<LPBYTE>(&val), &len))
|
||||
{
|
||||
return { false, 0 };
|
||||
}
|
||||
return { true, val };
|
||||
};
|
||||
|
||||
const auto read_reg_sz = [](HKEY hKey, std::string_view value_name) -> std::pair<bool, std::string>
|
||||
{
|
||||
constexpr usz MAX_SZ_LEN = 255;
|
||||
char sz[MAX_SZ_LEN + 1];
|
||||
DWORD sz_len = MAX_SZ_LEN;
|
||||
|
||||
// Safety; null terminate
|
||||
sz[0] = 0;
|
||||
sz[MAX_SZ_LEN] = 0;
|
||||
|
||||
// Read string
|
||||
if (ERROR_SUCCESS != RegQueryValueExA(hKey, value_name.data(), nullptr, nullptr, reinterpret_cast<LPBYTE>(sz), &sz_len))
|
||||
{
|
||||
return { false, "" };
|
||||
}
|
||||
|
||||
// Safety, force null terminator
|
||||
if (sz_len < MAX_SZ_LEN)
|
||||
{
|
||||
sz[sz_len] = 0;
|
||||
}
|
||||
return { true, sz };
|
||||
};
|
||||
|
||||
HKEY hKey;
|
||||
if (ERROR_SUCCESS != RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &hKey))
|
||||
{
|
||||
@@ -151,6 +153,7 @@ namespace utils
|
||||
return fmt::format("Operating system: %s, Version %s", product_name, version_id);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
bool utils::has_ssse3()
|
||||
@@ -277,17 +280,6 @@ bool utils::has_avx10()
|
||||
#endif
|
||||
}
|
||||
|
||||
bool utils::has_avx10_512()
|
||||
{
|
||||
#if defined(ARCH_X64)
|
||||
// AVX10 with 512 wide vectors
|
||||
static const bool g_value = has_avx10() && get_cpuid(24, 0)[2] & 0x40000;
|
||||
return g_value;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
u32 utils::avx10_isa_version()
|
||||
{
|
||||
#if defined(ARCH_X64)
|
||||
@@ -309,28 +301,6 @@ u32 utils::avx10_isa_version()
|
||||
#endif
|
||||
}
|
||||
|
||||
bool utils::has_avx512_256()
|
||||
{
|
||||
#if defined(ARCH_X64)
|
||||
// Either AVX10 or AVX512 implies support for 256-bit length AVX-512 SKL-X tier instructions
|
||||
static const bool g_value = (has_avx512() || has_avx10());
|
||||
return g_value;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool utils::has_avx512_icl_256()
|
||||
{
|
||||
#if defined(ARCH_X64)
|
||||
// Check for AVX512_ICL or check for AVX10, together with GFNI, VAES, and VPCLMULQDQ, implies support for the same instructions that AVX-512_icl does at 256 bit length
|
||||
static const bool g_value = (has_avx512_icl() || (has_avx10() && get_cpuid(7, 0)[2] & 0x00000700));
|
||||
return g_value;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool utils::has_xop()
|
||||
{
|
||||
#if defined(ARCH_X64)
|
||||
@@ -524,7 +494,7 @@ std::string utils::get_system_info()
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::append(result, " | TSC: Bad");
|
||||
fmt::append(result, " | TSC: Disabled");
|
||||
}
|
||||
|
||||
if (has_avx())
|
||||
@@ -535,15 +505,6 @@ std::string utils::get_system_info()
|
||||
{
|
||||
const u32 avx10_version = avx10_isa_version();
|
||||
fmt::append(result, "10.%d", avx10_version);
|
||||
|
||||
if (has_avx10_512())
|
||||
{
|
||||
result += "-512";
|
||||
}
|
||||
else
|
||||
{
|
||||
result += "-256";
|
||||
}
|
||||
}
|
||||
else if (has_avx512())
|
||||
{
|
||||
@@ -660,14 +621,88 @@ std::string utils::get_firmware_version()
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string utils::get_OS_version()
|
||||
utils::OS_version utils::get_OS_version()
|
||||
{
|
||||
OS_version res {};
|
||||
|
||||
#if _WIN32
|
||||
res.type = "windows";
|
||||
#elif __linux__
|
||||
res.type = "linux";
|
||||
#elif __APPLE__
|
||||
res.type = "macos";
|
||||
#elif __FreeBSD__
|
||||
res.type = "freebsd";
|
||||
#else
|
||||
res.type = "unknown";
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
res.arch = "x64";
|
||||
#elif defined(ARCH_ARM64)
|
||||
res.arch = "arm64";
|
||||
#else
|
||||
res.arch = "unknown";
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// GetVersionEx is deprecated, RtlGetVersion is kernel-mode only and AnalyticsInfo is UWP only.
|
||||
// So we're forced to read PEB instead to get Windows version info. It's ugly but works.
|
||||
#if defined(ARCH_X64)
|
||||
constexpr DWORD peb_offset = 0x60;
|
||||
const INT_PTR peb = __readgsqword(peb_offset);
|
||||
res.version_major = *reinterpret_cast<const DWORD*>(peb + 0x118);
|
||||
res.version_minor = *reinterpret_cast<const DWORD*>(peb + 0x11c);
|
||||
res.version_patch = *reinterpret_cast<const WORD*>(peb + 0x120);
|
||||
#else
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
const auto [check_major, version_major] = read_reg_dword(hKey, "CurrentMajorVersionNumber");
|
||||
const auto [check_minor, version_minor] = read_reg_dword(hKey, "CurrentMinorVersionNumber");
|
||||
const auto [check_build, version_patch] = read_reg_sz(hKey, "CurrentBuildNumber");
|
||||
|
||||
if (check_major) res.version_major = version_major;
|
||||
if (check_minor) res.version_minor = version_minor;
|
||||
if (check_build) res.version_patch = stoi(version_patch);
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
#endif
|
||||
#elif defined (__APPLE__)
|
||||
res.version_major = Darwin_Version::getNSmajorVersion();
|
||||
res.version_minor = Darwin_Version::getNSminorVersion();
|
||||
res.version_patch = Darwin_Version::getNSpatchVersion();
|
||||
#else
|
||||
if (struct utsname details = {}; !uname(&details))
|
||||
{
|
||||
const std::vector<std::string> version_list = fmt::split(details.release, { "." });
|
||||
const auto get_version_part = [&version_list](usz i) -> usz
|
||||
{
|
||||
if (version_list.size() <= i) return 0;
|
||||
if (const auto [success, version_part] = string_to_number(version_list[i]); success)
|
||||
{
|
||||
return version_part;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
res.version_major = get_version_part(0);
|
||||
res.version_minor = get_version_part(1);
|
||||
res.version_patch = get_version_part(2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string utils::get_OS_version_string()
|
||||
{
|
||||
std::string output;
|
||||
#ifdef _WIN32
|
||||
// GetVersionEx is deprecated, RtlGetVersion is kernel-mode only and AnalyticsInfo is UWP only.
|
||||
// So we're forced to read PEB instead to get Windows version info. It's ugly but works.
|
||||
#if defined(ARCH_X64)
|
||||
const DWORD peb_offset = 0x60;
|
||||
constexpr DWORD peb_offset = 0x60;
|
||||
const INT_PTR peb = __readgsqword(peb_offset);
|
||||
const DWORD version_major = *reinterpret_cast<const DWORD*>(peb + 0x118);
|
||||
const DWORD version_minor = *reinterpret_cast<const DWORD*>(peb + 0x11c);
|
||||
@@ -772,18 +807,68 @@ static const bool s_tsc_freq_evaluated = []() -> bool
|
||||
#endif
|
||||
|
||||
if (!utils::has_invariant_tsc())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
LARGE_INTEGER freq;
|
||||
if (!QueryPerformanceFrequency(&freq))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (freq.QuadPart <= 9'999'999)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ullong timer_freq = freq.QuadPart;
|
||||
#else
|
||||
|
||||
#ifdef __linux__
|
||||
// Check if system clocksource is TSC. If the kernel trusts the TSC, we should too.
|
||||
// Some Ryzen laptops have broken firmware when running linux (requires a kernel patch). This is also a problem on some older intel CPUs.
|
||||
const char* clocksource_file = "/sys/devices/system/clocksource/clocksource0/available_clocksource";
|
||||
if (!fs::is_file(clocksource_file))
|
||||
{
|
||||
// OS doesn't support sysfs?
|
||||
printf("[TSC calibration] Could not determine available clock sources. Disabling TSC.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string clock_sources;
|
||||
std::ifstream file(clocksource_file);
|
||||
std::getline(file, clock_sources);
|
||||
|
||||
if (file.fail())
|
||||
{
|
||||
printf("[TSC calibration] Could not read the available clock sources on this system. Disabling TSC.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("[TSC calibration] Available clock sources: '%s'\n", clock_sources.c_str());
|
||||
|
||||
// Check if the Kernel has blacklisted the TSC
|
||||
const auto available_clocks = fmt::split(clock_sources, { " " });
|
||||
const bool tsc_reliable = std::find(available_clocks.begin(), available_clocks.end(), "tsc") != available_clocks.end();
|
||||
|
||||
if (!tsc_reliable)
|
||||
{
|
||||
printf("[TSC calibration] TSC is not a supported clock source on this system.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("[TSC calibration] Kernel reports the TSC is reliable.\n");
|
||||
#else
|
||||
if (utils::get_cpu_brand().find("Ryzen") != umax)
|
||||
{
|
||||
// MacOS is arm-native these days and I don't know much about BSD to fix this if it's an issue. (kd-11)
|
||||
// Having this check only for Ryzen is broken behavior - other CPUs can also have this problem.
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
constexpr ullong timer_freq = 1'000'000'000;
|
||||
#endif
|
||||
|
||||
@@ -880,7 +965,7 @@ static const bool s_tsc_freq_evaluated = []() -> bool
|
||||
return round_tsc(res, utils::mul_saturate<u64>(utils::add_saturate<u64>(rdtsc_diff[0], rdtsc_diff[1]), utils::aligned_div(timer_freq, timer_data[1] - timer_data[0])));
|
||||
}();
|
||||
|
||||
atomic_storage<u64>::release(utils::s_tsc_freq, cal_tsc);
|
||||
atomic_storage<u64>::store(utils::s_tsc_freq, cal_tsc);
|
||||
return true;
|
||||
}();
|
||||
|
||||
@@ -963,10 +1048,20 @@ u32 utils::get_cpu_model()
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace utils
|
||||
u64 utils::_get_main_tid()
|
||||
{
|
||||
u64 _get_main_tid()
|
||||
{
|
||||
return thread_ctrl::get_tid();
|
||||
}
|
||||
return thread_ctrl::get_tid();
|
||||
}
|
||||
|
||||
std::pair<bool, usz> utils::string_to_number(std::string_view str)
|
||||
{
|
||||
std::add_pointer_t<char> eval;
|
||||
const usz number = std::strtol(str.data(), &eval, 10);
|
||||
|
||||
if (str.data() + str.size() == eval)
|
||||
{
|
||||
return { true, number };
|
||||
}
|
||||
|
||||
return { false, 0 };
|
||||
}
|
||||
|
||||
@@ -29,14 +29,8 @@ namespace utils
|
||||
|
||||
bool has_avx10();
|
||||
|
||||
bool has_avx10_512();
|
||||
|
||||
u32 avx10_isa_version();
|
||||
|
||||
bool has_avx512_256();
|
||||
|
||||
bool has_avx512_icl_256();
|
||||
|
||||
bool has_xop();
|
||||
|
||||
bool has_clwb();
|
||||
@@ -67,7 +61,17 @@ namespace utils
|
||||
|
||||
std::string get_firmware_version();
|
||||
|
||||
std::string get_OS_version();
|
||||
struct OS_version
|
||||
{
|
||||
std::string type;
|
||||
std::string arch;
|
||||
int version_major = 0;
|
||||
int version_minor = 0;
|
||||
int version_patch = 0;
|
||||
};
|
||||
OS_version get_OS_version();
|
||||
|
||||
std::string get_OS_version_string();
|
||||
|
||||
int get_maxfiles();
|
||||
|
||||
@@ -94,4 +98,6 @@ namespace utils
|
||||
{
|
||||
return s_tsc_freq;
|
||||
}
|
||||
|
||||
std::pair<bool, usz> string_to_number(std::string_view str);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/types.hpp"
|
||||
#include "util/shared_ptr.hpp"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#define ATTR_PURE __attribute__((pure))
|
||||
|
||||
Reference in New Issue
Block a user