summaryrefslogtreecommitdiffstats
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/CMakeLists.txt100
-rw-r--r--src/common/bit_field.h10
-rw-r--r--src/common/color.h40
-rw-r--r--src/common/common_paths.h1
-rw-r--r--src/common/file_util.cpp1
-rw-r--r--src/common/file_util.h1
-rw-r--r--src/common/logging/backend.cpp70
-rw-r--r--src/common/logging/backend.h5
-rw-r--r--src/common/logging/log.h1
-rw-r--r--src/common/math_util.h4
-rw-r--r--src/common/memory_hook.cpp11
-rw-r--r--src/common/memory_hook.h47
-rw-r--r--src/common/page_table.cpp29
-rw-r--r--src/common/page_table.h80
-rw-r--r--src/common/quaternion.h10
-rw-r--r--src/common/scm_rev.cpp.in2
-rw-r--r--src/common/scm_rev.h1
-rw-r--r--src/common/swap.h6
-rw-r--r--src/common/thread_queue_list.h6
-rw-r--r--src/common/threadsafe_queue.h53
-rw-r--r--src/common/uint128.cpp45
-rw-r--r--src/common/uint128.h19
-rw-r--r--src/common/vector_math.h4
23 files changed, 415 insertions, 131 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 845626fc5..43ae8a9e7 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -1,42 +1,70 @@
-# Generate cpp with Git revision from template
-# Also if this is a CI build, add the build name (ie: Nightly, Canary) to the scm_rev file as well
-set(REPO_NAME "")
-set(BUILD_VERSION "0")
-if ($ENV{CI})
- if ($ENV{TRAVIS})
+# Add a custom command to generate a new shader_cache_version hash when any of the following files change
+# NOTE: This is an approximation of what files affect shader generation, its possible something else
+# could affect the result, but much more unlikely than the following files. Keeping a list of files
+# like this allows for much better caching since it doesn't force the user to recompile binary shaders every update
+set(VIDEO_CORE "${CMAKE_SOURCE_DIR}/src/video_core")
+if (DEFINED ENV{CI})
+ if (DEFINED ENV{TRAVIS})
set(BUILD_REPOSITORY $ENV{TRAVIS_REPO_SLUG})
set(BUILD_TAG $ENV{TRAVIS_TAG})
- elseif($ENV{APPVEYOR})
+ elseif(DEFINED ENV{APPVEYOR})
set(BUILD_REPOSITORY $ENV{APPVEYOR_REPO_NAME})
set(BUILD_TAG $ENV{APPVEYOR_REPO_TAG_NAME})
endif()
- # regex capture the string nightly or canary into CMAKE_MATCH_1
- string(REGEX MATCH "yuzu-emu/yuzu-?(.*)" OUTVAR ${BUILD_REPOSITORY})
- if (${CMAKE_MATCH_COUNT} GREATER 0)
- # capitalize the first letter of each word in the repo name.
- string(REPLACE "-" ";" REPO_NAME_LIST ${CMAKE_MATCH_1})
- foreach(WORD ${REPO_NAME_LIST})
- string(SUBSTRING ${WORD} 0 1 FIRST_LETTER)
- string(SUBSTRING ${WORD} 1 -1 REMAINDER)
- string(TOUPPER ${FIRST_LETTER} FIRST_LETTER)
- set(REPO_NAME "${REPO_NAME}${FIRST_LETTER}${REMAINDER}")
- endforeach()
- if (BUILD_TAG)
- string(REGEX MATCH "${CMAKE_MATCH_1}-([0-9]+)" OUTVAR ${BUILD_TAG})
- if (${CMAKE_MATCH_COUNT} GREATER 0)
- set(BUILD_VERSION ${CMAKE_MATCH_1})
- endif()
- if (BUILD_VERSION)
- # This leaves a trailing space on the last word, but we actually want that
- # because of how it's styled in the title bar.
- set(BUILD_FULLNAME "${REPO_NAME} ${BUILD_VERSION} ")
- else()
- set(BUILD_FULLNAME "")
- endif()
- endif()
- endif()
endif()
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp" @ONLY)
+add_custom_command(OUTPUT scm_rev.cpp
+ COMMAND ${CMAKE_COMMAND}
+ -DSRC_DIR="${CMAKE_SOURCE_DIR}"
+ -DBUILD_REPOSITORY="${BUILD_REPOSITORY}"
+ -DBUILD_TAG="${BUILD_TAG}"
+ -P "${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake"
+ DEPENDS
+ # WARNING! It was too much work to try and make a common location for this list,
+ # so if you need to change it, please update CMakeModules/GenerateSCMRev.cmake as well
+ "${VIDEO_CORE}/renderer_opengl/gl_shader_cache.cpp"
+ "${VIDEO_CORE}/renderer_opengl/gl_shader_cache.h"
+ "${VIDEO_CORE}/renderer_opengl/gl_shader_decompiler.cpp"
+ "${VIDEO_CORE}/renderer_opengl/gl_shader_decompiler.h"
+ "${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.cpp"
+ "${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.h"
+ "${VIDEO_CORE}/renderer_opengl/gl_shader_gen.cpp"
+ "${VIDEO_CORE}/renderer_opengl/gl_shader_gen.h"
+ "${VIDEO_CORE}/shader/decode/arithmetic.cpp"
+ "${VIDEO_CORE}/shader/decode/arithmetic_half.cpp"
+ "${VIDEO_CORE}/shader/decode/arithmetic_half_immediate.cpp"
+ "${VIDEO_CORE}/shader/decode/arithmetic_immediate.cpp"
+ "${VIDEO_CORE}/shader/decode/arithmetic_integer.cpp"
+ "${VIDEO_CORE}/shader/decode/arithmetic_integer_immediate.cpp"
+ "${VIDEO_CORE}/shader/decode/bfe.cpp"
+ "${VIDEO_CORE}/shader/decode/bfi.cpp"
+ "${VIDEO_CORE}/shader/decode/conversion.cpp"
+ "${VIDEO_CORE}/shader/decode/ffma.cpp"
+ "${VIDEO_CORE}/shader/decode/float_set.cpp"
+ "${VIDEO_CORE}/shader/decode/float_set_predicate.cpp"
+ "${VIDEO_CORE}/shader/decode/half_set.cpp"
+ "${VIDEO_CORE}/shader/decode/half_set_predicate.cpp"
+ "${VIDEO_CORE}/shader/decode/hfma2.cpp"
+ "${VIDEO_CORE}/shader/decode/integer_set.cpp"
+ "${VIDEO_CORE}/shader/decode/integer_set_predicate.cpp"
+ "${VIDEO_CORE}/shader/decode/memory.cpp"
+ "${VIDEO_CORE}/shader/decode/texture.cpp"
+ "${VIDEO_CORE}/shader/decode/other.cpp"
+ "${VIDEO_CORE}/shader/decode/predicate_set_predicate.cpp"
+ "${VIDEO_CORE}/shader/decode/predicate_set_register.cpp"
+ "${VIDEO_CORE}/shader/decode/register_set_predicate.cpp"
+ "${VIDEO_CORE}/shader/decode/shift.cpp"
+ "${VIDEO_CORE}/shader/decode/video.cpp"
+ "${VIDEO_CORE}/shader/decode/xmad.cpp"
+ "${VIDEO_CORE}/shader/decode.cpp"
+ "${VIDEO_CORE}/shader/shader_ir.cpp"
+ "${VIDEO_CORE}/shader/shader_ir.h"
+ "${VIDEO_CORE}/shader/track.cpp"
+ # and also check that the scm_rev files haven't changed
+ "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in"
+ "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.h"
+ # technically we should regenerate if the git version changed, but its not worth the effort imo
+ "${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake"
+)
add_library(common STATIC
alignment.h
@@ -64,10 +92,14 @@ add_library(common STATIC
logging/text_formatter.cpp
logging/text_formatter.h
math_util.h
+ memory_hook.cpp
+ memory_hook.h
microprofile.cpp
microprofile.h
microprofileui.h
misc.cpp
+ page_table.cpp
+ page_table.h
param_package.cpp
param_package.h
quaternion.h
@@ -86,6 +118,8 @@ add_library(common STATIC
threadsafe_queue.h
timer.cpp
timer.h
+ uint128.cpp
+ uint128.h
vector_math.h
web_result.h
)
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 639efe22d..8e35c463f 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -162,9 +162,13 @@ public:
BitField(T val) = delete;
BitField& operator=(T val) = delete;
- // Force default constructor to be created
- // so that we can use this within unions
- constexpr BitField() = default;
+ constexpr BitField() noexcept = default;
+
+ constexpr BitField(const BitField&) noexcept = default;
+ constexpr BitField& operator=(const BitField&) noexcept = default;
+
+ constexpr BitField(BitField&&) noexcept = default;
+ constexpr BitField& operator=(BitField&&) noexcept = default;
constexpr FORCE_INLINE operator T() const {
return Value();
diff --git a/src/common/color.h b/src/common/color.h
index 0379040be..3a2222077 100644
--- a/src/common/color.h
+++ b/src/common/color.h
@@ -55,36 +55,36 @@ constexpr u8 Convert8To6(u8 value) {
/**
* Decode a color stored in RGBA8 format
* @param bytes Pointer to encoded source color
- * @return Result color decoded as Math::Vec4<u8>
+ * @return Result color decoded as Common::Vec4<u8>
*/
-inline Math::Vec4<u8> DecodeRGBA8(const u8* bytes) {
+inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) {
return {bytes[3], bytes[2], bytes[1], bytes[0]};
}
/**
* Decode a color stored in RGB8 format
* @param bytes Pointer to encoded source color
- * @return Result color decoded as Math::Vec4<u8>
+ * @return Result color decoded as Common::Vec4<u8>
*/
-inline Math::Vec4<u8> DecodeRGB8(const u8* bytes) {
+inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) {
return {bytes[2], bytes[1], bytes[0], 255};
}
/**
* Decode a color stored in RG8 (aka HILO8) format
* @param bytes Pointer to encoded source color
- * @return Result color decoded as Math::Vec4<u8>
+ * @return Result color decoded as Common::Vec4<u8>
*/
-inline Math::Vec4<u8> DecodeRG8(const u8* bytes) {
+inline Common::Vec4<u8> DecodeRG8(const u8* bytes) {
return {bytes[1], bytes[0], 0, 255};
}
/**
* Decode a color stored in RGB565 format
* @param bytes Pointer to encoded source color
- * @return Result color decoded as Math::Vec4<u8>
+ * @return Result color decoded as Common::Vec4<u8>
*/
-inline Math::Vec4<u8> DecodeRGB565(const u8* bytes) {
+inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) {
u16_le pixel;
std::memcpy(&pixel, bytes, sizeof(pixel));
return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F),
@@ -94,9 +94,9 @@ inline Math::Vec4<u8> DecodeRGB565(const u8* bytes) {
/**
* Decode a color stored in RGB5A1 format
* @param bytes Pointer to encoded source color
- * @return Result color decoded as Math::Vec4<u8>
+ * @return Result color decoded as Common::Vec4<u8>
*/
-inline Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
+inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
u16_le pixel;
std::memcpy(&pixel, bytes, sizeof(pixel));
return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F),
@@ -106,9 +106,9 @@ inline Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
/**
* Decode a color stored in RGBA4 format
* @param bytes Pointer to encoded source color
- * @return Result color decoded as Math::Vec4<u8>
+ * @return Result color decoded as Common::Vec4<u8>
*/
-inline Math::Vec4<u8> DecodeRGBA4(const u8* bytes) {
+inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) {
u16_le pixel;
std::memcpy(&pixel, bytes, sizeof(pixel));
return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF),
@@ -138,9 +138,9 @@ inline u32 DecodeD24(const u8* bytes) {
/**
* Decode a depth value and a stencil value stored in D24S8 format
* @param bytes Pointer to encoded source values
- * @return Resulting values stored as a Math::Vec2
+ * @return Resulting values stored as a Common::Vec2
*/
-inline Math::Vec2<u32> DecodeD24S8(const u8* bytes) {
+inline Common::Vec2<u32> DecodeD24S8(const u8* bytes) {
return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]};
}
@@ -149,7 +149,7 @@ inline Math::Vec2<u32> DecodeD24S8(const u8* bytes) {
* @param color Source color to encode
* @param bytes Destination pointer to store encoded color
*/
-inline void EncodeRGBA8(const Math::Vec4<u8>& color, u8* bytes) {
+inline void EncodeRGBA8(const Common::Vec4<u8>& color, u8* bytes) {
bytes[3] = color.r();
bytes[2] = color.g();
bytes[1] = color.b();
@@ -161,7 +161,7 @@ inline void EncodeRGBA8(const Math::Vec4<u8>& color, u8* bytes) {
* @param color Source color to encode
* @param bytes Destination pointer to store encoded color
*/
-inline void EncodeRGB8(const Math::Vec4<u8>& color, u8* bytes) {
+inline void EncodeRGB8(const Common::Vec4<u8>& color, u8* bytes) {
bytes[2] = color.r();
bytes[1] = color.g();
bytes[0] = color.b();
@@ -172,7 +172,7 @@ inline void EncodeRGB8(const Math::Vec4<u8>& color, u8* bytes) {
* @param color Source color to encode
* @param bytes Destination pointer to store encoded color
*/
-inline void EncodeRG8(const Math::Vec4<u8>& color, u8* bytes) {
+inline void EncodeRG8(const Common::Vec4<u8>& color, u8* bytes) {
bytes[1] = color.r();
bytes[0] = color.g();
}
@@ -181,7 +181,7 @@ inline void EncodeRG8(const Math::Vec4<u8>& color, u8* bytes) {
* @param color Source color to encode
* @param bytes Destination pointer to store encoded color
*/
-inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) {
+inline void EncodeRGB565(const Common::Vec4<u8>& color, u8* bytes) {
const u16_le data =
(Convert8To5(color.r()) << 11) | (Convert8To6(color.g()) << 5) | Convert8To5(color.b());
@@ -193,7 +193,7 @@ inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) {
* @param color Source color to encode
* @param bytes Destination pointer to store encoded color
*/
-inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) {
+inline void EncodeRGB5A1(const Common::Vec4<u8>& color, u8* bytes) {
const u16_le data = (Convert8To5(color.r()) << 11) | (Convert8To5(color.g()) << 6) |
(Convert8To5(color.b()) << 1) | Convert8To1(color.a());
@@ -205,7 +205,7 @@ inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) {
* @param color Source color to encode
* @param bytes Destination pointer to store encoded color
*/
-inline void EncodeRGBA4(const Math::Vec4<u8>& color, u8* bytes) {
+inline void EncodeRGBA4(const Common::Vec4<u8>& color, u8* bytes) {
const u16 data = (Convert8To4(color.r()) << 12) | (Convert8To4(color.g()) << 8) |
(Convert8To4(color.b()) << 4) | Convert8To4(color.a());
diff --git a/src/common/common_paths.h b/src/common/common_paths.h
index 4f88de768..076752d3b 100644
--- a/src/common/common_paths.h
+++ b/src/common/common_paths.h
@@ -35,6 +35,7 @@
#define KEYS_DIR "keys"
#define LOAD_DIR "load"
#define DUMP_DIR "dump"
+#define SHADER_DIR "shader"
#define LOG_DIR "log"
// Filenames
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index b52492da6..aecb66c32 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -710,6 +710,7 @@ const std::string& GetUserPath(UserPath path, const std::string& new_path) {
paths.emplace(UserPath::NANDDir, user_path + NAND_DIR DIR_SEP);
paths.emplace(UserPath::LoadDir, user_path + LOAD_DIR DIR_SEP);
paths.emplace(UserPath::DumpDir, user_path + DUMP_DIR DIR_SEP);
+ paths.emplace(UserPath::ShaderDir, user_path + SHADER_DIR DIR_SEP);
paths.emplace(UserPath::SysDataDir, user_path + SYSDATA_DIR DIR_SEP);
paths.emplace(UserPath::KeysDir, user_path + KEYS_DIR DIR_SEP);
// TODO: Put the logs in a better location for each OS
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 571503d2a..38cc7f059 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -31,6 +31,7 @@ enum class UserPath {
SDMCDir,
LoadDir,
DumpDir,
+ ShaderDir,
SysDataDir,
UserDir,
};
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 12f6d0114..4462ff3fb 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -39,10 +39,10 @@ public:
Impl(Impl const&) = delete;
const Impl& operator=(Impl const&) = delete;
- void PushEntry(Entry e) {
- std::lock_guard<std::mutex> lock(message_mutex);
- message_queue.Push(std::move(e));
- message_cv.notify_one();
+ void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num,
+ const char* function, std::string message) {
+ message_queue.Push(
+ CreateEntry(log_class, log_level, filename, line_num, function, std::move(message)));
}
void AddBackend(std::unique_ptr<Backend> backend) {
@@ -86,15 +86,13 @@ private:
}
};
while (true) {
- {
- std::unique_lock<std::mutex> lock(message_mutex);
- message_cv.wait(lock, [&] { return !running || message_queue.Pop(entry); });
- }
- if (!running) {
+ entry = message_queue.PopWait();
+ if (entry.final_entry) {
break;
}
write_logs(entry);
}
+
// Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a case
// where a system is repeatedly spamming logs even on close.
const int MAX_LOGS_TO_WRITE = filter.IsDebug() ? INT_MAX : 100;
@@ -106,18 +104,36 @@ private:
}
~Impl() {
- running = false;
- message_cv.notify_one();
+ Entry entry;
+ entry.final_entry = true;
+ message_queue.Push(entry);
backend_thread.join();
}
- std::atomic_bool running{true};
- std::mutex message_mutex, writing_mutex;
- std::condition_variable message_cv;
+ Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
+ const char* function, std::string message) const {
+ using std::chrono::duration_cast;
+ using std::chrono::steady_clock;
+
+ Entry entry;
+ entry.timestamp =
+ duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin);
+ entry.log_class = log_class;
+ entry.log_level = log_level;
+ entry.filename = Common::TrimSourcePath(filename);
+ entry.line_num = line_nr;
+ entry.function = function;
+ entry.message = std::move(message);
+
+ return entry;
+ }
+
+ std::mutex writing_mutex;
std::thread backend_thread;
std::vector<std::unique_ptr<Backend>> backends;
Common::MPSCQueue<Log::Entry> message_queue;
Filter filter;
+ std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
};
void ConsoleBackend::Write(const Entry& entry) {
@@ -232,6 +248,7 @@ void DebuggerBackend::Write(const Entry& entry) {
CLS(Render) \
SUB(Render, Software) \
SUB(Render, OpenGL) \
+ SUB(Render, Vulkan) \
CLS(Audio) \
SUB(Audio, DSP) \
SUB(Audio, Sink) \
@@ -275,25 +292,6 @@ const char* GetLevelName(Level log_level) {
#undef LVL
}
-Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
- const char* function, std::string message) {
- using std::chrono::duration_cast;
- using std::chrono::steady_clock;
-
- static steady_clock::time_point time_origin = steady_clock::now();
-
- Entry entry;
- entry.timestamp = duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin);
- entry.log_class = log_class;
- entry.log_level = log_level;
- entry.filename = Common::TrimSourcePath(filename);
- entry.line_num = line_nr;
- entry.function = function;
- entry.message = std::move(message);
-
- return entry;
-}
-
void SetGlobalFilter(const Filter& filter) {
Impl::Instance().SetGlobalFilter(filter);
}
@@ -318,9 +316,7 @@ void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
if (!filter.CheckMessage(log_class, log_level))
return;
- Entry entry =
- CreateEntry(log_class, log_level, filename, line_num, function, fmt::vformat(format, args));
-
- instance.PushEntry(std::move(entry));
+ instance.PushEntry(log_class, log_level, filename, line_num, function,
+ fmt::vformat(format, args));
}
} // namespace Log
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
index 91bb0c309..fca0267a1 100644
--- a/src/common/logging/backend.h
+++ b/src/common/logging/backend.h
@@ -27,6 +27,7 @@ struct Entry {
unsigned int line_num;
std::string function;
std::string message;
+ bool final_entry = false;
Entry() = default;
Entry(Entry&& o) = default;
@@ -134,10 +135,6 @@ const char* GetLogClassName(Class log_class);
*/
const char* GetLevelName(Level log_level);
-/// Creates a log entry by formatting the given source location, and message.
-Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
- const char* function, std::string message);
-
/**
* The global filter will prevent any messages from even being processed if they are filtered. Each
* backend can have a filter, but if the level is lower than the global filter, the backend will
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index d4ec31ec3..8ed6d5050 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -112,6 +112,7 @@ enum class Class : ClassType {
Render, ///< Emulator video output and hardware acceleration
Render_Software, ///< Software renderer backend
Render_OpenGL, ///< OpenGL backend
+ Render_Vulkan, ///< Vulkan backend
Audio, ///< Audio emulation
Audio_DSP, ///< The HLE implementation of the DSP
Audio_Sink, ///< Emulator audio output backend
diff --git a/src/common/math_util.h b/src/common/math_util.h
index 94b4394c5..cff3d48c5 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -7,7 +7,7 @@
#include <cstdlib>
#include <type_traits>
-namespace MathUtil {
+namespace Common {
constexpr float PI = 3.14159265f;
@@ -41,4 +41,4 @@ struct Rectangle {
}
};
-} // namespace MathUtil
+} // namespace Common
diff --git a/src/common/memory_hook.cpp b/src/common/memory_hook.cpp
new file mode 100644
index 000000000..3986986d6
--- /dev/null
+++ b/src/common/memory_hook.cpp
@@ -0,0 +1,11 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/memory_hook.h"
+
+namespace Common {
+
+MemoryHook::~MemoryHook() = default;
+
+} // namespace Common
diff --git a/src/common/memory_hook.h b/src/common/memory_hook.h
new file mode 100644
index 000000000..adaa4c2c5
--- /dev/null
+++ b/src/common/memory_hook.h
@@ -0,0 +1,47 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <optional>
+
+#include "common/common_types.h"
+
+namespace Common {
+
+/**
+ * Memory hooks have two purposes:
+ * 1. To allow reads and writes to a region of memory to be intercepted. This is used to implement
+ * texture forwarding and memory breakpoints for debugging.
+ * 2. To allow for the implementation of MMIO devices.
+ *
+ * A hook may be mapped to multiple regions of memory.
+ *
+ * If a std::nullopt or false is returned from a function, the read/write request is passed through
+ * to the underlying memory region.
+ */
+class MemoryHook {
+public:
+ virtual ~MemoryHook();
+
+ virtual std::optional<bool> IsValidAddress(VAddr addr) = 0;
+
+ virtual std::optional<u8> Read8(VAddr addr) = 0;
+ virtual std::optional<u16> Read16(VAddr addr) = 0;
+ virtual std::optional<u32> Read32(VAddr addr) = 0;
+ virtual std::optional<u64> Read64(VAddr addr) = 0;
+
+ virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) = 0;
+
+ virtual bool Write8(VAddr addr, u8 data) = 0;
+ virtual bool Write16(VAddr addr, u16 data) = 0;
+ virtual bool Write32(VAddr addr, u32 data) = 0;
+ virtual bool Write64(VAddr addr, u64 data) = 0;
+
+ virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size) = 0;
+};
+
+using MemoryHookPointer = std::shared_ptr<MemoryHook>;
+} // namespace Common
diff --git a/src/common/page_table.cpp b/src/common/page_table.cpp
new file mode 100644
index 000000000..8eba1c3f1
--- /dev/null
+++ b/src/common/page_table.cpp
@@ -0,0 +1,29 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/page_table.h"
+
+namespace Common {
+
+PageTable::PageTable(std::size_t page_size_in_bits) : page_size_in_bits{page_size_in_bits} {}
+
+PageTable::~PageTable() = default;
+
+void PageTable::Resize(std::size_t address_space_width_in_bits) {
+ const std::size_t num_page_table_entries = 1ULL
+ << (address_space_width_in_bits - page_size_in_bits);
+
+ pointers.resize(num_page_table_entries);
+ attributes.resize(num_page_table_entries);
+
+ // The default is a 39-bit address space, which causes an initial 1GB allocation size. If the
+ // vector size is subsequently decreased (via resize), the vector might not automatically
+ // actually reallocate/resize its underlying allocation, which wastes up to ~800 MB for
+ // 36-bit titles. Call shrink_to_fit to reduce capacity to what's actually in use.
+
+ pointers.shrink_to_fit();
+ attributes.shrink_to_fit();
+}
+
+} // namespace Common
diff --git a/src/common/page_table.h b/src/common/page_table.h
new file mode 100644
index 000000000..8339f2890
--- /dev/null
+++ b/src/common/page_table.h
@@ -0,0 +1,80 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <vector>
+#include <boost/icl/interval_map.hpp>
+#include "common/common_types.h"
+#include "common/memory_hook.h"
+
+namespace Common {
+
+enum class PageType : u8 {
+ /// Page is unmapped and should cause an access error.
+ Unmapped,
+ /// Page is mapped to regular memory. This is the only type you can get pointers to.
+ Memory,
+ /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and
+ /// invalidation
+ RasterizerCachedMemory,
+ /// Page is mapped to a I/O region. Writing and reading to this page is handled by functions.
+ Special,
+};
+
+struct SpecialRegion {
+ enum class Type {
+ DebugHook,
+ IODevice,
+ } type;
+
+ MemoryHookPointer handler;
+
+ bool operator<(const SpecialRegion& other) const {
+ return std::tie(type, handler) < std::tie(other.type, other.handler);
+ }
+
+ bool operator==(const SpecialRegion& other) const {
+ return std::tie(type, handler) == std::tie(other.type, other.handler);
+ }
+};
+
+/**
+ * A (reasonably) fast way of allowing switchable and remappable process address spaces. It loosely
+ * mimics the way a real CPU page table works.
+ */
+struct PageTable {
+ explicit PageTable(std::size_t page_size_in_bits);
+ ~PageTable();
+
+ /**
+ * Resizes the page table to be able to accomodate enough pages within
+ * a given address space.
+ *
+ * @param address_space_width_in_bits The address size width in bits.
+ */
+ void Resize(std::size_t address_space_width_in_bits);
+
+ /**
+ * Vector of memory pointers backing each page. An entry can only be non-null if the
+ * corresponding entry in the `attributes` vector is of type `Memory`.
+ */
+ std::vector<u8*> pointers;
+
+ /**
+ * Contains MMIO handlers that back memory regions whose entries in the `attribute` vector is
+ * of type `Special`.
+ */
+ boost::icl::interval_map<VAddr, std::set<SpecialRegion>> special_regions;
+
+ /**
+ * Vector of fine grained page attributes. If it is set to any value other than `Memory`, then
+ * the corresponding entry in `pointers` MUST be set to null.
+ */
+ std::vector<PageType> attributes;
+
+ const std::size_t page_size_in_bits{};
+};
+
+} // namespace Common
diff --git a/src/common/quaternion.h b/src/common/quaternion.h
index c528c0b68..370198ae0 100644
--- a/src/common/quaternion.h
+++ b/src/common/quaternion.h
@@ -6,12 +6,12 @@
#include "common/vector_math.h"
-namespace Math {
+namespace Common {
template <typename T>
class Quaternion {
public:
- Math::Vec3<T> xyz;
+ Vec3<T> xyz;
T w{};
Quaternion<decltype(-T{})> Inverse() const {
@@ -38,12 +38,12 @@ public:
};
template <typename T>
-auto QuaternionRotate(const Quaternion<T>& q, const Math::Vec3<T>& v) {
+auto QuaternionRotate(const Quaternion<T>& q, const Vec3<T>& v) {
return v + 2 * Cross(q.xyz, Cross(q.xyz, v) + v * q.w);
}
-inline Quaternion<float> MakeQuaternion(const Math::Vec3<float>& axis, float angle) {
+inline Quaternion<float> MakeQuaternion(const Vec3<float>& axis, float angle) {
return {axis * std::sin(angle / 2), std::cos(angle / 2)};
}
-} // namespace Math
+} // namespace Common
diff --git a/src/common/scm_rev.cpp.in b/src/common/scm_rev.cpp.in
index 2b1727769..d69038f65 100644
--- a/src/common/scm_rev.cpp.in
+++ b/src/common/scm_rev.cpp.in
@@ -11,6 +11,7 @@
#define BUILD_DATE "@BUILD_DATE@"
#define BUILD_FULLNAME "@BUILD_FULLNAME@"
#define BUILD_VERSION "@BUILD_VERSION@"
+#define SHADER_CACHE_VERSION "@SHADER_CACHE_VERSION@"
namespace Common {
@@ -21,6 +22,7 @@ const char g_build_name[] = BUILD_NAME;
const char g_build_date[] = BUILD_DATE;
const char g_build_fullname[] = BUILD_FULLNAME;
const char g_build_version[] = BUILD_VERSION;
+const char g_shader_cache_version[] = SHADER_CACHE_VERSION;
} // namespace
diff --git a/src/common/scm_rev.h b/src/common/scm_rev.h
index af9a9daed..666bf0367 100644
--- a/src/common/scm_rev.h
+++ b/src/common/scm_rev.h
@@ -13,5 +13,6 @@ extern const char g_build_name[];
extern const char g_build_date[];
extern const char g_build_fullname[];
extern const char g_build_version[];
+extern const char g_shader_cache_version[];
} // namespace Common
diff --git a/src/common/swap.h b/src/common/swap.h
index 4b82865fe..b3eab1324 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -30,8 +30,8 @@
#include <cstring>
#include "common/common_types.h"
-// GCC 4.6+
-#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+// GCC
+#ifdef __GNUC__
#if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && !defined(COMMON_LITTLE_ENDIAN)
#define COMMON_LITTLE_ENDIAN 1
@@ -40,7 +40,7 @@
#endif
// LLVM/clang
-#elif __clang__
+#elif defined(__clang__)
#if __LITTLE_ENDIAN__ && !defined(COMMON_LITTLE_ENDIAN)
#define COMMON_LITTLE_ENDIAN 1
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
index e7594db68..791f99a8c 100644
--- a/src/common/thread_queue_list.h
+++ b/src/common/thread_queue_list.h
@@ -6,7 +6,6 @@
#include <array>
#include <deque>
-#include <boost/range/algorithm_ext/erase.hpp>
namespace Common {
@@ -111,8 +110,9 @@ struct ThreadQueueList {
}
void remove(Priority priority, const T& thread_id) {
- Queue* cur = &queues[priority];
- boost::remove_erase(cur->data, thread_id);
+ Queue* const cur = &queues[priority];
+ const auto iter = std::remove(cur->data.begin(), cur->data.end(), thread_id);
+ cur->data.erase(iter, cur->data.end());
}
void rotate(Priority priority) {
diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h
index edf13bc49..821e8536a 100644
--- a/src/common/threadsafe_queue.h
+++ b/src/common/threadsafe_queue.h
@@ -7,17 +7,17 @@
// a simple lockless thread-safe,
// single reader, single writer queue
-#include <algorithm>
#include <atomic>
+#include <condition_variable>
#include <cstddef>
#include <mutex>
-#include "common/common_types.h"
+#include <utility>
namespace Common {
-template <typename T, bool NeedSize = true>
+template <typename T>
class SPSCQueue {
public:
- SPSCQueue() : size(0) {
+ SPSCQueue() {
write_ptr = read_ptr = new ElementPtr();
}
~SPSCQueue() {
@@ -25,13 +25,12 @@ public:
delete read_ptr;
}
- u32 Size() const {
- static_assert(NeedSize, "using Size() on FifoQueue without NeedSize");
+ std::size_t Size() const {
return size.load();
}
bool Empty() const {
- return !read_ptr->next.load();
+ return Size() == 0;
}
T& Front() const {
@@ -47,13 +46,14 @@ public:
ElementPtr* new_ptr = new ElementPtr();
write_ptr->next.store(new_ptr, std::memory_order_release);
write_ptr = new_ptr;
- if (NeedSize)
- size++;
+ cv.notify_one();
+
+ ++size;
}
void Pop() {
- if (NeedSize)
- size--;
+ --size;
+
ElementPtr* tmpptr = read_ptr;
// advance the read pointer
read_ptr = tmpptr->next.load();
@@ -66,8 +66,7 @@ public:
if (Empty())
return false;
- if (NeedSize)
- size--;
+ --size;
ElementPtr* tmpptr = read_ptr;
read_ptr = tmpptr->next.load(std::memory_order_acquire);
@@ -77,6 +76,16 @@ public:
return true;
}
+ T PopWait() {
+ if (Empty()) {
+ std::unique_lock<std::mutex> lock(cv_mutex);
+ cv.wait(lock, [this]() { return !Empty(); });
+ }
+ T t;
+ Pop(t);
+ return t;
+ }
+
// not thread-safe
void Clear() {
size.store(0);
@@ -89,7 +98,7 @@ private:
// and a pointer to the next ElementPtr
class ElementPtr {
public:
- ElementPtr() : next(nullptr) {}
+ ElementPtr() {}
~ElementPtr() {
ElementPtr* next_ptr = next.load();
@@ -98,21 +107,23 @@ private:
}
T current;
- std::atomic<ElementPtr*> next;
+ std::atomic<ElementPtr*> next{nullptr};
};
ElementPtr* write_ptr;
ElementPtr* read_ptr;
- std::atomic<u32> size;
+ std::atomic_size_t size{0};
+ std::mutex cv_mutex;
+ std::condition_variable cv;
};
// a simple thread-safe,
// single reader, multiple writer queue
-template <typename T, bool NeedSize = true>
+template <typename T>
class MPSCQueue {
public:
- u32 Size() const {
+ std::size_t Size() const {
return spsc_queue.Size();
}
@@ -138,13 +149,17 @@ public:
return spsc_queue.Pop(t);
}
+ T PopWait() {
+ return spsc_queue.PopWait();
+ }
+
// not thread-safe
void Clear() {
spsc_queue.Clear();
}
private:
- SPSCQueue<T, NeedSize> spsc_queue;
+ SPSCQueue<T> spsc_queue;
std::mutex write_lock;
};
} // namespace Common
diff --git a/src/common/uint128.cpp b/src/common/uint128.cpp
new file mode 100644
index 000000000..32bf56730
--- /dev/null
+++ b/src/common/uint128.cpp
@@ -0,0 +1,45 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#ifdef _MSC_VER
+#include <intrin.h>
+
+#pragma intrinsic(_umul128)
+#endif
+#include <cstring>
+#include "common/uint128.h"
+
+namespace Common {
+
+u128 Multiply64Into128(u64 a, u64 b) {
+ u128 result;
+#ifdef _MSC_VER
+ result[0] = _umul128(a, b, &result[1]);
+#else
+ unsigned __int128 tmp = a;
+ tmp *= b;
+ std::memcpy(&result, &tmp, sizeof(u128));
+#endif
+ return result;
+}
+
+std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor) {
+ u64 remainder = dividend[0] % divisor;
+ u64 accum = dividend[0] / divisor;
+ if (dividend[1] == 0)
+ return {accum, remainder};
+ // We ignore dividend[1] / divisor as that overflows
+ const u64 first_segment = (dividend[1] % divisor) << 32;
+ accum += (first_segment / divisor) << 32;
+ const u64 second_segment = (first_segment % divisor) << 32;
+ accum += (second_segment / divisor);
+ remainder += second_segment % divisor;
+ if (remainder >= divisor) {
+ accum++;
+ remainder -= divisor;
+ }
+ return {accum, remainder};
+}
+
+} // namespace Common
diff --git a/src/common/uint128.h b/src/common/uint128.h
new file mode 100644
index 000000000..a3be2a2cb
--- /dev/null
+++ b/src/common/uint128.h
@@ -0,0 +1,19 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <utility>
+#include "common/common_types.h"
+
+namespace Common {
+
+// This function multiplies 2 u64 values and produces a u128 value;
+u128 Multiply64Into128(u64 a, u64 b);
+
+// This function divides a u128 by a u32 value and produces two u64 values:
+// the result of division and the remainder
+std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor);
+
+} // namespace Common
diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index 8feb49941..429485329 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -33,7 +33,7 @@
#include <cmath>
#include <type_traits>
-namespace Math {
+namespace Common {
template <typename T>
class Vec2;
@@ -690,4 +690,4 @@ constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
return MakeVec(x, yzw[0], yzw[1], yzw[2]);
}
-} // namespace Math
+} // namespace Common