summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/frontend/emu_window.cpp3
-rw-r--r--src/core/frontend/framebuffer_layout.cpp36
-rw-r--r--src/core/frontend/framebuffer_layout.h11
-rw-r--r--src/core/hle/lock.cpp2
-rw-r--r--src/core/hle/lock.h2
-rw-r--r--src/core/hle/svc.cpp2
-rw-r--r--src/core/memory.cpp4
-rw-r--r--src/core/settings.cpp2
-rw-r--r--src/core/settings.h8
-rw-r--r--src/core/telemetry_session.cpp57
-rw-r--r--src/core/telemetry_session.h12
11 files changed, 129 insertions, 10 deletions
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
index 787c517ff..e67394177 100644
--- a/src/core/frontend/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -119,6 +119,9 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height)
case Settings::LayoutOption::LargeScreen:
layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen);
break;
+ case Settings::LayoutOption::SideScreen:
+ layout = Layout::SideFrameLayout(width, height, Settings::values.swap_screen);
+ break;
case Settings::LayoutOption::Default:
default:
layout = Layout::DefaultFrameLayout(width, height, Settings::values.swap_screen);
diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp
index d2d02f9ff..e9f778fcb 100644
--- a/src/core/frontend/framebuffer_layout.cpp
+++ b/src/core/frontend/framebuffer_layout.cpp
@@ -141,6 +141,40 @@ FramebufferLayout LargeFrameLayout(unsigned width, unsigned height, bool swapped
return res;
}
+FramebufferLayout SideFrameLayout(unsigned width, unsigned height, bool swapped) {
+ ASSERT(width > 0);
+ ASSERT(height > 0);
+
+ FramebufferLayout res{width, height, true, true, {}, {}};
+ // Aspect ratio of both screens side by side
+ const float emulation_aspect_ratio = static_cast<float>(Core::kScreenTopHeight) /
+ (Core::kScreenTopWidth + Core::kScreenBottomWidth);
+ float window_aspect_ratio = static_cast<float>(height) / width;
+ MathUtil::Rectangle<unsigned> screen_window_area{0, 0, width, height};
+ // Find largest Rectangle that can fit in the window size with the given aspect ratio
+ MathUtil::Rectangle<unsigned> screen_rect =
+ maxRectangle(screen_window_area, emulation_aspect_ratio);
+ // Find sizes of top and bottom screen
+ MathUtil::Rectangle<unsigned> top_screen = maxRectangle(screen_rect, TOP_SCREEN_ASPECT_RATIO);
+ MathUtil::Rectangle<unsigned> bot_screen = maxRectangle(screen_rect, BOT_SCREEN_ASPECT_RATIO);
+
+ if (window_aspect_ratio < emulation_aspect_ratio) {
+ // Apply borders to the left and right sides of the window.
+ u32 shift_horizontal = (screen_window_area.GetWidth() - screen_rect.GetWidth()) / 2;
+ top_screen = top_screen.TranslateX(shift_horizontal);
+ bot_screen = bot_screen.TranslateX(shift_horizontal);
+ } else {
+ // Window is narrower than the emulation content => apply borders to the top and bottom
+ u32 shift_vertical = (screen_window_area.GetHeight() - screen_rect.GetHeight()) / 2;
+ top_screen = top_screen.TranslateY(shift_vertical);
+ bot_screen = bot_screen.TranslateY(shift_vertical);
+ }
+ // Move the top screen to the right if we are swapped.
+ res.top_screen = swapped ? top_screen.TranslateX(bot_screen.GetWidth()) : top_screen;
+ res.bottom_screen = swapped ? bot_screen : bot_screen.TranslateX(top_screen.GetWidth());
+ return res;
+}
+
FramebufferLayout CustomFrameLayout(unsigned width, unsigned height) {
ASSERT(width > 0);
ASSERT(height > 0);
@@ -158,4 +192,4 @@ FramebufferLayout CustomFrameLayout(unsigned width, unsigned height) {
res.bottom_screen = bot_screen;
return res;
}
-}
+} // namespace Layout
diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h
index 9a7738969..4983cf103 100644
--- a/src/core/frontend/framebuffer_layout.h
+++ b/src/core/frontend/framebuffer_layout.h
@@ -54,6 +54,17 @@ FramebufferLayout SingleFrameLayout(unsigned width, unsigned height, bool is_swa
FramebufferLayout LargeFrameLayout(unsigned width, unsigned height, bool is_swapped);
/**
+* Factory method for constructing a Frame with the Top screen and bottom
+* screen side by side
+* This is useful for devices with small screens, like the GPDWin
+* @param width Window framebuffer width in pixels
+* @param height Window framebuffer height in pixels
+* @param is_swapped if true, the bottom screen will be the left display
+* @return Newly created FramebufferLayout object with default screen regions initialized
+*/
+FramebufferLayout SideFrameLayout(unsigned width, unsigned height, bool is_swapped);
+
+/**
* Factory method for constructing a custom FramebufferLayout
* @param width Window framebuffer width in pixels
* @param height Window framebuffer height in pixels
diff --git a/src/core/hle/lock.cpp b/src/core/hle/lock.cpp
index 082f689c8..1c24c7ce9 100644
--- a/src/core/hle/lock.cpp
+++ b/src/core/hle/lock.cpp
@@ -7,5 +7,5 @@
#include <core/hle/lock.h>
namespace HLE {
-std::mutex g_hle_lock;
+std::recursive_mutex g_hle_lock;
}
diff --git a/src/core/hle/lock.h b/src/core/hle/lock.h
index 8265621e1..5c99fe996 100644
--- a/src/core/hle/lock.h
+++ b/src/core/hle/lock.h
@@ -14,5 +14,5 @@ namespace HLE {
* to the emulated memory is not protected by this mutex, and should be avoided in any threads other
* than the CPU thread.
*/
-extern std::mutex g_hle_lock;
+extern std::recursive_mutex g_hle_lock;
} // namespace HLE
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index b98938cb4..dfc36748c 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -1334,7 +1334,7 @@ void CallSVC(u32 immediate) {
MICROPROFILE_SCOPE(Kernel_SVC);
// Lock the global kernel mutex when we enter the kernel HLE.
- std::lock_guard<std::mutex> lock(HLE::g_hle_lock);
+ std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
const FunctionDef* info = GetSVCInfo(immediate);
if (info) {
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index a3c5f4a9d..097bc5b47 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -183,7 +183,7 @@ T Read(const VAddr vaddr) {
}
// The memory access might do an MMIO or cached access, so we have to lock the HLE kernel state
- std::lock_guard<std::mutex> lock(HLE::g_hle_lock);
+ std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
switch (type) {
@@ -224,7 +224,7 @@ void Write(const VAddr vaddr, const T data) {
}
// The memory access might do an MMIO or cached access, so we have to lock the HLE kernel state
- std::lock_guard<std::mutex> lock(HLE::g_hle_lock);
+ std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
switch (type) {
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index d4f0429d1..efcf1267d 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -36,4 +36,4 @@ void Apply() {
Service::IR::ReloadInputDevices();
}
-} // namespace
+} // namespace Settings
diff --git a/src/core/settings.h b/src/core/settings.h
index 088d7651a..024f14666 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -15,6 +15,7 @@ enum class LayoutOption {
Default,
SingleScreen,
LargeScreen,
+ SideScreen,
};
namespace NativeButton {
@@ -70,7 +71,7 @@ enum Values {
static const std::array<const char*, NumAnalogs> mapping = {{
"circle_pad", "c_stick",
}};
-} // namespace NumAnalog
+} // namespace NativeAnalog
struct Values {
// CheckNew3DS
@@ -130,7 +131,10 @@ struct Values {
u16 gdbstub_port;
// WebService
+ bool enable_telemetry;
std::string telemetry_endpoint_url;
+ std::string citra_username;
+ std::string citra_token;
} extern values;
// a special value for Values::region_value indicating that citra will automatically select a region
@@ -138,4 +142,4 @@ struct Values {
static constexpr int REGION_VALUE_AUTO_SELECT = -1;
void Apply();
-}
+} // namespace Settings
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 94483f385..104a16cc9 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -3,8 +3,10 @@
// Refer to the license.txt file included.
#include <cstring>
+#include <cryptopp/osrng.h>
#include "common/assert.h"
+#include "common/file_util.h"
#include "common/scm_rev.h"
#include "common/x64/cpu_detect.h"
#include "core/core.h"
@@ -29,12 +31,65 @@ static const char* CpuVendorToStr(Common::CPUVendor vendor) {
UNREACHABLE();
}
+static u64 GenerateTelemetryId() {
+ u64 telemetry_id{};
+ CryptoPP::AutoSeededRandomPool rng;
+ rng.GenerateBlock(reinterpret_cast<CryptoPP::byte*>(&telemetry_id), sizeof(u64));
+ return telemetry_id;
+}
+
+u64 GetTelemetryId() {
+ u64 telemetry_id{};
+ static const std::string& filename{FileUtil::GetUserPath(D_CONFIG_IDX) + "telemetry_id"};
+
+ if (FileUtil::Exists(filename)) {
+ FileUtil::IOFile file(filename, "rb");
+ if (!file.IsOpen()) {
+ LOG_ERROR(Core, "failed to open telemetry_id: %s", filename.c_str());
+ return {};
+ }
+ file.ReadBytes(&telemetry_id, sizeof(u64));
+ } else {
+ FileUtil::IOFile file(filename, "wb");
+ if (!file.IsOpen()) {
+ LOG_ERROR(Core, "failed to open telemetry_id: %s", filename.c_str());
+ return {};
+ }
+ telemetry_id = GenerateTelemetryId();
+ file.WriteBytes(&telemetry_id, sizeof(u64));
+ }
+
+ return telemetry_id;
+}
+
+u64 RegenerateTelemetryId() {
+ const u64 new_telemetry_id{GenerateTelemetryId()};
+ static const std::string& filename{FileUtil::GetUserPath(D_CONFIG_IDX) + "telemetry_id"};
+
+ FileUtil::IOFile file(filename, "wb");
+ if (!file.IsOpen()) {
+ LOG_ERROR(Core, "failed to open telemetry_id: %s", filename.c_str());
+ return {};
+ }
+ file.WriteBytes(&new_telemetry_id, sizeof(u64));
+ return new_telemetry_id;
+}
+
TelemetrySession::TelemetrySession() {
#ifdef ENABLE_WEB_SERVICE
- backend = std::make_unique<WebService::TelemetryJson>();
+ if (Settings::values.enable_telemetry) {
+ backend = std::make_unique<WebService::TelemetryJson>(
+ Settings::values.telemetry_endpoint_url, Settings::values.citra_username,
+ Settings::values.citra_token);
+ } else {
+ backend = std::make_unique<Telemetry::NullVisitor>();
+ }
#else
backend = std::make_unique<Telemetry::NullVisitor>();
#endif
+ // Log one-time top-level information
+ AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId());
+
// Log one-time session start information
const s64 init_time{std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h
index cf53835c3..65613daae 100644
--- a/src/core/telemetry_session.h
+++ b/src/core/telemetry_session.h
@@ -35,4 +35,16 @@ private:
std::unique_ptr<Telemetry::VisitorInterface> backend; ///< Backend interface that logs fields
};
+/**
+ * Gets TelemetryId, a unique identifier used for the user's telemetry sessions.
+ * @returns The current TelemetryId for the session.
+ */
+u64 GetTelemetryId();
+
+/**
+ * Regenerates TelemetryId, a unique identifier used for the user's telemetry sessions.
+ * @returns The new TelemetryId that was generated.
+ */
+u64 RegenerateTelemetryId();
+
} // namespace Core