Compare commits

...

8 Commits

Author SHA1 Message Date
GodsWill Dev ccddd6fb94 user: make the local profile configurable (#347)
user: make the local user ID configurable

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-29 04:27:49 +04:00
nmzik e559771a08 libc: isolate guest setenv from host environment. Fix linux debugging 2026-08-29 03:57:09 +04:00
nmzik b870a77176 network: enable IPv4 UDP sockets on POSIX 2026-08-29 03:57:09 +04:00
nmzik 62eaead3a3 add configurable Vulkan present modes
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
2026-08-29 03:57:09 +04:00
nmzik d7808d9cb4 add configurable local user name
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
2026-08-29 03:57:09 +04:00
nmzik 8267c422b5 launcher: add 1440p/2160p
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
2026-08-29 03:57:09 +04:00
nmzik b46e141762 dev: add Linux overrides to VS Code launch configurations 2026-08-29 03:55:29 +04:00
nmzik cfa140fb12 window: create Vulkan surface visible on main thread 2026-08-29 01:31:02 +04:00
18 changed files with 368 additions and 250 deletions
+37 -3
View File
@@ -10,7 +10,14 @@
"stopAtEntry": false,
"cwd": "${workspaceFolder}\\_Build\\vscode-clang\\launcher",
"environment": [],
"externalConsole": false
"externalConsole": false,
"linux": {
"type": "cppdbg",
"program": "${workspaceFolder}/_Build/vscode-clang/launcher/launcher",
"cwd": "${workspaceFolder}/_Build/vscode-clang/launcher",
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb"
}
},
{
"name": "Debug kyty_emulator",
@@ -25,13 +32,40 @@
"stopAtEntry": false,
"cwd": "${workspaceFolder}\\_Build\\vscode-clang",
"environment": [],
"externalConsole": true
"externalConsole": true,
"linux": {
"type": "cppdbg",
"program": "${workspaceFolder}/_Build/vscode-clang/kyty_emulator",
"cwd": "${workspaceFolder}/_Build/vscode-clang",
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"setupCommands": [
{
"description": "Pass Kyty's internal signals to its handlers",
"text": "handle SIG37 SIGSEGV SIGBUS SIGILL nostop noprint pass",
"ignoreFailures": false
}
]
}
},
{
"name": "Attach to running kyty_emulator",
"type": "cppvsdbg",
"request": "attach",
"processId": "${command:pickProcess}"
"processId": "${command:pickProcess}",
"linux": {
"type": "cppdbg",
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"setupCommands": [
{
"description": "Pass Kyty's internal signals to its handlers",
"text": "handle SIG37 SIGSEGV SIGBUS SIGILL nostop noprint pass",
"ignoreFailures": false
}
]
}
}
]
}
+10
View File
@@ -524,6 +524,16 @@ if(NOT KYTY_CLANG_CL)
endif()
if(BUILD_TESTING)
add_test(NAME emulator_user_name_cli
COMMAND $<TARGET_FILE:kyty_emulator> --help --user-name 1234567890123456)
add_test(NAME emulator_user_name_too_long
COMMAND $<TARGET_FILE:kyty_emulator> --help --user-name 12345678901234567)
set_tests_properties(emulator_user_name_too_long PROPERTIES WILL_FAIL TRUE)
add_test(NAME emulator_present_mode_cli
COMMAND $<TARGET_FILE:kyty_emulator> --help --present-mode Immediate)
add_test(NAME emulator_present_mode_invalid
COMMAND $<TARGET_FILE:kyty_emulator> --help --present-mode Invalid)
set_tests_properties(emulator_present_mode_invalid PROPERTIES WILL_FAIL TRUE)
add_test(NAME ime_dialog COMMAND $<TARGET_FILE:ime_dialog_tests>)
add_test(NAME shader_cfg COMMAND $<TARGET_FILE:shader_cfg_tests>)
add_test(NAME scalar_provenance COMMAND $<TARGET_FILE:scalar_provenance_tests>)
+14
View File
@@ -21,6 +21,8 @@ void Shutdown() {
void Load(const ConfigOptions& cfg) {
EXIT_IF(g_config == nullptr);
EXIT_IF(cfg.user_name.empty() || cfg.user_name.size() > MAX_USER_NAME_LENGTH);
EXIT_IF(!IsConfiguredUserIdValid(cfg.user_id));
*g_config = cfg;
}
@@ -33,6 +35,18 @@ uint32_t GetScreenHeight() {
return g_config->screen_height;
}
const std::string& GetUserName() {
return g_config->user_name;
}
int32_t GetUserId() {
return g_config->user_id;
}
PresentMode GetPresentMode() {
return g_config->present_mode;
}
bool FullscreenEnabled() {
return g_config->fullscreen_enabled;
}
+17
View File
@@ -3,6 +3,7 @@
#include "common/common.h"
#include <cstddef>
#include <filesystem>
#include <string>
#include <vector>
@@ -26,14 +27,27 @@ enum class ProfilerDirection { None, Network };
enum class OutputDirection { Silent, Console, File };
enum class PresentMode { Fifo, Mailbox, Immediate };
using Keymap = std::vector<std::string>;
constexpr uint32_t DEFAULT_CONSOLE_LANGUAGE = 1;
constexpr uint32_t MAX_CONSOLE_LANGUAGE = 29;
constexpr std::size_t MAX_USER_NAME_LENGTH = 16;
constexpr int32_t DEFAULT_USER_ID = 1000;
constexpr bool IsConfiguredUserIdValid(int32_t user_id) {
constexpr int32_t USER_ID_EVERYONE = 0xfe;
constexpr int32_t USER_ID_SYSTEM = 0xff;
return user_id >= 0 && user_id != USER_ID_EVERYONE && user_id != USER_ID_SYSTEM;
}
struct ConfigOptions {
uint32_t screen_width = 1280;
uint32_t screen_height = 720;
std::string user_name = "Kyty";
int32_t user_id = DEFAULT_USER_ID;
PresentMode present_mode = PresentMode::Fifo;
bool fullscreen_enabled = false;
uint32_t vblank_frequency = 60;
uint32_t console_language = DEFAULT_CONSOLE_LANGUAGE;
@@ -63,6 +77,9 @@ void Load(const ConfigOptions& cfg);
uint32_t GetScreenWidth();
uint32_t GetScreenHeight();
const std::string& GetUserName();
int32_t GetUserId();
PresentMode GetPresentMode();
bool FullscreenEnabled();
uint32_t GetVblankFrequency();
uint32_t GetConsoleLanguage();
+20 -71
View File
@@ -1,30 +1,9 @@
#include "SDL.h"
#include "SDL_error.h"
#include "SDL_events.h"
#include "SDL_gamecontroller.h"
#include "SDL_hints.h"
#include "SDL_joystick.h"
#include "SDL_keyboard.h"
#include "SDL_keycode.h"
#include "SDL_mouse.h"
#include "SDL_pixels.h"
#include "SDL_rwops.h"
#include "SDL_stdinc.h"
#include "SDL_surface.h"
#include "SDL_thread.h"
#include "SDL_touch.h"
#include "SDL_video.h"
#include "SDL_vulkan.h"
#include "common/assert.h"
#include "common/common.h"
#include "common/emulatorConfig.h"
#include "common/file.h"
#include "common/logging/log.h"
#include "common/profiler.h"
#include "common/stringUtils.h"
#include "common/systemInfo.h"
#include "common/threads.h"
#include "common/timer.h"
#include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h"
@@ -34,19 +13,11 @@
#include "graphics/presentation/presenter.h"
#include "graphics/presentation/videoOut.h"
#include "graphics/presentation/window/windowInternal.h"
#include "libs/controller.h"
#include "loader/systemContent.h"
#include <algorithm>
#include <array>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <fmt/format.h>
#include <limits>
#include <memory>
#include <string>
#include <vector>
#include <vulkan/vk_platform.h>
@@ -334,7 +305,6 @@ public:
private:
void Destroy();
void RefreshSurfaceSize();
WindowContext& m_window;
vk::SwapchainKHR m_handle = nullptr;
@@ -396,12 +366,12 @@ struct Presenter::Impl {
void Swapchain::Create() {
auto& graphics = m_window.graphic_ctx;
EXIT_IF(graphics.screen_width == 0);
EXIT_IF(graphics.screen_height == 0);
EXIT_IF(graphics.device == nullptr);
EXIT_IF(m_window.surface == nullptr);
Common::LockGuard lock(m_window.mutex);
EXIT_IF(graphics.screen_width == 0);
EXIT_IF(graphics.screen_height == 0);
const auto& surface = m_window.surface_capabilities;
EXIT_NOT_IMPLEMENTED(surface.formats.empty());
@@ -459,7 +429,21 @@ void Swapchain::Create() {
create_info.imageSharingMode = vk::SharingMode::eExclusive;
create_info.preTransform = transform;
create_info.compositeAlpha = composite;
create_info.presentMode = vk::PresentModeKHR::eFifo;
switch (Config::GetPresentMode()) {
case Config::PresentMode::Mailbox:
create_info.presentMode = vk::PresentModeKHR::eMailbox;
break;
case Config::PresentMode::Immediate:
create_info.presentMode = vk::PresentModeKHR::eImmediate;
break;
case Config::PresentMode::Fifo:
default: create_info.presentMode = vk::PresentModeKHR::eFifo; break;
}
if (std::find(surface.present_modes.begin(), surface.present_modes.end(),
create_info.presentMode) == surface.present_modes.end()) {
LOGF("warning: requested present mode is unavailable; falling back to Fifo\n");
create_info.presentMode = vk::PresentModeKHR::eFifo;
}
create_info.clipped = VK_TRUE;
RequireVulkanSuccess(graphics.device.createSwapchainKHR(&create_info, nullptr, &m_handle),
"vkCreateSwapchainKHR");
@@ -554,30 +538,18 @@ void Swapchain::Destroy() {
m_render_complete.clear();
}
void Swapchain::RefreshSurfaceSize() {
int width = 0;
int height = 0;
SDL_Vulkan_GetDrawableSize(m_window.window, &width, &height);
if (width > 0 && height > 0) {
m_window.graphic_ctx.screen_width = static_cast<uint32_t>(width);
m_window.graphic_ctx.screen_height = static_cast<uint32_t>(height);
}
m_window.RefreshSurfaceCapabilities();
}
void Swapchain::Recreate(bool surface_lost) {
Destroy();
if (surface_lost) {
#if defined(__APPLE__)
// Surface recreation goes through SDL_Vulkan_CreateSurface, which touches the
// window's view/layer and must run on the main thread on macOS.
m_window.RunOnMainThread([this] { m_window.RecreateSurface(); }, true);
m_window.RunOnMainThread([this] { m_window.RecreateSurface(); });
#else
m_window.RecreateSurface();
#endif
}
RefreshSurfaceSize();
m_window.RefreshSurfaceCapabilities();
Create();
}
@@ -803,29 +775,6 @@ void Presenter::Present(Frame& frame, bool reuse) {
KYTY_PROFILER_FUNCTION();
m_impl->frames.ValidateForPresent(&frame, reuse);
auto& window = m_impl->window;
if (window.window_hidden) {
#if defined(__APPLE__)
// AppKit traps if a window is shown off the main thread; marshal and wait so the
// swapchain below is recreated against a visible window.
window.RunOnMainThread(
[&window] {
window.UpdateIcon();
SDL_ShowWindow(window.window);
SDL_RaiseWindow(window.window);
},
true);
#else
window.UpdateIcon();
SDL_ShowWindow(window.window);
SDL_RaiseWindow(window.window);
#endif
window.window_hidden = false;
m_impl->RecoverSwapchain(Swapchain::Status::Recreate);
}
const auto ime_visual = GetImeVisualState();
auto& swapchain = m_impl->swapchain;
for (uint32_t attempt = 0; attempt < 2; attempt++) {
@@ -848,7 +797,7 @@ void Presenter::Present(Frame& frame, bool reuse) {
}
m_impl->presented_ime_revision.store(ime_visual.revision, std::memory_order_release);
window.UpdateTitle();
m_impl->window.UpdateTitle();
m_impl->frames.Release(&frame, true);
return;
}
@@ -22,7 +22,6 @@
#include "common/logging/log.h"
#include "common/profiler.h"
#include "common/stringUtils.h"
#include "common/systemInfo.h"
#include "common/threads.h"
#include "common/timer.h"
#include "graphics/host_gpu/graphicContext.h"
@@ -1037,10 +1036,6 @@ void WindowContext::CreateVulkan() {
}
}
memcpy(device_name, device_properties.deviceName, sizeof(device_name));
std::snprintf(processor_name, sizeof(processor_name), "%s",
Common::GetSystemInfo().ProcessorName.c_str());
VulkanInitSubgroupSizeControl(graphic_ctx.physical_device, graphic_ctx);
graphic_ctx.device = VulkanCreateDevice(graphic_ctx.physical_device, r, queue_family,
@@ -1079,7 +1074,6 @@ void WindowContext::RecreateSurface() {
EXIT("Could not recreate the Vulkan surface: %s\n", SDL_GetError());
}
surface = native_surface;
RefreshSurfaceCapabilities();
}
WindowContext::~WindowContext() {
+18 -30
View File
@@ -23,7 +23,6 @@
#include "common/file.h"
#include "common/logging/log.h"
#include "common/profiler.h"
#include "common/stringUtils.h"
#include "common/systemInfo.h"
#include "common/threads.h"
#include "common/timer.h"
@@ -39,21 +38,18 @@
#include "libs/controller.h"
#include "loader/systemContent.h"
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <string>
#include <vector>
#include <vulkan/vk_platform.h>
#include <fmt/format.h>
#define STB_IMAGE_IMPLEMENTATION
#define STBI_NO_SIMD
#include "stb_image.h"
#include <fmt/format.h>
// IWYU pragma: no_include <intrin.h>
#define KYTY_ENABLE_DEBUG_PRINTF
@@ -197,8 +193,6 @@ std::unique_ptr<WindowContext> g_window;
} // namespace
constexpr const char* KYTY_SDL_WINDOW_CAPTION = "Game";
constexpr uint32_t KYTY_SDL_WINDOW_FLAGS =
(static_cast<uint32_t>(SDL_WINDOW_HIDDEN) | static_cast<uint32_t>(SDL_WINDOW_VULKAN));
constexpr int KYTY_SDL_WINDOWPOS_CENTERED = SDL_WINDOWPOS_CENTERED; /*NOLINT(hicpp-signed-bitwise)*/
static void SetPause(WindowLoopState& game, bool flag) {
@@ -407,6 +401,7 @@ static void GameEventDidEnterForeground(WindowLoopState& game) {
void WindowContext::Resize(uint32_t new_width, uint32_t new_height) {
EXIT_IF(new_width == 0 || new_height == 0);
Common::LockGuard lock(mutex);
graphic_ctx.screen_width = new_width;
graphic_ctx.screen_height = new_height;
}
@@ -728,8 +723,7 @@ void WindowContext::ProcessEvent(double time_s) {
}
}
#if defined(__APPLE__)
void WindowContext::RunOnMainThread(std::function<void()> task, bool wait) {
void WindowContext::RunOnMainThread(std::function<void()> task) {
if (Common::Thread::IsMainThread()) {
task();
return;
@@ -747,9 +741,6 @@ void WindowContext::RunOnMainThread(std::function<void()> task, bool wait) {
event.type = SDL_USEREVENT;
SDL_PushEvent(&event);
if (!wait) {
return;
}
Common::LockGuard lock(main_task_mutex);
while (main_tasks_run < ticket) {
main_task_done.Wait(&main_task_mutex);
@@ -772,7 +763,6 @@ void WindowContext::DrainMainThreadTasks() {
main_tasks_run += tasks.size();
main_task_done.SignalAll();
}
#endif
void WindowContext::Run() {
Common::Timer timer;
@@ -783,9 +773,7 @@ void WindowContext::Run() {
loop.paused.store(false, std::memory_order_release);
while (!loop.need_exit) {
#if defined(__APPLE__)
DrainMainThreadTasks();
#endif
if (loop.paused.load(std::memory_order_acquire)) {
if (!timer.IsPaused()) {
timer.Pause();
@@ -821,10 +809,7 @@ static void WindowCreate(WindowContext& context) {
LOGF("WindowCreate(): width = %d, height = %d\n", width, height);
uint32_t window_flags = KYTY_SDL_WINDOW_FLAGS;
if (Config::FullscreenEnabled()) {
window_flags |= static_cast<uint32_t>(SDL_WINDOW_FULLSCREEN_DESKTOP);
}
uint32_t window_flags = WindowContext::InitialWindowFlags(Config::FullscreenEnabled());
#if defined(__APPLE__)
// macOS 26 window chrome (CoreUI asset decode, SwiftUI titlebar) has been observed
// throwing NSExceptions under Rosetta during the first CATransaction commit. A
@@ -836,13 +821,20 @@ static void WindowCreate(WindowContext& context) {
context.window = SDL_CreateWindow(KYTY_SDL_WINDOW_CAPTION, KYTY_SDL_WINDOWPOS_CENTERED,
KYTY_SDL_WINDOWPOS_CENTERED, width, height, window_flags);
context.window_hidden = true;
if (context.window == nullptr) {
EXIT("%s\n", SDL_GetError());
}
SDL_SetWindowResizable(context.window, SDL_FALSE);
context.UpdateIcon();
}
uint32_t WindowContext::InitialWindowFlags(bool fullscreen) noexcept {
auto flags = static_cast<uint32_t>(SDL_WINDOW_VULKAN);
if (fullscreen) {
flags |= static_cast<uint32_t>(SDL_WINDOW_FULLSCREEN_DESKTOP);
}
return flags;
}
Presenter& WindowInit(uint32_t width, uint32_t height) {
@@ -959,6 +951,7 @@ void WindowContext::UpdateTitle() {
Loader::SystemContentParamSfoGetString("TITLE_ID", title_id, sizeof(title_id));
static bool has_app_ver =
Loader::SystemContentParamSfoGetString("APP_VER", app_ver, sizeof(app_ver));
static const std::string processor_name = Common::GetSystemInfo().ProcessorName;
static uint64_t fps_start = Common::Timer::QueryPerformanceCounter();
static uint64_t frame_num = 0;
static uint64_t fps_frames = 0;
@@ -983,19 +976,14 @@ void WindowContext::UpdateTitle() {
fps_frames = 0;
}
auto fps = fmt::format(
const auto* device_name = graphic_ctx.GetPhysicalDeviceProperties().deviceName.data();
auto text = fmt::format(
"[{} | {}] {}{}{}{}{}{}[{}] [{}], frame: {}, fps: {:f}", KYTY_BUILD_LABEL, build_type,
(has_title ? title : ""), (has_title ? ", " : ""), (has_title_id ? title_id : ""),
(has_title_id ? ", " : ""), (has_app_ver ? app_ver : ""), (has_app_ver ? " " : ""),
device_name, processor_name, frame_num, current_fps);
#if defined(__APPLE__)
// AppKit traps on title changes off the main thread; fire-and-forget keeps present pacing.
RunOnMainThread([this, fps = std::move(fps)] { SDL_SetWindowTitle(window, fps.c_str()); },
false);
#else
SDL_SetWindowTitle(window, fps.c_str());
#endif
RunOnMainThread([this, text = std::move(text)] { SDL_SetWindowTitle(window, text.c_str()); });
}
} // namespace Libs::Graphics
@@ -9,13 +9,10 @@
#include <atomic>
#include <cstdint>
#include <functional>
#include <memory>
#include <vector>
#if defined(__APPLE__)
#include <functional>
#endif
namespace Libs::Graphics {
class Presenter;
@@ -39,6 +36,7 @@ struct WindowContext {
KYTY_CLASS_NO_COPY(WindowContext);
[[nodiscard]] static vk::PhysicalDeviceVulkan13Features RequiredVulkan13Features() noexcept;
[[nodiscard]] static uint32_t InitialWindowFlags(bool fullscreen) noexcept;
void CreateVulkan();
void RecreateSurface();
void RefreshSurfaceCapabilities();
@@ -49,36 +47,25 @@ struct WindowContext {
void ProcessDisplayEvent(const SDL_DisplayEvent& event);
void ProcessEvent(double time_seconds);
void Run();
#if defined(__APPLE__)
// AppKit only allows window operations (show, icon, title, view/layer changes) on the
// main thread; the present thread marshals them through the SDL main loop with these.
// wait=true blocks until the task has run on the main thread.
void RunOnMainThread(std::function<void()> task, bool wait);
// SDL window operations must complete on the main thread.
void RunOnMainThread(std::function<void()> task);
void DrainMainThreadTasks();
#endif
GraphicContext graphic_ctx;
SDL_Window* window = nullptr;
bool window_hidden = true;
vk::SurfaceKHR surface = nullptr;
SurfaceCapabilities surface_capabilities;
std::unique_ptr<RenderContext> render_context;
std::unique_ptr<Presenter> presenter;
WindowLoopState loop;
char device_name[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE] = {0};
char processor_name[64] = {0};
Common::Mutex mutex;
#if defined(__APPLE__)
Common::Mutex main_task_mutex;
Common::CondVar main_task_done;
std::vector<std::function<void()>> main_tasks; // guarded by main_task_mutex
uint64_t main_tasks_queued = 0; // guarded by main_task_mutex
uint64_t main_tasks_run = 0; // guarded by main_task_mutex
#endif
};
} // namespace Libs::Graphics
+67 -19
View File
@@ -102,27 +102,75 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_user_name">
<property name="text">
<string>User name:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="MandatoryLineEdit" name="lineEdit_user_name">
<property name="toolTip">
<string>Local user name exposed to games</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_user_id">
<property name="text">
<string>User ID:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinBox_user_id">
<property name="toolTip">
<string>Local user ID exposed to games</string>
</property>
<property name="maximum">
<number>2147483647</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Screen resolution:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="3" column="1">
<widget class="QComboBox" name="comboBox_screen_resolution">
<property name="toolTip">
<string>Window resolution</string>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="4" column="0">
<widget class="QLabel" name="label_present_mode">
<property name="text">
<string>Present mode:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="comboBox_present_mode">
<property name="toolTip">
<string>Vulkan swapchain presentation mode</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_vblank_frequency">
<property name="text">
<string>Vblank frequency:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="5" column="1">
<widget class="QSpinBox" name="spinBox_vblank_frequency">
<property name="toolTip">
<string>Virtual display refresh rate used for frame pacing</string>
@@ -138,56 +186,56 @@
</property>
</widget>
</item>
<item row="3" column="0">
<item row="6" column="0">
<widget class="QLabel" name="label_console_language">
<property name="text">
<string>Console language:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="6" column="1">
<widget class="QComboBox" name="comboBox_console_language">
<property name="toolTip">
<string>Language</string>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="7" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Shader optimization type:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="7" column="1">
<widget class="QComboBox" name="comboBox_shader_optimization_type">
<property name="toolTip">
<string>Optimize shaders for code size or performance</string>
</property>
</widget>
</item>
<item row="5" column="0">
<item row="8" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Shader log direction:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="8" column="1">
<widget class="QComboBox" name="comboBox_shader_log_direction">
<property name="toolTip">
<string>Dump shaders to file or console window. If enabled may decrease emulator performance</string>
</property>
</widget>
</item>
<item row="6" column="0">
<item row="9" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Shader log folder:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="9" column="1">
<widget class="MandatoryLineEdit" name="lineEdit_shader_log_folder">
<property name="toolTip">
<string>Specify directory to dump shaders</string>
@@ -197,14 +245,14 @@
</property>
</widget>
</item>
<item row="7" column="0">
<item row="10" column="0">
<widget class="QLabel" name="label_24">
<property name="text">
<string>Command buffer dump folder:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<item row="10" column="1">
<widget class="MandatoryLineEdit" name="lineEdit_cmd_dump_folder">
<property name="toolTip">
<string>Specify directory to dump command buffers</string>
@@ -214,28 +262,28 @@
</property>
</widget>
</item>
<item row="8" column="0">
<item row="11" column="0">
<widget class="QLabel" name="label_25">
<property name="text">
<string>Printf direction:</string>
</property>
</widget>
</item>
<item row="8" column="1">
<item row="11" column="1">
<widget class="QComboBox" name="comboBox_printf_direction">
<property name="toolTip">
<string>Print logs to file or console window. If enabled may decrease emulator performance</string>
</property>
</widget>
</item>
<item row="9" column="0">
<item row="12" column="0">
<widget class="QLabel" name="label_26">
<property name="text">
<string>Printf output file:</string>
</property>
</widget>
</item>
<item row="9" column="1">
<item row="12" column="1">
<widget class="MandatoryLineEdit" name="lineEdit_printf_file">
<property name="toolTip">
<string>Specify file to dump logs</string>
@@ -245,14 +293,14 @@
</property>
</widget>
</item>
<item row="10" column="0">
<item row="13" column="0">
<widget class="QLabel" name="label_27">
<property name="text">
<string>Profiler direction:</string>
</property>
</widget>
</item>
<item row="10" column="1">
<item row="13" column="1">
<widget class="QComboBox" name="comboBox_profiler_direction">
<property name="toolTip">
<string>Enable or disable profiler. If enabled may decrease emulator performance</string>
+25
View File
@@ -2,6 +2,7 @@
#define LAUNCHER_INCLUDE_CONFIGURATION_H_
#include "common.h"
#include "common/emulatorConfig.h"
#include <QByteArray>
#include <QChar>
@@ -54,12 +55,17 @@ public:
enum class Resolution {
R1280X720,
R1920X1080,
R2560X1440,
R3840X2160,
};
Q_ENUM(Resolution)
enum class ShaderOptimizationType { None, Size, Performance };
Q_ENUM(ShaderOptimizationType)
enum class PresentMode { Fifo, Mailbox, Immediate };
Q_ENUM(PresentMode)
enum class ShaderLogDirection { Silent, Console, File };
Q_ENUM(ShaderLogDirection)
@@ -85,6 +91,9 @@ public:
QString game_comment;
Resolution screen_resolution = Resolution::R1280X720;
QString user_name = "Kyty";
int user_id = Config::DEFAULT_USER_ID;
PresentMode present_mode = PresentMode::Fifo;
bool fullscreen_enabled = false;
int vblank_frequency = 60;
int console_language = DEFAULT_CONSOLE_LANGUAGE;
@@ -108,6 +117,9 @@ public:
void CopyEmulatorSettingsFrom(const Configuration& other) {
screen_resolution = other.screen_resolution;
user_name = other.user_name;
user_id = other.user_id;
present_mode = other.present_mode;
fullscreen_enabled = other.fullscreen_enabled;
vblank_frequency = other.vblank_frequency;
console_language = other.console_language;
@@ -148,6 +160,9 @@ public:
KYTY_CFG_SET(game_path);
KYTY_CFG_SET(custom_settings);
KYTY_CFG_SET(screen_resolution);
KYTY_CFG_SET(user_name);
KYTY_CFG_SET(user_id);
KYTY_CFG_SET(present_mode);
KYTY_CFG_SET(fullscreen_enabled);
KYTY_CFG_SET(vblank_frequency);
KYTY_CFG_SET(console_language);
@@ -175,6 +190,16 @@ public:
KYTY_CFG_GET(game_path);
KYTY_CFG_GET(custom_settings);
KYTY_CFG_GET(screen_resolution);
user_name = s->value("user_name", user_name).toString();
bool user_id_ok = false;
auto saved_user_id = s->value("user_id", user_id).toInt(&user_id_ok);
user_id = user_id_ok && Config::IsConfiguredUserIdValid(saved_user_id)
? saved_user_id
: Config::DEFAULT_USER_ID;
KYTY_CFG_GET(present_mode);
if (EnumToText(present_mode).isEmpty()) {
present_mode = PresentMode::Fifo;
}
KYTY_CFG_GET(fullscreen_enabled);
vblank_frequency = s->value("vblank_frequency", vblank_frequency).toInt();
console_language = s->value("console_language", console_language).toInt();
@@ -1,5 +1,6 @@
#include "configurationEditDialog.h"
#include "common/emulatorConfig.h"
#include "configuration.h"
#include "mandatoryLineEdit.h"
@@ -12,6 +13,7 @@
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLayout>
#include <QLineEdit>
#include <QListView>
#include <QListWidget>
#include <QMessageBox>
@@ -152,7 +154,11 @@ static void ListInit(QComboBox* combo, T value) {
}
void ConfigurationEditDialog::Init(const Configuration& info) {
m_ui->lineEdit_user_name->setMaxLength(static_cast<int>(Config::MAX_USER_NAME_LENGTH));
m_ui->lineEdit_user_name->setText(info.user_name);
m_ui->spinBox_user_id->setValue(info.user_id);
ListInit(m_ui->comboBox_screen_resolution, info.screen_resolution);
ListInit(m_ui->comboBox_present_mode, info.present_mode);
m_ui->checkBox_fullscreen->setChecked(info.fullscreen_enabled);
m_ui->spinBox_vblank_frequency->setValue(info.vblank_frequency);
m_ui->comboBox_console_language->clear();
@@ -283,8 +289,12 @@ void ConfigurationEditDialog::moveEvent(QMoveEvent* event) {
}
static void UpdateInfo(Configuration& info, Ui::ConfigurationEditDialog& ui) {
info.user_name = ui.lineEdit_user_name->text().trimmed();
info.user_id = ui.spinBox_user_id->value();
info.screen_resolution =
TextToEnum<Configuration::Resolution>(ui.comboBox_screen_resolution->currentText());
info.present_mode =
TextToEnum<Configuration::PresentMode>(ui.comboBox_present_mode->currentText());
info.fullscreen_enabled = ui.checkBox_fullscreen->isChecked();
info.vblank_frequency = ui.spinBox_vblank_frequency->value();
info.console_language = ui.comboBox_console_language->currentIndex();
@@ -322,6 +332,19 @@ void ConfigurationEditDialog::save() {
return;
}
const auto user_name = m_ui->lineEdit_user_name->text().trimmed();
if (user_name.isEmpty() || user_name.toUtf8().size() > Config::MAX_USER_NAME_LENGTH) {
QMessageBox::critical(this, tr("Save failed"),
tr("User name must contain 1-16 UTF-8 bytes"));
return;
}
m_ui->lineEdit_user_name->setText(user_name);
if (!Config::IsConfiguredUserIdValid(m_ui->spinBox_user_id->value())) {
QMessageBox::critical(this, tr("Save failed"),
tr("User ID cannot be 254 (everyone) or 255 (system)"));
return;
}
update_info();
emit accept();
+3
View File
@@ -204,6 +204,9 @@ static QStringList CreateEmulatorArgs(const Configuration& info) {
args << "--screen-width" << r.at(0);
args << "--screen-height" << r.at(1);
args << "--user-name" << info.user_name;
args << "--user-id" << QString::number(info.user_id);
args << "--present-mode" << EnumToText(info.present_mode);
if (info.fullscreen_enabled) {
args << "--fullscreen";
}
+2 -2
View File
@@ -2,6 +2,7 @@
#include "common/assert.h"
#include "common/common.h"
#include "common/emulatorConfig.h"
#include "common/logging/log.h"
#include "common/stringUtils.h"
#include "common/threads.h"
@@ -358,13 +359,12 @@ int KYTY_SYSV_ABI PadInit() {
}
static bool PadOpenArgsAreValid(int user_id, int type, int index) {
constexpr int user_id_initial = 1000;
constexpr int user_id_system = 0xff;
constexpr int port_type_standard = 0;
constexpr int port_type_special = 2;
constexpr int port_type_remote = 16;
const bool personal_port =
user_id == user_id_initial && (type == port_type_standard || type == port_type_special);
user_id == Config::GetUserId() && (type == port_type_standard || type == port_type_special);
const bool system_remote_control = user_id == user_id_system && type == port_type_remote;
return index == 0 && (personal_port || system_remote_control);
}
+5 -5
View File
@@ -1,5 +1,6 @@
#include "libs/dialog.h"
#include "common/emulatorConfig.h"
#include "common/logging/log.h"
#include "common/stringUtils.h"
#include "libs/errno.h"
@@ -41,7 +42,6 @@ constexpr int LOGIN_RESULT_OK = 0;
constexpr int LOGIN_MODE_ALL_USERS = 0;
constexpr int LOGIN_MODE_NOT_LOGGED_IN = 1;
constexpr int LOGIN_USER_INVALID = -1;
constexpr int LOGIN_USER_ID = 1000;
constexpr int LOGIN_ERROR_NOT_INITIALIZED = static_cast<int>(0x81340001u);
constexpr int LOGIN_ERROR_ALREADY_INITIALIZED = static_cast<int>(0x81340002u);
@@ -67,7 +67,7 @@ static_assert(sizeof(LoginDialogResult) == 16);
static_assert(sizeof(LoginDialogParam) == 64);
static int g_login_status = LOGIN_STATUS_NONE;
static int g_login_selected_user = LOGIN_USER_ID;
static int g_login_selected_user = LOGIN_USER_INVALID;
int KYTY_SYSV_ABI LoginDialogInitialize() {
PRINT_NAME();
@@ -77,7 +77,7 @@ int KYTY_SYSV_ABI LoginDialogInitialize() {
}
g_login_status = LOGIN_STATUS_INITIALIZED;
g_login_selected_user = LOGIN_USER_ID;
g_login_selected_user = Config::GetUserId();
return OK;
}
@@ -90,7 +90,7 @@ int KYTY_SYSV_ABI LoginDialogTerminate() {
}
g_login_status = LOGIN_STATUS_NONE;
g_login_selected_user = LOGIN_USER_ID;
g_login_selected_user = LOGIN_USER_INVALID;
return OK;
}
@@ -112,7 +112,7 @@ int KYTY_SYSV_ABI LoginDialogOpen(const void* param) {
}
g_login_selected_user =
p->initial_focus != LOGIN_USER_INVALID ? p->initial_focus : LOGIN_USER_ID;
p->initial_focus != LOGIN_USER_INVALID ? p->initial_focus : Config::GetUserId();
LOGF("\t size = %d\n"
"\t mode = %d\n"
+1 -18
View File
@@ -327,25 +327,8 @@ static KYTY_SYSV_ABI int setenv(const char* name, const char* value, int overwri
return -1;
}
if (overwrite == 0 && std::getenv(name) != nullptr) {
return 0;
}
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
const auto ret = ::_putenv_s(name, value);
if (ret != 0) {
*Posix::GetErrorAddr() = ret;
return -1;
}
// Guest environment changes must not leak into emulator host libraries.
return 0;
#else
const auto ret = ::setenv(name, value, overwrite);
if (ret != 0) {
*Posix::GetErrorAddr() = errno;
return -1;
}
return 0;
#endif
}
static KYTY_SYSV_ABI int64_t libc_time(int64_t* timer) {
+16 -16
View File
@@ -1,11 +1,10 @@
#include "common/abi.h"
#include "common/assert.h"
#include "common/stringUtils.h"
#include "common/emulatorConfig.h"
#include "libs/errno.h"
#include "libs/libs.h"
#include "loader/symbolDatabase.h"
#include <cinttypes>
#include <cstdio>
#include <cstring>
@@ -57,7 +56,7 @@ static KYTY_SYSV_ABI int UserServiceGetInitialUser(int* user_id) {
EXIT_NOT_IMPLEMENTED(user_id == nullptr);
*user_id = 1000;
*user_id = Config::GetUserId();
return OK;
}
@@ -72,7 +71,7 @@ static KYTY_SYSV_ABI int UserServiceGetEvent(SceUserServiceEvent* event) {
if (!logged_in) {
logged_in = true;
event->event_type = UserServiceEventTypeLogin;
event->user_id = 1000;
event->user_id = Config::GetUserId();
return OK;
}
@@ -84,7 +83,7 @@ static KYTY_SYSV_ABI int UserServiceGetLoginUserIdList(UserServiceLoginUserIdLis
EXIT_NOT_IMPLEMENTED(user_id_list == nullptr);
user_id_list->user_id[0] = 1000;
user_id_list->user_id[0] = Config::GetUserId();
user_id_list->user_id[1] = -1;
user_id_list->user_id[2] = -1;
user_id_list->user_id[3] = -1;
@@ -93,10 +92,11 @@ static KYTY_SYSV_ABI int UserServiceGetLoginUserIdList(UserServiceLoginUserIdLis
}
static KYTY_SYSV_ABI int UserServiceGetUserName(int user_id, char* name, size_t size) {
EXIT_NOT_IMPLEMENTED(user_id != 1000);
EXIT_NOT_IMPLEMENTED(user_id != Config::GetUserId());
EXIT_NOT_IMPLEMENTED(size < 5);
int s = snprintf(name, size, "%s", "Kyty");
const auto& user_name = Config::GetUserName();
int s = snprintf(name, size, "%s", user_name.c_str());
EXIT_NOT_IMPLEMENTED(static_cast<size_t>(s) >= size);
@@ -109,7 +109,7 @@ static KYTY_SYSV_ABI int UserServiceGetUserNumber(int user_id, int32_t* number)
if (number == nullptr) {
return USER_SERVICE_ERROR_INVALID_ARGUMENT;
}
if (user_id != 1000) {
if (user_id != Config::GetUserId()) {
return USER_SERVICE_ERROR_NOT_LOGGED_IN;
}
@@ -124,7 +124,7 @@ static KYTY_SYSV_ABI int UserServiceGetGamePresets(int user_id, UserServiceGameP
if (presets == nullptr) {
return USER_SERVICE_ERROR_INVALID_ARGUMENT;
}
if (user_id != 1000) {
if (user_id != Config::GetUserId()) {
return USER_SERVICE_ERROR_NOT_LOGGED_IN;
}
@@ -145,7 +145,7 @@ static KYTY_SYSV_ABI int UserServiceGetAccessibilityVibration(int user_id, int32
if (vibration == nullptr) {
return USER_SERVICE_ERROR_INVALID_ARGUMENT;
}
if (user_id != 1000) {
if (user_id != Config::GetUserId()) {
return USER_SERVICE_ERROR_NOT_LOGGED_IN;
}
@@ -161,7 +161,7 @@ static KYTY_SYSV_ABI int UserServiceGetAccessibilityTriggerEffect(int user_
if (trigger_effect == nullptr) {
return USER_SERVICE_ERROR_INVALID_ARGUMENT;
}
if (user_id != 1000) {
if (user_id != Config::GetUserId()) {
return USER_SERVICE_ERROR_NOT_LOGGED_IN;
}
@@ -176,7 +176,7 @@ static KYTY_SYSV_ABI int UserServiceGetAgeLevel(int user_id, uint32_t* age_level
if (age_level == nullptr) {
return USER_SERVICE_ERROR_INVALID_ARGUMENT;
}
if (user_id != 1000) {
if (user_id != Config::GetUserId()) {
return USER_SERVICE_ERROR_NOT_LOGGED_IN;
}
@@ -192,7 +192,7 @@ static KYTY_SYSV_ABI int UserServiceGetAccessibilityChatTranscription(int u
if (chat_transcription == nullptr) {
return USER_SERVICE_ERROR_INVALID_ARGUMENT;
}
if (user_id != 1000) {
if (user_id != Config::GetUserId()) {
return USER_SERVICE_ERROR_NOT_LOGGED_IN;
}
@@ -208,7 +208,7 @@ UserServiceGetAccessibilityPressAndHoldDelay(int user_id, int32_t* press_and_hol
if (press_and_hold_delay == nullptr) {
return USER_SERVICE_ERROR_INVALID_ARGUMENT;
}
if (user_id != 1000) {
if (user_id != Config::GetUserId()) {
return USER_SERVICE_ERROR_NOT_LOGGED_IN;
}
@@ -224,7 +224,7 @@ static KYTY_SYSV_ABI int UserServiceGetAccessibilityZoomEnabled(int user_id
if (zoom_enabled == nullptr) {
return USER_SERVICE_ERROR_INVALID_ARGUMENT;
}
if (user_id != 1000) {
if (user_id != Config::GetUserId()) {
return USER_SERVICE_ERROR_NOT_LOGGED_IN;
}
@@ -240,7 +240,7 @@ static KYTY_SYSV_ABI int UserServiceGetAccessibilityZoomFollowFocus(int use
if (zoom_follow_focus == nullptr) {
return USER_SERVICE_ERROR_INVALID_ARGUMENT;
}
if (user_id != 1000) {
if (user_id != Config::GetUserId()) {
return USER_SERVICE_ERROR_NOT_LOGGED_IN;
}
+73 -63
View File
@@ -16,11 +16,6 @@
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
// POSIX uses plain int file descriptors for sockets; provide the Winsock spellings
// the shared (non-guarded) code paths reference.
using SOCKET = int;
static constexpr SOCKET INVALID_SOCKET = -1;
#endif
#include "common/assert.h"
@@ -823,9 +818,11 @@ struct NetEtherAddr {
#if defined(_WIN32)
using NativeSocket = SOCKET;
static constexpr NativeSocket INVALID_NATIVE_SOCKET = INVALID_SOCKET;
using SocketLength = int;
#else
using NativeSocket = int;
static constexpr NativeSocket INVALID_NATIVE_SOCKET = -1;
using SocketLength = socklen_t;
#endif
struct SocketSlot {
@@ -898,7 +895,12 @@ static bool EnsureSocketBackend() {
return true;
}
static int SetPosixSocketError(int error) {
static int SetGuestSocketError(int error) {
*Posix::GetErrorAddr() = error;
return -1;
}
static int SetHostSocketError(int error) {
int posix_error = Posix::POSIX_EIO;
#if defined(_WIN32)
switch (error) {
@@ -933,17 +935,31 @@ static int SetPosixSocketError(int error) {
default: break;
}
#else
posix_error = error;
switch (error) {
case EACCES: posix_error = Posix::POSIX_EACCES; break;
case EADDRINUSE: posix_error = Posix::POSIX_EADDRINUSE; break;
case EADDRNOTAVAIL: posix_error = Posix::POSIX_EADDRNOTAVAIL; break;
case EAFNOSUPPORT: posix_error = Posix::POSIX_EAFNOSUPPORT; break;
case EBADF: posix_error = Posix::POSIX_EBADF; break;
case EFAULT: posix_error = Posix::POSIX_EFAULT; break;
case EINVAL: posix_error = Posix::POSIX_EINVAL; break;
case EMFILE: posix_error = Posix::POSIX_EMFILE; break;
case ENFILE: posix_error = Posix::POSIX_ENFILE; break;
case ENOBUFS: posix_error = Posix::POSIX_ENOBUFS; break;
case ENOMEM: posix_error = Posix::POSIX_ENOMEM; break;
case ENOTSOCK: posix_error = Posix::POSIX_ENOTSOCK; break;
case EPROTONOSUPPORT: posix_error = Posix::POSIX_EPROTONOSUPPORT; break;
default: break;
}
#endif
*Posix::GetErrorAddr() = posix_error;
return -1;
return SetGuestSocketError(posix_error);
}
static int SetPosixSocketError() {
static int SetHostSocketError() {
#if defined(_WIN32)
return SetPosixSocketError(WSAGetLastError());
return SetHostSocketError(WSAGetLastError());
#else
return SetPosixSocketError(errno);
return SetHostSocketError(errno);
#endif
}
@@ -991,9 +1007,8 @@ static int ConvertMessageFlags(int flags) {
#endif
}
#if defined(_WIN32)
static int ConvertGuestSockaddr(const void* addr, uint32_t addrlen, sockaddr_storage* out,
int* out_len) {
SocketLength* out_len) {
EXIT_IF(out == nullptr);
EXIT_IF(out_len == nullptr);
@@ -1028,6 +1043,7 @@ static int ConvertGuestSockaddr(const void* addr, uint32_t addrlen, sockaddr_sto
return 0;
}
#if defined(_WIN32)
static int ConvertHostSockaddr(const sockaddr_storage* addr, int addrlen, void* out,
uint32_t* out_len) {
EXIT_IF(addr == nullptr);
@@ -1364,7 +1380,7 @@ int KYTY_SYSV_ABI NetGetSockInfo(int s, void* info, int n, int flags) {
int KYTY_SYSV_ABI EpollCreate(const char* name, int flags) {
if (name == nullptr || flags != 0) {
return SetPosixSocketError(Posix::POSIX_EINVAL);
return SetGuestSocketError(Posix::POSIX_EINVAL);
}
std::lock_guard lock(g_epoll_mutex);
@@ -1378,7 +1394,7 @@ int KYTY_SYSV_ABI EpollCreate(const char* name, int flags) {
}
}
return SetPosixSocketError(Posix::POSIX_EMFILE);
return SetGuestSocketError(Posix::POSIX_EMFILE);
}
int KYTY_SYSV_ABI EpollControl(int eid, int op, int id, const NetEpollEvent* event) {
@@ -1387,22 +1403,22 @@ int KYTY_SYSV_ABI EpollControl(int eid, int op, int id, const NetEpollEvent* eve
constexpr int EPOLL_CTL_DEL = 3;
if ((op == EPOLL_CTL_ADD || op == EPOLL_CTL_MOD) && event == nullptr) {
return SetPosixSocketError(Posix::POSIX_EINVAL);
return SetGuestSocketError(Posix::POSIX_EINVAL);
}
if (op == EPOLL_CTL_DEL && event != nullptr) {
return SetPosixSocketError(Posix::POSIX_EINVAL);
return SetGuestSocketError(Posix::POSIX_EINVAL);
}
if (op < EPOLL_CTL_ADD || op > EPOLL_CTL_DEL) {
return SetPosixSocketError(Posix::POSIX_EINVAL);
return SetGuestSocketError(Posix::POSIX_EINVAL);
}
if (!IsSocket(id)) {
return SetPosixSocketError(Posix::POSIX_EBADF);
return SetGuestSocketError(Posix::POSIX_EBADF);
}
std::lock_guard lock(g_epoll_mutex);
auto* slot = GetEpollSlot(eid);
if (slot == nullptr) {
return SetPosixSocketError(Posix::POSIX_EBADF);
return SetGuestSocketError(Posix::POSIX_EBADF);
}
auto registration = std::find_if(slot->registrations.begin(), slot->registrations.end(),
@@ -1410,19 +1426,19 @@ int KYTY_SYSV_ABI EpollControl(int eid, int op, int id, const NetEpollEvent* eve
switch (op) {
case EPOLL_CTL_ADD:
if (registration != slot->registrations.end()) {
return SetPosixSocketError(Posix::POSIX_EEXIST);
return SetGuestSocketError(Posix::POSIX_EEXIST);
}
slot->registrations.push_back({id, *event});
break;
case EPOLL_CTL_MOD:
if (registration == slot->registrations.end()) {
return SetPosixSocketError(Posix::POSIX_ENOENT);
return SetGuestSocketError(Posix::POSIX_ENOENT);
}
registration->event = *event;
break;
case EPOLL_CTL_DEL:
if (registration == slot->registrations.end()) {
return SetPosixSocketError(Posix::POSIX_ENOENT);
return SetGuestSocketError(Posix::POSIX_ENOENT);
}
slot->registrations.erase(registration);
break;
@@ -1435,10 +1451,10 @@ int KYTY_SYSV_ABI EpollControl(int eid, int op, int id, const NetEpollEvent* eve
int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int timeout) {
if (events == nullptr) {
return SetPosixSocketError(Posix::POSIX_EFAULT);
return SetGuestSocketError(Posix::POSIX_EFAULT);
}
if (maxevents <= 0 || timeout < -1) {
return SetPosixSocketError(Posix::POSIX_EINVAL);
return SetGuestSocketError(Posix::POSIX_EINVAL);
}
std::vector<EpollRegistration> registrations;
@@ -1446,7 +1462,7 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
std::unique_lock lock(g_epoll_mutex);
auto* slot = GetEpollSlot(eid);
if (slot == nullptr) {
return SetPosixSocketError(Posix::POSIX_EBADF);
return SetGuestSocketError(Posix::POSIX_EBADF);
}
if (slot->registrations.empty() && timeout != 0) {
@@ -1461,7 +1477,7 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
}
slot = GetEpollSlot(eid);
if (slot == nullptr) {
return SetPosixSocketError(Posix::POSIX_EBADF);
return SetGuestSocketError(Posix::POSIX_EBADF);
}
}
registrations = slot->registrations;
@@ -1492,7 +1508,7 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
continue;
}
if (host_registrations.size() >= FD_SETSIZE) {
return SetPosixSocketError(Posix::POSIX_EINVAL);
return SetGuestSocketError(Posix::POSIX_EINVAL);
}
if ((registration.event.events & EPOLL_IN) != 0) {
FD_SET(socket, &host_read);
@@ -1518,7 +1534,7 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
const int result = ::select(0, &host_read, &host_write, &host_except, host_timeout_ptr);
if (result == SOCKET_ERROR) {
return SetPosixSocketError();
return SetHostSocketError();
}
if (result == 0) {
return 0;
@@ -1552,7 +1568,7 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
return count;
#else
(void)timeout;
return SetPosixSocketError(Posix::POSIX_ENOSYS);
return SetGuestSocketError(Posix::POSIX_ENOSYS);
#endif
}
@@ -1560,7 +1576,7 @@ int KYTY_SYSV_ABI EpollDestroy(int eid) {
std::lock_guard lock(g_epoll_mutex);
auto* slot = GetEpollSlot(eid);
if (slot == nullptr) {
return SetPosixSocketError(Posix::POSIX_EBADF);
return SetGuestSocketError(Posix::POSIX_EBADF);
}
slot->used = false;
@@ -1582,14 +1598,15 @@ int KYTY_SYSV_ABI SocketClose(int s) {
RemoveSocketFromEpolls(s);
#if defined(_WIN32)
if (closesocket(socket) == SOCKET_ERROR) {
const int result = closesocket(socket);
#else
const int result = ::close(socket);
#endif
if (result != 0) {
return NET_ERROR_EBADF;
}
return OK;
#else
return NET_ERROR_ENOSYS;
#endif
}
int KYTY_SYSV_ABI Socket(int family, int type, int protocol) {
@@ -1601,7 +1618,7 @@ int KYTY_SYSV_ABI Socket(int family, int type, int protocol) {
family, type, protocol);
if (!EnsureSocketBackend()) {
return SetPosixSocketError(Posix::POSIX_ENETDOWN);
return SetGuestSocketError(Posix::POSIX_ENETDOWN);
}
const int host_family = ConvertFamily(family);
@@ -1610,25 +1627,24 @@ int KYTY_SYSV_ABI Socket(int family, int type, int protocol) {
return -1;
}
#if defined(_WIN32)
NativeSocket socket = ::socket(host_family, type, protocol);
if (socket == INVALID_NATIVE_SOCKET) {
return SetPosixSocketError();
return SetHostSocketError();
}
const int fd = AllocSocketFd(socket);
if (fd < 0) {
#if defined(_WIN32)
closesocket(socket);
#else
::close(socket);
#endif
*Posix::GetErrorAddr() = Posix::POSIX_EMFILE;
return -1;
}
LOGF("\t fd = %d\n", fd);
return fd;
#else
*Posix::GetErrorAddr() = Posix::POSIX_ENOSYS;
return -1;
#endif
}
int KYTY_SYSV_ABI Bind(int s, const void* addr, uint32_t addrlen) {
@@ -1645,23 +1661,17 @@ int KYTY_SYSV_ABI Bind(int s, const void* addr, uint32_t addrlen) {
return -1;
}
#if defined(_WIN32)
sockaddr_storage host_addr {};
int host_addrlen = 0;
SocketLength host_addrlen = 0;
if (ConvertGuestSockaddr(addr, addrlen, &host_addr, &host_addrlen) != 0) {
return -1;
}
if (::bind(socket, reinterpret_cast<const sockaddr*>(&host_addr), host_addrlen) ==
SOCKET_ERROR) {
return SetPosixSocketError();
if (::bind(socket, reinterpret_cast<const sockaddr*>(&host_addr), host_addrlen) != 0) {
return SetHostSocketError();
}
return 0;
#else
*Posix::GetErrorAddr() = Posix::POSIX_ENOSYS;
return -1;
#endif
}
int KYTY_SYSV_ABI Connect(int s, const void* addr, uint32_t addrlen) {
@@ -1687,7 +1697,7 @@ int KYTY_SYSV_ABI Connect(int s, const void* addr, uint32_t addrlen) {
if (::connect(socket, reinterpret_cast<const sockaddr*>(&host_addr), host_addrlen) ==
SOCKET_ERROR) {
return SetPosixSocketError();
return SetHostSocketError();
}
return 0;
@@ -1712,7 +1722,7 @@ int KYTY_SYSV_ABI Listen(int s, int backlog) {
#if defined(_WIN32)
if (::listen(socket, backlog) == SOCKET_ERROR) {
return SetPosixSocketError();
return SetHostSocketError();
}
return 0;
@@ -1742,7 +1752,7 @@ int KYTY_SYSV_ABI Accept(int s, void* addr, uint32_t* addrlen) {
NativeSocket accepted =
::accept(socket, reinterpret_cast<sockaddr*>(&host_addr), &host_addrlen);
if (accepted == INVALID_NATIVE_SOCKET) {
return SetPosixSocketError();
return SetHostSocketError();
}
const int fd = AllocSocketFd(accepted);
@@ -1791,7 +1801,7 @@ int KYTY_SYSV_ABI Shutdown(int s, int how) {
#if defined(_WIN32)
if (::shutdown(socket, how) == SOCKET_ERROR) {
return SetPosixSocketError();
return SetHostSocketError();
}
return 0;
@@ -1821,7 +1831,7 @@ int KYTY_SYSV_ABI Getsockname(int s, void* addr, uint32_t* addrlen) {
int host_addrlen = sizeof(host_addr);
if (::getsockname(socket, reinterpret_cast<sockaddr*>(&host_addr), &host_addrlen) ==
SOCKET_ERROR) {
return SetPosixSocketError();
return SetHostSocketError();
}
return ConvertHostSockaddr(&host_addr, host_addrlen, addr, addrlen);
@@ -1850,7 +1860,7 @@ int KYTY_SYSV_ABI Getsockopt(int s, int level, int optname, void* optval, uint32
int len = static_cast<int>(*optlen);
if (::getsockopt(socket, ConvertSocketOptionLevel(level), optname, static_cast<char*>(optval),
&len) == SOCKET_ERROR) {
return SetPosixSocketError();
return SetHostSocketError();
}
*optlen = static_cast<uint32_t>(len);
return 0;
@@ -1881,14 +1891,14 @@ int KYTY_SYSV_ABI Setsockopt(int s, int level, int optname, const void* optval,
optlen >= sizeof(int)) {
u_long enabled = (*static_cast<const int*>(optval) != 0 ? 1 : 0);
if (ioctlsocket(socket, FIONBIO, &enabled) == SOCKET_ERROR) {
return SetPosixSocketError();
return SetHostSocketError();
}
return 0;
}
if (::setsockopt(socket, ConvertSocketOptionLevel(level), optname,
static_cast<const char*>(optval), static_cast<int>(optlen)) == SOCKET_ERROR) {
return SetPosixSocketError();
return SetHostSocketError();
}
return 0;
@@ -1941,7 +1951,7 @@ int64_t KYTY_SYSV_ABI Sendto(int s, const void* buf, uint64_t len, int flags, co
reinterpret_cast<const sockaddr*>(&host_addr), host_addrlen);
}
if (result == SOCKET_ERROR) {
return SetPosixSocketError();
return SetHostSocketError();
}
return result;
@@ -2000,7 +2010,7 @@ int64_t KYTY_SYSV_ABI Recvfrom(int s, void* buf, uint64_t len, int flags, void*
}
}
if (result == SOCKET_ERROR) {
return SetPosixSocketError();
return SetHostSocketError();
}
return result;
@@ -2101,7 +2111,7 @@ int KYTY_SYSV_ABI Select(int nfds, void* readfds, void* writefds, void* exceptfd
const int result = ::select(0, read_ptr, write_ptr, except_ptr, host_timeout_ptr);
if (result == SOCKET_ERROR) {
return SetPosixSocketError();
return SetHostSocketError();
}
GuestFdZero(readfds, nfds);
+33
View File
@@ -47,6 +47,11 @@ static void PrintUsage() {
" --game-patch <json> Validated patch plan to apply before entry.\n");
::printf(" --screen-width <num> Window width. Default: 1280.\n");
::printf(" --screen-height <num> Window height. Default: 720.\n");
::printf(
" --user-name <name> Local user name (1-16 bytes). Default: Kyty.\n");
::printf(" --user-id <num> Local user ID. Default: %d.\n",
Config::DEFAULT_USER_ID);
::printf(" --present-mode <value> Fifo, Mailbox, or Immediate. Default: Fifo.\n");
::printf(" --fullscreen Run in borderless desktop fullscreen.\n");
::printf(" --vblank-frequency <num> Virtual vblank frequency. Default: 60.\n");
::printf(" --console-language <0-29> Console language. Default: 1 (English US).\n");
@@ -122,6 +127,17 @@ static bool ParseConsoleLanguage(const std::string& value, uint32_t& out) {
return true;
}
static bool ParseUserId(const std::string& value, int32_t& out) {
int32_t user_id = 0;
auto [end, error] = std::from_chars(value.data(), value.data() + value.size(), user_id);
if (error != std::errc {} || end != value.data() + value.size() ||
!Config::IsConfiguredUserIdValid(user_id)) {
return false;
}
out = user_id;
return true;
}
static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_help) {
show_help = false;
@@ -201,6 +217,23 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
options.config.screen_width = static_cast<uint32_t>(Common::ToInt32(value));
} else if (arg == "--screen-height") {
options.config.screen_height = static_cast<uint32_t>(Common::ToInt32(value));
} else if (arg == "--user-name") {
if (value.empty() || value.size() > Config::MAX_USER_NAME_LENGTH) {
::printf("invalid user name: must contain 1-%zu bytes\n",
Config::MAX_USER_NAME_LENGTH);
return false;
}
options.config.user_name = value;
} else if (arg == "--user-id") {
if (!ParseUserId(value, options.config.user_id)) {
::printf("invalid user ID: %s\n", value.c_str());
return false;
}
} else if (arg == "--present-mode") {
if (!ParseEnum(value, options.config.present_mode)) {
::printf("invalid present mode: %s\n", value.c_str());
return false;
}
} else if (arg == "--vblank-frequency") {
const int32_t vblank_frequency = Common::ToInt32(value);
options.config.vblank_frequency =