diff options
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/CMakeLists.txt | 100 | ||||
| -rw-r--r-- | src/common/bit_field.h | 10 | ||||
| -rw-r--r-- | src/common/color.h | 40 | ||||
| -rw-r--r-- | src/common/common_paths.h | 1 | ||||
| -rw-r--r-- | src/common/file_util.cpp | 1 | ||||
| -rw-r--r-- | src/common/file_util.h | 1 | ||||
| -rw-r--r-- | src/common/logging/backend.cpp | 70 | ||||
| -rw-r--r-- | src/common/logging/backend.h | 5 | ||||
| -rw-r--r-- | src/common/logging/log.h | 1 | ||||
| -rw-r--r-- | src/common/math_util.h | 4 | ||||
| -rw-r--r-- | src/common/memory_hook.cpp | 11 | ||||
| -rw-r--r-- | src/common/memory_hook.h | 47 | ||||
| -rw-r--r-- | src/common/page_table.cpp | 29 | ||||
| -rw-r--r-- | src/common/page_table.h | 80 | ||||
| -rw-r--r-- | src/common/quaternion.h | 10 | ||||
| -rw-r--r-- | src/common/scm_rev.cpp.in | 2 | ||||
| -rw-r--r-- | src/common/scm_rev.h | 1 | ||||
| -rw-r--r-- | src/common/swap.h | 6 | ||||
| -rw-r--r-- | src/common/thread_queue_list.h | 6 | ||||
| -rw-r--r-- | src/common/threadsafe_queue.h | 53 | ||||
| -rw-r--r-- | src/common/uint128.cpp | 45 | ||||
| -rw-r--r-- | src/common/uint128.h | 19 | ||||
| -rw-r--r-- | src/common/vector_math.h | 4 |
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 @@ | |||
| 1 | # Generate cpp with Git revision from template | 1 | # Add a custom command to generate a new shader_cache_version hash when any of the following files change |
| 2 | # Also if this is a CI build, add the build name (ie: Nightly, Canary) to the scm_rev file as well | 2 | # NOTE: This is an approximation of what files affect shader generation, its possible something else |
| 3 | set(REPO_NAME "") | 3 | # could affect the result, but much more unlikely than the following files. Keeping a list of files |
| 4 | set(BUILD_VERSION "0") | 4 | # like this allows for much better caching since it doesn't force the user to recompile binary shaders every update |
| 5 | if ($ENV{CI}) | 5 | set(VIDEO_CORE "${CMAKE_SOURCE_DIR}/src/video_core") |
| 6 | if ($ENV{TRAVIS}) | 6 | if (DEFINED ENV{CI}) |
| 7 | if (DEFINED ENV{TRAVIS}) | ||
| 7 | set(BUILD_REPOSITORY $ENV{TRAVIS_REPO_SLUG}) | 8 | set(BUILD_REPOSITORY $ENV{TRAVIS_REPO_SLUG}) |
| 8 | set(BUILD_TAG $ENV{TRAVIS_TAG}) | 9 | set(BUILD_TAG $ENV{TRAVIS_TAG}) |
| 9 | elseif($ENV{APPVEYOR}) | 10 | elseif(DEFINED ENV{APPVEYOR}) |
| 10 | set(BUILD_REPOSITORY $ENV{APPVEYOR_REPO_NAME}) | 11 | set(BUILD_REPOSITORY $ENV{APPVEYOR_REPO_NAME}) |
| 11 | set(BUILD_TAG $ENV{APPVEYOR_REPO_TAG_NAME}) | 12 | set(BUILD_TAG $ENV{APPVEYOR_REPO_TAG_NAME}) |
| 12 | endif() | 13 | endif() |
| 13 | # regex capture the string nightly or canary into CMAKE_MATCH_1 | ||
| 14 | string(REGEX MATCH "yuzu-emu/yuzu-?(.*)" OUTVAR ${BUILD_REPOSITORY}) | ||
| 15 | if (${CMAKE_MATCH_COUNT} GREATER 0) | ||
| 16 | # capitalize the first letter of each word in the repo name. | ||
| 17 | string(REPLACE "-" ";" REPO_NAME_LIST ${CMAKE_MATCH_1}) | ||
| 18 | foreach(WORD ${REPO_NAME_LIST}) | ||
| 19 | string(SUBSTRING ${WORD} 0 1 FIRST_LETTER) | ||
| 20 | string(SUBSTRING ${WORD} 1 -1 REMAINDER) | ||
| 21 | string(TOUPPER ${FIRST_LETTER} FIRST_LETTER) | ||
| 22 | set(REPO_NAME "${REPO_NAME}${FIRST_LETTER}${REMAINDER}") | ||
| 23 | endforeach() | ||
| 24 | if (BUILD_TAG) | ||
| 25 | string(REGEX MATCH "${CMAKE_MATCH_1}-([0-9]+)" OUTVAR ${BUILD_TAG}) | ||
| 26 | if (${CMAKE_MATCH_COUNT} GREATER 0) | ||
| 27 | set(BUILD_VERSION ${CMAKE_MATCH_1}) | ||
| 28 | endif() | ||
| 29 | if (BUILD_VERSION) | ||
| 30 | # This leaves a trailing space on the last word, but we actually want that | ||
| 31 | # because of how it's styled in the title bar. | ||
| 32 | set(BUILD_FULLNAME "${REPO_NAME} ${BUILD_VERSION} ") | ||
| 33 | else() | ||
| 34 | set(BUILD_FULLNAME "") | ||
| 35 | endif() | ||
| 36 | endif() | ||
| 37 | endif() | ||
| 38 | endif() | 14 | endif() |
| 39 | configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp" @ONLY) | 15 | add_custom_command(OUTPUT scm_rev.cpp |
| 16 | COMMAND ${CMAKE_COMMAND} | ||
| 17 | -DSRC_DIR="${CMAKE_SOURCE_DIR}" | ||
| 18 | -DBUILD_REPOSITORY="${BUILD_REPOSITORY}" | ||
| 19 | -DBUILD_TAG="${BUILD_TAG}" | ||
| 20 | -P "${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake" | ||
| 21 | DEPENDS | ||
| 22 | # WARNING! It was too much work to try and make a common location for this list, | ||
| 23 | # so if you need to change it, please update CMakeModules/GenerateSCMRev.cmake as well | ||
| 24 | "${VIDEO_CORE}/renderer_opengl/gl_shader_cache.cpp" | ||
| 25 | "${VIDEO_CORE}/renderer_opengl/gl_shader_cache.h" | ||
| 26 | "${VIDEO_CORE}/renderer_opengl/gl_shader_decompiler.cpp" | ||
| 27 | "${VIDEO_CORE}/renderer_opengl/gl_shader_decompiler.h" | ||
| 28 | "${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.cpp" | ||
| 29 | "${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.h" | ||
| 30 | "${VIDEO_CORE}/renderer_opengl/gl_shader_gen.cpp" | ||
| 31 | "${VIDEO_CORE}/renderer_opengl/gl_shader_gen.h" | ||
| 32 | "${VIDEO_CORE}/shader/decode/arithmetic.cpp" | ||
| 33 | "${VIDEO_CORE}/shader/decode/arithmetic_half.cpp" | ||
| 34 | "${VIDEO_CORE}/shader/decode/arithmetic_half_immediate.cpp" | ||
| 35 | "${VIDEO_CORE}/shader/decode/arithmetic_immediate.cpp" | ||
| 36 | "${VIDEO_CORE}/shader/decode/arithmetic_integer.cpp" | ||
| 37 | "${VIDEO_CORE}/shader/decode/arithmetic_integer_immediate.cpp" | ||
| 38 | "${VIDEO_CORE}/shader/decode/bfe.cpp" | ||
| 39 | "${VIDEO_CORE}/shader/decode/bfi.cpp" | ||
| 40 | "${VIDEO_CORE}/shader/decode/conversion.cpp" | ||
| 41 | "${VIDEO_CORE}/shader/decode/ffma.cpp" | ||
| 42 | "${VIDEO_CORE}/shader/decode/float_set.cpp" | ||
| 43 | "${VIDEO_CORE}/shader/decode/float_set_predicate.cpp" | ||
| 44 | "${VIDEO_CORE}/shader/decode/half_set.cpp" | ||
| 45 | "${VIDEO_CORE}/shader/decode/half_set_predicate.cpp" | ||
| 46 | "${VIDEO_CORE}/shader/decode/hfma2.cpp" | ||
| 47 | "${VIDEO_CORE}/shader/decode/integer_set.cpp" | ||
| 48 | "${VIDEO_CORE}/shader/decode/integer_set_predicate.cpp" | ||
| 49 | "${VIDEO_CORE}/shader/decode/memory.cpp" | ||
| 50 | "${VIDEO_CORE}/shader/decode/texture.cpp" | ||
| 51 | "${VIDEO_CORE}/shader/decode/other.cpp" | ||
| 52 | "${VIDEO_CORE}/shader/decode/predicate_set_predicate.cpp" | ||
| 53 | "${VIDEO_CORE}/shader/decode/predicate_set_register.cpp" | ||
| 54 | "${VIDEO_CORE}/shader/decode/register_set_predicate.cpp" | ||
| 55 | "${VIDEO_CORE}/shader/decode/shift.cpp" | ||
| 56 | "${VIDEO_CORE}/shader/decode/video.cpp" | ||
| 57 | "${VIDEO_CORE}/shader/decode/xmad.cpp" | ||
| 58 | "${VIDEO_CORE}/shader/decode.cpp" | ||
| 59 | "${VIDEO_CORE}/shader/shader_ir.cpp" | ||
| 60 | "${VIDEO_CORE}/shader/shader_ir.h" | ||
| 61 | "${VIDEO_CORE}/shader/track.cpp" | ||
| 62 | # and also check that the scm_rev files haven't changed | ||
| 63 | "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" | ||
| 64 | "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.h" | ||
| 65 | # technically we should regenerate if the git version changed, but its not worth the effort imo | ||
| 66 | "${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake" | ||
| 67 | ) | ||
| 40 | 68 | ||
| 41 | add_library(common STATIC | 69 | add_library(common STATIC |
| 42 | alignment.h | 70 | alignment.h |
| @@ -64,10 +92,14 @@ add_library(common STATIC | |||
| 64 | logging/text_formatter.cpp | 92 | logging/text_formatter.cpp |
| 65 | logging/text_formatter.h | 93 | logging/text_formatter.h |
| 66 | math_util.h | 94 | math_util.h |
| 95 | memory_hook.cpp | ||
| 96 | memory_hook.h | ||
| 67 | microprofile.cpp | 97 | microprofile.cpp |
| 68 | microprofile.h | 98 | microprofile.h |
| 69 | microprofileui.h | 99 | microprofileui.h |
| 70 | misc.cpp | 100 | misc.cpp |
| 101 | page_table.cpp | ||
| 102 | page_table.h | ||
| 71 | param_package.cpp | 103 | param_package.cpp |
| 72 | param_package.h | 104 | param_package.h |
| 73 | quaternion.h | 105 | quaternion.h |
| @@ -86,6 +118,8 @@ add_library(common STATIC | |||
| 86 | threadsafe_queue.h | 118 | threadsafe_queue.h |
| 87 | timer.cpp | 119 | timer.cpp |
| 88 | timer.h | 120 | timer.h |
| 121 | uint128.cpp | ||
| 122 | uint128.h | ||
| 89 | vector_math.h | 123 | vector_math.h |
| 90 | web_result.h | 124 | web_result.h |
| 91 | ) | 125 | ) |
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: | |||
| 162 | BitField(T val) = delete; | 162 | BitField(T val) = delete; |
| 163 | BitField& operator=(T val) = delete; | 163 | BitField& operator=(T val) = delete; |
| 164 | 164 | ||
| 165 | // Force default constructor to be created | 165 | constexpr BitField() noexcept = default; |
| 166 | // so that we can use this within unions | 166 | |
| 167 | constexpr BitField() = default; | 167 | constexpr BitField(const BitField&) noexcept = default; |
| 168 | constexpr BitField& operator=(const BitField&) noexcept = default; | ||
| 169 | |||
| 170 | constexpr BitField(BitField&&) noexcept = default; | ||
| 171 | constexpr BitField& operator=(BitField&&) noexcept = default; | ||
| 168 | 172 | ||
| 169 | constexpr FORCE_INLINE operator T() const { | 173 | constexpr FORCE_INLINE operator T() const { |
| 170 | return Value(); | 174 | 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) { | |||
| 55 | /** | 55 | /** |
| 56 | * Decode a color stored in RGBA8 format | 56 | * Decode a color stored in RGBA8 format |
| 57 | * @param bytes Pointer to encoded source color | 57 | * @param bytes Pointer to encoded source color |
| 58 | * @return Result color decoded as Math::Vec4<u8> | 58 | * @return Result color decoded as Common::Vec4<u8> |
| 59 | */ | 59 | */ |
| 60 | inline Math::Vec4<u8> DecodeRGBA8(const u8* bytes) { | 60 | inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) { |
| 61 | return {bytes[3], bytes[2], bytes[1], bytes[0]}; | 61 | return {bytes[3], bytes[2], bytes[1], bytes[0]}; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | /** | 64 | /** |
| 65 | * Decode a color stored in RGB8 format | 65 | * Decode a color stored in RGB8 format |
| 66 | * @param bytes Pointer to encoded source color | 66 | * @param bytes Pointer to encoded source color |
| 67 | * @return Result color decoded as Math::Vec4<u8> | 67 | * @return Result color decoded as Common::Vec4<u8> |
| 68 | */ | 68 | */ |
| 69 | inline Math::Vec4<u8> DecodeRGB8(const u8* bytes) { | 69 | inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) { |
| 70 | return {bytes[2], bytes[1], bytes[0], 255}; | 70 | return {bytes[2], bytes[1], bytes[0], 255}; |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | /** | 73 | /** |
| 74 | * Decode a color stored in RG8 (aka HILO8) format | 74 | * Decode a color stored in RG8 (aka HILO8) format |
| 75 | * @param bytes Pointer to encoded source color | 75 | * @param bytes Pointer to encoded source color |
| 76 | * @return Result color decoded as Math::Vec4<u8> | 76 | * @return Result color decoded as Common::Vec4<u8> |
| 77 | */ | 77 | */ |
| 78 | inline Math::Vec4<u8> DecodeRG8(const u8* bytes) { | 78 | inline Common::Vec4<u8> DecodeRG8(const u8* bytes) { |
| 79 | return {bytes[1], bytes[0], 0, 255}; | 79 | return {bytes[1], bytes[0], 0, 255}; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | /** | 82 | /** |
| 83 | * Decode a color stored in RGB565 format | 83 | * Decode a color stored in RGB565 format |
| 84 | * @param bytes Pointer to encoded source color | 84 | * @param bytes Pointer to encoded source color |
| 85 | * @return Result color decoded as Math::Vec4<u8> | 85 | * @return Result color decoded as Common::Vec4<u8> |
| 86 | */ | 86 | */ |
| 87 | inline Math::Vec4<u8> DecodeRGB565(const u8* bytes) { | 87 | inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) { |
| 88 | u16_le pixel; | 88 | u16_le pixel; |
| 89 | std::memcpy(&pixel, bytes, sizeof(pixel)); | 89 | std::memcpy(&pixel, bytes, sizeof(pixel)); |
| 90 | return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F), | 90 | return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F), |
| @@ -94,9 +94,9 @@ inline Math::Vec4<u8> DecodeRGB565(const u8* bytes) { | |||
| 94 | /** | 94 | /** |
| 95 | * Decode a color stored in RGB5A1 format | 95 | * Decode a color stored in RGB5A1 format |
| 96 | * @param bytes Pointer to encoded source color | 96 | * @param bytes Pointer to encoded source color |
| 97 | * @return Result color decoded as Math::Vec4<u8> | 97 | * @return Result color decoded as Common::Vec4<u8> |
| 98 | */ | 98 | */ |
| 99 | inline Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) { | 99 | inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) { |
| 100 | u16_le pixel; | 100 | u16_le pixel; |
| 101 | std::memcpy(&pixel, bytes, sizeof(pixel)); | 101 | std::memcpy(&pixel, bytes, sizeof(pixel)); |
| 102 | return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F), | 102 | return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F), |
| @@ -106,9 +106,9 @@ inline Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) { | |||
| 106 | /** | 106 | /** |
| 107 | * Decode a color stored in RGBA4 format | 107 | * Decode a color stored in RGBA4 format |
| 108 | * @param bytes Pointer to encoded source color | 108 | * @param bytes Pointer to encoded source color |
| 109 | * @return Result color decoded as Math::Vec4<u8> | 109 | * @return Result color decoded as Common::Vec4<u8> |
| 110 | */ | 110 | */ |
| 111 | inline Math::Vec4<u8> DecodeRGBA4(const u8* bytes) { | 111 | inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) { |
| 112 | u16_le pixel; | 112 | u16_le pixel; |
| 113 | std::memcpy(&pixel, bytes, sizeof(pixel)); | 113 | std::memcpy(&pixel, bytes, sizeof(pixel)); |
| 114 | return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF), | 114 | return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF), |
| @@ -138,9 +138,9 @@ inline u32 DecodeD24(const u8* bytes) { | |||
| 138 | /** | 138 | /** |
| 139 | * Decode a depth value and a stencil value stored in D24S8 format | 139 | * Decode a depth value and a stencil value stored in D24S8 format |
| 140 | * @param bytes Pointer to encoded source values | 140 | * @param bytes Pointer to encoded source values |
| 141 | * @return Resulting values stored as a Math::Vec2 | 141 | * @return Resulting values stored as a Common::Vec2 |
| 142 | */ | 142 | */ |
| 143 | inline Math::Vec2<u32> DecodeD24S8(const u8* bytes) { | 143 | inline Common::Vec2<u32> DecodeD24S8(const u8* bytes) { |
| 144 | return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]}; | 144 | return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]}; |
| 145 | } | 145 | } |
| 146 | 146 | ||
| @@ -149,7 +149,7 @@ inline Math::Vec2<u32> DecodeD24S8(const u8* bytes) { | |||
| 149 | * @param color Source color to encode | 149 | * @param color Source color to encode |
| 150 | * @param bytes Destination pointer to store encoded color | 150 | * @param bytes Destination pointer to store encoded color |
| 151 | */ | 151 | */ |
| 152 | inline void EncodeRGBA8(const Math::Vec4<u8>& color, u8* bytes) { | 152 | inline void EncodeRGBA8(const Common::Vec4<u8>& color, u8* bytes) { |
| 153 | bytes[3] = color.r(); | 153 | bytes[3] = color.r(); |
| 154 | bytes[2] = color.g(); | 154 | bytes[2] = color.g(); |
| 155 | bytes[1] = color.b(); | 155 | bytes[1] = color.b(); |
| @@ -161,7 +161,7 @@ inline void EncodeRGBA8(const Math::Vec4<u8>& color, u8* bytes) { | |||
| 161 | * @param color Source color to encode | 161 | * @param color Source color to encode |
| 162 | * @param bytes Destination pointer to store encoded color | 162 | * @param bytes Destination pointer to store encoded color |
| 163 | */ | 163 | */ |
| 164 | inline void EncodeRGB8(const Math::Vec4<u8>& color, u8* bytes) { | 164 | inline void EncodeRGB8(const Common::Vec4<u8>& color, u8* bytes) { |
| 165 | bytes[2] = color.r(); | 165 | bytes[2] = color.r(); |
| 166 | bytes[1] = color.g(); | 166 | bytes[1] = color.g(); |
| 167 | bytes[0] = color.b(); | 167 | bytes[0] = color.b(); |
| @@ -172,7 +172,7 @@ inline void EncodeRGB8(const Math::Vec4<u8>& color, u8* bytes) { | |||
| 172 | * @param color Source color to encode | 172 | * @param color Source color to encode |
| 173 | * @param bytes Destination pointer to store encoded color | 173 | * @param bytes Destination pointer to store encoded color |
| 174 | */ | 174 | */ |
| 175 | inline void EncodeRG8(const Math::Vec4<u8>& color, u8* bytes) { | 175 | inline void EncodeRG8(const Common::Vec4<u8>& color, u8* bytes) { |
| 176 | bytes[1] = color.r(); | 176 | bytes[1] = color.r(); |
| 177 | bytes[0] = color.g(); | 177 | bytes[0] = color.g(); |
| 178 | } | 178 | } |
| @@ -181,7 +181,7 @@ inline void EncodeRG8(const Math::Vec4<u8>& color, u8* bytes) { | |||
| 181 | * @param color Source color to encode | 181 | * @param color Source color to encode |
| 182 | * @param bytes Destination pointer to store encoded color | 182 | * @param bytes Destination pointer to store encoded color |
| 183 | */ | 183 | */ |
| 184 | inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) { | 184 | inline void EncodeRGB565(const Common::Vec4<u8>& color, u8* bytes) { |
| 185 | const u16_le data = | 185 | const u16_le data = |
| 186 | (Convert8To5(color.r()) << 11) | (Convert8To6(color.g()) << 5) | Convert8To5(color.b()); | 186 | (Convert8To5(color.r()) << 11) | (Convert8To6(color.g()) << 5) | Convert8To5(color.b()); |
| 187 | 187 | ||
| @@ -193,7 +193,7 @@ inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) { | |||
| 193 | * @param color Source color to encode | 193 | * @param color Source color to encode |
| 194 | * @param bytes Destination pointer to store encoded color | 194 | * @param bytes Destination pointer to store encoded color |
| 195 | */ | 195 | */ |
| 196 | inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) { | 196 | inline void EncodeRGB5A1(const Common::Vec4<u8>& color, u8* bytes) { |
| 197 | const u16_le data = (Convert8To5(color.r()) << 11) | (Convert8To5(color.g()) << 6) | | 197 | const u16_le data = (Convert8To5(color.r()) << 11) | (Convert8To5(color.g()) << 6) | |
| 198 | (Convert8To5(color.b()) << 1) | Convert8To1(color.a()); | 198 | (Convert8To5(color.b()) << 1) | Convert8To1(color.a()); |
| 199 | 199 | ||
| @@ -205,7 +205,7 @@ inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) { | |||
| 205 | * @param color Source color to encode | 205 | * @param color Source color to encode |
| 206 | * @param bytes Destination pointer to store encoded color | 206 | * @param bytes Destination pointer to store encoded color |
| 207 | */ | 207 | */ |
| 208 | inline void EncodeRGBA4(const Math::Vec4<u8>& color, u8* bytes) { | 208 | inline void EncodeRGBA4(const Common::Vec4<u8>& color, u8* bytes) { |
| 209 | const u16 data = (Convert8To4(color.r()) << 12) | (Convert8To4(color.g()) << 8) | | 209 | const u16 data = (Convert8To4(color.r()) << 12) | (Convert8To4(color.g()) << 8) | |
| 210 | (Convert8To4(color.b()) << 4) | Convert8To4(color.a()); | 210 | (Convert8To4(color.b()) << 4) | Convert8To4(color.a()); |
| 211 | 211 | ||
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 @@ | |||
| 35 | #define KEYS_DIR "keys" | 35 | #define KEYS_DIR "keys" |
| 36 | #define LOAD_DIR "load" | 36 | #define LOAD_DIR "load" |
| 37 | #define DUMP_DIR "dump" | 37 | #define DUMP_DIR "dump" |
| 38 | #define SHADER_DIR "shader" | ||
| 38 | #define LOG_DIR "log" | 39 | #define LOG_DIR "log" |
| 39 | 40 | ||
| 40 | // Filenames | 41 | // 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) { | |||
| 710 | paths.emplace(UserPath::NANDDir, user_path + NAND_DIR DIR_SEP); | 710 | paths.emplace(UserPath::NANDDir, user_path + NAND_DIR DIR_SEP); |
| 711 | paths.emplace(UserPath::LoadDir, user_path + LOAD_DIR DIR_SEP); | 711 | paths.emplace(UserPath::LoadDir, user_path + LOAD_DIR DIR_SEP); |
| 712 | paths.emplace(UserPath::DumpDir, user_path + DUMP_DIR DIR_SEP); | 712 | paths.emplace(UserPath::DumpDir, user_path + DUMP_DIR DIR_SEP); |
| 713 | paths.emplace(UserPath::ShaderDir, user_path + SHADER_DIR DIR_SEP); | ||
| 713 | paths.emplace(UserPath::SysDataDir, user_path + SYSDATA_DIR DIR_SEP); | 714 | paths.emplace(UserPath::SysDataDir, user_path + SYSDATA_DIR DIR_SEP); |
| 714 | paths.emplace(UserPath::KeysDir, user_path + KEYS_DIR DIR_SEP); | 715 | paths.emplace(UserPath::KeysDir, user_path + KEYS_DIR DIR_SEP); |
| 715 | // TODO: Put the logs in a better location for each OS | 716 | // 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 { | |||
| 31 | SDMCDir, | 31 | SDMCDir, |
| 32 | LoadDir, | 32 | LoadDir, |
| 33 | DumpDir, | 33 | DumpDir, |
| 34 | ShaderDir, | ||
| 34 | SysDataDir, | 35 | SysDataDir, |
| 35 | UserDir, | 36 | UserDir, |
| 36 | }; | 37 | }; |
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: | |||
| 39 | Impl(Impl const&) = delete; | 39 | Impl(Impl const&) = delete; |
| 40 | const Impl& operator=(Impl const&) = delete; | 40 | const Impl& operator=(Impl const&) = delete; |
| 41 | 41 | ||
| 42 | void PushEntry(Entry e) { | 42 | void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num, |
| 43 | std::lock_guard<std::mutex> lock(message_mutex); | 43 | const char* function, std::string message) { |
| 44 | message_queue.Push(std::move(e)); | 44 | message_queue.Push( |
| 45 | message_cv.notify_one(); | 45 | CreateEntry(log_class, log_level, filename, line_num, function, std::move(message))); |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | void AddBackend(std::unique_ptr<Backend> backend) { | 48 | void AddBackend(std::unique_ptr<Backend> backend) { |
| @@ -86,15 +86,13 @@ private: | |||
| 86 | } | 86 | } |
| 87 | }; | 87 | }; |
| 88 | while (true) { | 88 | while (true) { |
| 89 | { | 89 | entry = message_queue.PopWait(); |
| 90 | std::unique_lock<std::mutex> lock(message_mutex); | 90 | if (entry.final_entry) { |
| 91 | message_cv.wait(lock, [&] { return !running || message_queue.Pop(entry); }); | ||
| 92 | } | ||
| 93 | if (!running) { | ||
| 94 | break; | 91 | break; |
| 95 | } | 92 | } |
| 96 | write_logs(entry); | 93 | write_logs(entry); |
| 97 | } | 94 | } |
| 95 | |||
| 98 | // Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a case | 96 | // Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a case |
| 99 | // where a system is repeatedly spamming logs even on close. | 97 | // where a system is repeatedly spamming logs even on close. |
| 100 | const int MAX_LOGS_TO_WRITE = filter.IsDebug() ? INT_MAX : 100; | 98 | const int MAX_LOGS_TO_WRITE = filter.IsDebug() ? INT_MAX : 100; |
| @@ -106,18 +104,36 @@ private: | |||
| 106 | } | 104 | } |
| 107 | 105 | ||
| 108 | ~Impl() { | 106 | ~Impl() { |
| 109 | running = false; | 107 | Entry entry; |
| 110 | message_cv.notify_one(); | 108 | entry.final_entry = true; |
| 109 | message_queue.Push(entry); | ||
| 111 | backend_thread.join(); | 110 | backend_thread.join(); |
| 112 | } | 111 | } |
| 113 | 112 | ||
| 114 | std::atomic_bool running{true}; | 113 | Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, |
| 115 | std::mutex message_mutex, writing_mutex; | 114 | const char* function, std::string message) const { |
| 116 | std::condition_variable message_cv; | 115 | using std::chrono::duration_cast; |
| 116 | using std::chrono::steady_clock; | ||
| 117 | |||
| 118 | Entry entry; | ||
| 119 | entry.timestamp = | ||
| 120 | duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin); | ||
| 121 | entry.log_class = log_class; | ||
| 122 | entry.log_level = log_level; | ||
| 123 | entry.filename = Common::TrimSourcePath(filename); | ||
| 124 | entry.line_num = line_nr; | ||
| 125 | entry.function = function; | ||
| 126 | entry.message = std::move(message); | ||
| 127 | |||
| 128 | return entry; | ||
| 129 | } | ||
| 130 | |||
| 131 | std::mutex writing_mutex; | ||
| 117 | std::thread backend_thread; | 132 | std::thread backend_thread; |
| 118 | std::vector<std::unique_ptr<Backend>> backends; | 133 | std::vector<std::unique_ptr<Backend>> backends; |
| 119 | Common::MPSCQueue<Log::Entry> message_queue; | 134 | Common::MPSCQueue<Log::Entry> message_queue; |
| 120 | Filter filter; | 135 | Filter filter; |
| 136 | std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()}; | ||
| 121 | }; | 137 | }; |
| 122 | 138 | ||
| 123 | void ConsoleBackend::Write(const Entry& entry) { | 139 | void ConsoleBackend::Write(const Entry& entry) { |
| @@ -232,6 +248,7 @@ void DebuggerBackend::Write(const Entry& entry) { | |||
| 232 | CLS(Render) \ | 248 | CLS(Render) \ |
| 233 | SUB(Render, Software) \ | 249 | SUB(Render, Software) \ |
| 234 | SUB(Render, OpenGL) \ | 250 | SUB(Render, OpenGL) \ |
| 251 | SUB(Render, Vulkan) \ | ||
| 235 | CLS(Audio) \ | 252 | CLS(Audio) \ |
| 236 | SUB(Audio, DSP) \ | 253 | SUB(Audio, DSP) \ |
| 237 | SUB(Audio, Sink) \ | 254 | SUB(Audio, Sink) \ |
| @@ -275,25 +292,6 @@ const char* GetLevelName(Level log_level) { | |||
| 275 | #undef LVL | 292 | #undef LVL |
| 276 | } | 293 | } |
| 277 | 294 | ||
| 278 | Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, | ||
| 279 | const char* function, std::string message) { | ||
| 280 | using std::chrono::duration_cast; | ||
| 281 | using std::chrono::steady_clock; | ||
| 282 | |||
| 283 | static steady_clock::time_point time_origin = steady_clock::now(); | ||
| 284 | |||
| 285 | Entry entry; | ||
| 286 | entry.timestamp = duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin); | ||
| 287 | entry.log_class = log_class; | ||
| 288 | entry.log_level = log_level; | ||
| 289 | entry.filename = Common::TrimSourcePath(filename); | ||
| 290 | entry.line_num = line_nr; | ||
| 291 | entry.function = function; | ||
| 292 | entry.message = std::move(message); | ||
| 293 | |||
| 294 | return entry; | ||
| 295 | } | ||
| 296 | |||
| 297 | void SetGlobalFilter(const Filter& filter) { | 295 | void SetGlobalFilter(const Filter& filter) { |
| 298 | Impl::Instance().SetGlobalFilter(filter); | 296 | Impl::Instance().SetGlobalFilter(filter); |
| 299 | } | 297 | } |
| @@ -318,9 +316,7 @@ void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, | |||
| 318 | if (!filter.CheckMessage(log_class, log_level)) | 316 | if (!filter.CheckMessage(log_class, log_level)) |
| 319 | return; | 317 | return; |
| 320 | 318 | ||
| 321 | Entry entry = | 319 | instance.PushEntry(log_class, log_level, filename, line_num, function, |
| 322 | CreateEntry(log_class, log_level, filename, line_num, function, fmt::vformat(format, args)); | 320 | fmt::vformat(format, args)); |
| 323 | |||
| 324 | instance.PushEntry(std::move(entry)); | ||
| 325 | } | 321 | } |
| 326 | } // namespace Log | 322 | } // 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 { | |||
| 27 | unsigned int line_num; | 27 | unsigned int line_num; |
| 28 | std::string function; | 28 | std::string function; |
| 29 | std::string message; | 29 | std::string message; |
| 30 | bool final_entry = false; | ||
| 30 | 31 | ||
| 31 | Entry() = default; | 32 | Entry() = default; |
| 32 | Entry(Entry&& o) = default; | 33 | Entry(Entry&& o) = default; |
| @@ -134,10 +135,6 @@ const char* GetLogClassName(Class log_class); | |||
| 134 | */ | 135 | */ |
| 135 | const char* GetLevelName(Level log_level); | 136 | const char* GetLevelName(Level log_level); |
| 136 | 137 | ||
| 137 | /// Creates a log entry by formatting the given source location, and message. | ||
| 138 | Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, | ||
| 139 | const char* function, std::string message); | ||
| 140 | |||
| 141 | /** | 138 | /** |
| 142 | * The global filter will prevent any messages from even being processed if they are filtered. Each | 139 | * The global filter will prevent any messages from even being processed if they are filtered. Each |
| 143 | * backend can have a filter, but if the level is lower than the global filter, the backend will | 140 | * 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 { | |||
| 112 | Render, ///< Emulator video output and hardware acceleration | 112 | Render, ///< Emulator video output and hardware acceleration |
| 113 | Render_Software, ///< Software renderer backend | 113 | Render_Software, ///< Software renderer backend |
| 114 | Render_OpenGL, ///< OpenGL backend | 114 | Render_OpenGL, ///< OpenGL backend |
| 115 | Render_Vulkan, ///< Vulkan backend | ||
| 115 | Audio, ///< Audio emulation | 116 | Audio, ///< Audio emulation |
| 116 | Audio_DSP, ///< The HLE implementation of the DSP | 117 | Audio_DSP, ///< The HLE implementation of the DSP |
| 117 | Audio_Sink, ///< Emulator audio output backend | 118 | 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 @@ | |||
| 7 | #include <cstdlib> | 7 | #include <cstdlib> |
| 8 | #include <type_traits> | 8 | #include <type_traits> |
| 9 | 9 | ||
| 10 | namespace MathUtil { | 10 | namespace Common { |
| 11 | 11 | ||
| 12 | constexpr float PI = 3.14159265f; | 12 | constexpr float PI = 3.14159265f; |
| 13 | 13 | ||
| @@ -41,4 +41,4 @@ struct Rectangle { | |||
| 41 | } | 41 | } |
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | } // namespace MathUtil | 44 | } // 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 @@ | |||
| 1 | // Copyright 2018 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/memory_hook.h" | ||
| 6 | |||
| 7 | namespace Common { | ||
| 8 | |||
| 9 | MemoryHook::~MemoryHook() = default; | ||
| 10 | |||
| 11 | } // 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 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <optional> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | |||
| 12 | namespace Common { | ||
| 13 | |||
| 14 | /** | ||
| 15 | * Memory hooks have two purposes: | ||
| 16 | * 1. To allow reads and writes to a region of memory to be intercepted. This is used to implement | ||
| 17 | * texture forwarding and memory breakpoints for debugging. | ||
| 18 | * 2. To allow for the implementation of MMIO devices. | ||
| 19 | * | ||
| 20 | * A hook may be mapped to multiple regions of memory. | ||
| 21 | * | ||
| 22 | * If a std::nullopt or false is returned from a function, the read/write request is passed through | ||
| 23 | * to the underlying memory region. | ||
| 24 | */ | ||
| 25 | class MemoryHook { | ||
| 26 | public: | ||
| 27 | virtual ~MemoryHook(); | ||
| 28 | |||
| 29 | virtual std::optional<bool> IsValidAddress(VAddr addr) = 0; | ||
| 30 | |||
| 31 | virtual std::optional<u8> Read8(VAddr addr) = 0; | ||
| 32 | virtual std::optional<u16> Read16(VAddr addr) = 0; | ||
| 33 | virtual std::optional<u32> Read32(VAddr addr) = 0; | ||
| 34 | virtual std::optional<u64> Read64(VAddr addr) = 0; | ||
| 35 | |||
| 36 | virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) = 0; | ||
| 37 | |||
| 38 | virtual bool Write8(VAddr addr, u8 data) = 0; | ||
| 39 | virtual bool Write16(VAddr addr, u16 data) = 0; | ||
| 40 | virtual bool Write32(VAddr addr, u32 data) = 0; | ||
| 41 | virtual bool Write64(VAddr addr, u64 data) = 0; | ||
| 42 | |||
| 43 | virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size) = 0; | ||
| 44 | }; | ||
| 45 | |||
| 46 | using MemoryHookPointer = std::shared_ptr<MemoryHook>; | ||
| 47 | } // 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 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/page_table.h" | ||
| 6 | |||
| 7 | namespace Common { | ||
| 8 | |||
| 9 | PageTable::PageTable(std::size_t page_size_in_bits) : page_size_in_bits{page_size_in_bits} {} | ||
| 10 | |||
| 11 | PageTable::~PageTable() = default; | ||
| 12 | |||
| 13 | void PageTable::Resize(std::size_t address_space_width_in_bits) { | ||
| 14 | const std::size_t num_page_table_entries = 1ULL | ||
| 15 | << (address_space_width_in_bits - page_size_in_bits); | ||
| 16 | |||
| 17 | pointers.resize(num_page_table_entries); | ||
| 18 | attributes.resize(num_page_table_entries); | ||
| 19 | |||
| 20 | // The default is a 39-bit address space, which causes an initial 1GB allocation size. If the | ||
| 21 | // vector size is subsequently decreased (via resize), the vector might not automatically | ||
| 22 | // actually reallocate/resize its underlying allocation, which wastes up to ~800 MB for | ||
| 23 | // 36-bit titles. Call shrink_to_fit to reduce capacity to what's actually in use. | ||
| 24 | |||
| 25 | pointers.shrink_to_fit(); | ||
| 26 | attributes.shrink_to_fit(); | ||
| 27 | } | ||
| 28 | |||
| 29 | } // 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 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vector> | ||
| 8 | #include <boost/icl/interval_map.hpp> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/memory_hook.h" | ||
| 11 | |||
| 12 | namespace Common { | ||
| 13 | |||
| 14 | enum class PageType : u8 { | ||
| 15 | /// Page is unmapped and should cause an access error. | ||
| 16 | Unmapped, | ||
| 17 | /// Page is mapped to regular memory. This is the only type you can get pointers to. | ||
| 18 | Memory, | ||
| 19 | /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and | ||
| 20 | /// invalidation | ||
| 21 | RasterizerCachedMemory, | ||
| 22 | /// Page is mapped to a I/O region. Writing and reading to this page is handled by functions. | ||
| 23 | Special, | ||
| 24 | }; | ||
| 25 | |||
| 26 | struct SpecialRegion { | ||
| 27 | enum class Type { | ||
| 28 | DebugHook, | ||
| 29 | IODevice, | ||
| 30 | } type; | ||
| 31 | |||
| 32 | MemoryHookPointer handler; | ||
| 33 | |||
| 34 | bool operator<(const SpecialRegion& other) const { | ||
| 35 | return std::tie(type, handler) < std::tie(other.type, other.handler); | ||
| 36 | } | ||
| 37 | |||
| 38 | bool operator==(const SpecialRegion& other) const { | ||
| 39 | return std::tie(type, handler) == std::tie(other.type, other.handler); | ||
| 40 | } | ||
| 41 | }; | ||
| 42 | |||
| 43 | /** | ||
| 44 | * A (reasonably) fast way of allowing switchable and remappable process address spaces. It loosely | ||
| 45 | * mimics the way a real CPU page table works. | ||
| 46 | */ | ||
| 47 | struct PageTable { | ||
| 48 | explicit PageTable(std::size_t page_size_in_bits); | ||
| 49 | ~PageTable(); | ||
| 50 | |||
| 51 | /** | ||
| 52 | * Resizes the page table to be able to accomodate enough pages within | ||
| 53 | * a given address space. | ||
| 54 | * | ||
| 55 | * @param address_space_width_in_bits The address size width in bits. | ||
| 56 | */ | ||
| 57 | void Resize(std::size_t address_space_width_in_bits); | ||
| 58 | |||
| 59 | /** | ||
| 60 | * Vector of memory pointers backing each page. An entry can only be non-null if the | ||
| 61 | * corresponding entry in the `attributes` vector is of type `Memory`. | ||
| 62 | */ | ||
| 63 | std::vector<u8*> pointers; | ||
| 64 | |||
| 65 | /** | ||
| 66 | * Contains MMIO handlers that back memory regions whose entries in the `attribute` vector is | ||
| 67 | * of type `Special`. | ||
| 68 | */ | ||
| 69 | boost::icl::interval_map<VAddr, std::set<SpecialRegion>> special_regions; | ||
| 70 | |||
| 71 | /** | ||
| 72 | * Vector of fine grained page attributes. If it is set to any value other than `Memory`, then | ||
| 73 | * the corresponding entry in `pointers` MUST be set to null. | ||
| 74 | */ | ||
| 75 | std::vector<PageType> attributes; | ||
| 76 | |||
| 77 | const std::size_t page_size_in_bits{}; | ||
| 78 | }; | ||
| 79 | |||
| 80 | } // 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 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/vector_math.h" | 7 | #include "common/vector_math.h" |
| 8 | 8 | ||
| 9 | namespace Math { | 9 | namespace Common { |
| 10 | 10 | ||
| 11 | template <typename T> | 11 | template <typename T> |
| 12 | class Quaternion { | 12 | class Quaternion { |
| 13 | public: | 13 | public: |
| 14 | Math::Vec3<T> xyz; | 14 | Vec3<T> xyz; |
| 15 | T w{}; | 15 | T w{}; |
| 16 | 16 | ||
| 17 | Quaternion<decltype(-T{})> Inverse() const { | 17 | Quaternion<decltype(-T{})> Inverse() const { |
| @@ -38,12 +38,12 @@ public: | |||
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | template <typename T> | 40 | template <typename T> |
| 41 | auto QuaternionRotate(const Quaternion<T>& q, const Math::Vec3<T>& v) { | 41 | auto QuaternionRotate(const Quaternion<T>& q, const Vec3<T>& v) { |
| 42 | return v + 2 * Cross(q.xyz, Cross(q.xyz, v) + v * q.w); | 42 | return v + 2 * Cross(q.xyz, Cross(q.xyz, v) + v * q.w); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | inline Quaternion<float> MakeQuaternion(const Math::Vec3<float>& axis, float angle) { | 45 | inline Quaternion<float> MakeQuaternion(const Vec3<float>& axis, float angle) { |
| 46 | return {axis * std::sin(angle / 2), std::cos(angle / 2)}; | 46 | return {axis * std::sin(angle / 2), std::cos(angle / 2)}; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | } // namespace Math | 49 | } // 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 @@ | |||
| 11 | #define BUILD_DATE "@BUILD_DATE@" | 11 | #define BUILD_DATE "@BUILD_DATE@" |
| 12 | #define BUILD_FULLNAME "@BUILD_FULLNAME@" | 12 | #define BUILD_FULLNAME "@BUILD_FULLNAME@" |
| 13 | #define BUILD_VERSION "@BUILD_VERSION@" | 13 | #define BUILD_VERSION "@BUILD_VERSION@" |
| 14 | #define SHADER_CACHE_VERSION "@SHADER_CACHE_VERSION@" | ||
| 14 | 15 | ||
| 15 | namespace Common { | 16 | namespace Common { |
| 16 | 17 | ||
| @@ -21,6 +22,7 @@ const char g_build_name[] = BUILD_NAME; | |||
| 21 | const char g_build_date[] = BUILD_DATE; | 22 | const char g_build_date[] = BUILD_DATE; |
| 22 | const char g_build_fullname[] = BUILD_FULLNAME; | 23 | const char g_build_fullname[] = BUILD_FULLNAME; |
| 23 | const char g_build_version[] = BUILD_VERSION; | 24 | const char g_build_version[] = BUILD_VERSION; |
| 25 | const char g_shader_cache_version[] = SHADER_CACHE_VERSION; | ||
| 24 | 26 | ||
| 25 | } // namespace | 27 | } // namespace |
| 26 | 28 | ||
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[]; | |||
| 13 | extern const char g_build_date[]; | 13 | extern const char g_build_date[]; |
| 14 | extern const char g_build_fullname[]; | 14 | extern const char g_build_fullname[]; |
| 15 | extern const char g_build_version[]; | 15 | extern const char g_build_version[]; |
| 16 | extern const char g_shader_cache_version[]; | ||
| 16 | 17 | ||
| 17 | } // namespace Common | 18 | } // 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 @@ | |||
| 30 | #include <cstring> | 30 | #include <cstring> |
| 31 | #include "common/common_types.h" | 31 | #include "common/common_types.h" |
| 32 | 32 | ||
| 33 | // GCC 4.6+ | 33 | // GCC |
| 34 | #if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | 34 | #ifdef __GNUC__ |
| 35 | 35 | ||
| 36 | #if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && !defined(COMMON_LITTLE_ENDIAN) | 36 | #if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && !defined(COMMON_LITTLE_ENDIAN) |
| 37 | #define COMMON_LITTLE_ENDIAN 1 | 37 | #define COMMON_LITTLE_ENDIAN 1 |
| @@ -40,7 +40,7 @@ | |||
| 40 | #endif | 40 | #endif |
| 41 | 41 | ||
| 42 | // LLVM/clang | 42 | // LLVM/clang |
| 43 | #elif __clang__ | 43 | #elif defined(__clang__) |
| 44 | 44 | ||
| 45 | #if __LITTLE_ENDIAN__ && !defined(COMMON_LITTLE_ENDIAN) | 45 | #if __LITTLE_ENDIAN__ && !defined(COMMON_LITTLE_ENDIAN) |
| 46 | #define COMMON_LITTLE_ENDIAN 1 | 46 | #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 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <deque> | 8 | #include <deque> |
| 9 | #include <boost/range/algorithm_ext/erase.hpp> | ||
| 10 | 9 | ||
| 11 | namespace Common { | 10 | namespace Common { |
| 12 | 11 | ||
| @@ -111,8 +110,9 @@ struct ThreadQueueList { | |||
| 111 | } | 110 | } |
| 112 | 111 | ||
| 113 | void remove(Priority priority, const T& thread_id) { | 112 | void remove(Priority priority, const T& thread_id) { |
| 114 | Queue* cur = &queues[priority]; | 113 | Queue* const cur = &queues[priority]; |
| 115 | boost::remove_erase(cur->data, thread_id); | 114 | const auto iter = std::remove(cur->data.begin(), cur->data.end(), thread_id); |
| 115 | cur->data.erase(iter, cur->data.end()); | ||
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | void rotate(Priority priority) { | 118 | 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 @@ | |||
| 7 | // a simple lockless thread-safe, | 7 | // a simple lockless thread-safe, |
| 8 | // single reader, single writer queue | 8 | // single reader, single writer queue |
| 9 | 9 | ||
| 10 | #include <algorithm> | ||
| 11 | #include <atomic> | 10 | #include <atomic> |
| 11 | #include <condition_variable> | ||
| 12 | #include <cstddef> | 12 | #include <cstddef> |
| 13 | #include <mutex> | 13 | #include <mutex> |
| 14 | #include "common/common_types.h" | 14 | #include <utility> |
| 15 | 15 | ||
| 16 | namespace Common { | 16 | namespace Common { |
| 17 | template <typename T, bool NeedSize = true> | 17 | template <typename T> |
| 18 | class SPSCQueue { | 18 | class SPSCQueue { |
| 19 | public: | 19 | public: |
| 20 | SPSCQueue() : size(0) { | 20 | SPSCQueue() { |
| 21 | write_ptr = read_ptr = new ElementPtr(); | 21 | write_ptr = read_ptr = new ElementPtr(); |
| 22 | } | 22 | } |
| 23 | ~SPSCQueue() { | 23 | ~SPSCQueue() { |
| @@ -25,13 +25,12 @@ public: | |||
| 25 | delete read_ptr; | 25 | delete read_ptr; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | u32 Size() const { | 28 | std::size_t Size() const { |
| 29 | static_assert(NeedSize, "using Size() on FifoQueue without NeedSize"); | ||
| 30 | return size.load(); | 29 | return size.load(); |
| 31 | } | 30 | } |
| 32 | 31 | ||
| 33 | bool Empty() const { | 32 | bool Empty() const { |
| 34 | return !read_ptr->next.load(); | 33 | return Size() == 0; |
| 35 | } | 34 | } |
| 36 | 35 | ||
| 37 | T& Front() const { | 36 | T& Front() const { |
| @@ -47,13 +46,14 @@ public: | |||
| 47 | ElementPtr* new_ptr = new ElementPtr(); | 46 | ElementPtr* new_ptr = new ElementPtr(); |
| 48 | write_ptr->next.store(new_ptr, std::memory_order_release); | 47 | write_ptr->next.store(new_ptr, std::memory_order_release); |
| 49 | write_ptr = new_ptr; | 48 | write_ptr = new_ptr; |
| 50 | if (NeedSize) | 49 | cv.notify_one(); |
| 51 | size++; | 50 | |
| 51 | ++size; | ||
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | void Pop() { | 54 | void Pop() { |
| 55 | if (NeedSize) | 55 | --size; |
| 56 | size--; | 56 | |
| 57 | ElementPtr* tmpptr = read_ptr; | 57 | ElementPtr* tmpptr = read_ptr; |
| 58 | // advance the read pointer | 58 | // advance the read pointer |
| 59 | read_ptr = tmpptr->next.load(); | 59 | read_ptr = tmpptr->next.load(); |
| @@ -66,8 +66,7 @@ public: | |||
| 66 | if (Empty()) | 66 | if (Empty()) |
| 67 | return false; | 67 | return false; |
| 68 | 68 | ||
| 69 | if (NeedSize) | 69 | --size; |
| 70 | size--; | ||
| 71 | 70 | ||
| 72 | ElementPtr* tmpptr = read_ptr; | 71 | ElementPtr* tmpptr = read_ptr; |
| 73 | read_ptr = tmpptr->next.load(std::memory_order_acquire); | 72 | read_ptr = tmpptr->next.load(std::memory_order_acquire); |
| @@ -77,6 +76,16 @@ public: | |||
| 77 | return true; | 76 | return true; |
| 78 | } | 77 | } |
| 79 | 78 | ||
| 79 | T PopWait() { | ||
| 80 | if (Empty()) { | ||
| 81 | std::unique_lock<std::mutex> lock(cv_mutex); | ||
| 82 | cv.wait(lock, [this]() { return !Empty(); }); | ||
| 83 | } | ||
| 84 | T t; | ||
| 85 | Pop(t); | ||
| 86 | return t; | ||
| 87 | } | ||
| 88 | |||
| 80 | // not thread-safe | 89 | // not thread-safe |
| 81 | void Clear() { | 90 | void Clear() { |
| 82 | size.store(0); | 91 | size.store(0); |
| @@ -89,7 +98,7 @@ private: | |||
| 89 | // and a pointer to the next ElementPtr | 98 | // and a pointer to the next ElementPtr |
| 90 | class ElementPtr { | 99 | class ElementPtr { |
| 91 | public: | 100 | public: |
| 92 | ElementPtr() : next(nullptr) {} | 101 | ElementPtr() {} |
| 93 | ~ElementPtr() { | 102 | ~ElementPtr() { |
| 94 | ElementPtr* next_ptr = next.load(); | 103 | ElementPtr* next_ptr = next.load(); |
| 95 | 104 | ||
| @@ -98,21 +107,23 @@ private: | |||
| 98 | } | 107 | } |
| 99 | 108 | ||
| 100 | T current; | 109 | T current; |
| 101 | std::atomic<ElementPtr*> next; | 110 | std::atomic<ElementPtr*> next{nullptr}; |
| 102 | }; | 111 | }; |
| 103 | 112 | ||
| 104 | ElementPtr* write_ptr; | 113 | ElementPtr* write_ptr; |
| 105 | ElementPtr* read_ptr; | 114 | ElementPtr* read_ptr; |
| 106 | std::atomic<u32> size; | 115 | std::atomic_size_t size{0}; |
| 116 | std::mutex cv_mutex; | ||
| 117 | std::condition_variable cv; | ||
| 107 | }; | 118 | }; |
| 108 | 119 | ||
| 109 | // a simple thread-safe, | 120 | // a simple thread-safe, |
| 110 | // single reader, multiple writer queue | 121 | // single reader, multiple writer queue |
| 111 | 122 | ||
| 112 | template <typename T, bool NeedSize = true> | 123 | template <typename T> |
| 113 | class MPSCQueue { | 124 | class MPSCQueue { |
| 114 | public: | 125 | public: |
| 115 | u32 Size() const { | 126 | std::size_t Size() const { |
| 116 | return spsc_queue.Size(); | 127 | return spsc_queue.Size(); |
| 117 | } | 128 | } |
| 118 | 129 | ||
| @@ -138,13 +149,17 @@ public: | |||
| 138 | return spsc_queue.Pop(t); | 149 | return spsc_queue.Pop(t); |
| 139 | } | 150 | } |
| 140 | 151 | ||
| 152 | T PopWait() { | ||
| 153 | return spsc_queue.PopWait(); | ||
| 154 | } | ||
| 155 | |||
| 141 | // not thread-safe | 156 | // not thread-safe |
| 142 | void Clear() { | 157 | void Clear() { |
| 143 | spsc_queue.Clear(); | 158 | spsc_queue.Clear(); |
| 144 | } | 159 | } |
| 145 | 160 | ||
| 146 | private: | 161 | private: |
| 147 | SPSCQueue<T, NeedSize> spsc_queue; | 162 | SPSCQueue<T> spsc_queue; |
| 148 | std::mutex write_lock; | 163 | std::mutex write_lock; |
| 149 | }; | 164 | }; |
| 150 | } // namespace Common | 165 | } // 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 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #ifdef _MSC_VER | ||
| 6 | #include <intrin.h> | ||
| 7 | |||
| 8 | #pragma intrinsic(_umul128) | ||
| 9 | #endif | ||
| 10 | #include <cstring> | ||
| 11 | #include "common/uint128.h" | ||
| 12 | |||
| 13 | namespace Common { | ||
| 14 | |||
| 15 | u128 Multiply64Into128(u64 a, u64 b) { | ||
| 16 | u128 result; | ||
| 17 | #ifdef _MSC_VER | ||
| 18 | result[0] = _umul128(a, b, &result[1]); | ||
| 19 | #else | ||
| 20 | unsigned __int128 tmp = a; | ||
| 21 | tmp *= b; | ||
| 22 | std::memcpy(&result, &tmp, sizeof(u128)); | ||
| 23 | #endif | ||
| 24 | return result; | ||
| 25 | } | ||
| 26 | |||
| 27 | std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor) { | ||
| 28 | u64 remainder = dividend[0] % divisor; | ||
| 29 | u64 accum = dividend[0] / divisor; | ||
| 30 | if (dividend[1] == 0) | ||
| 31 | return {accum, remainder}; | ||
| 32 | // We ignore dividend[1] / divisor as that overflows | ||
| 33 | const u64 first_segment = (dividend[1] % divisor) << 32; | ||
| 34 | accum += (first_segment / divisor) << 32; | ||
| 35 | const u64 second_segment = (first_segment % divisor) << 32; | ||
| 36 | accum += (second_segment / divisor); | ||
| 37 | remainder += second_segment % divisor; | ||
| 38 | if (remainder >= divisor) { | ||
| 39 | accum++; | ||
| 40 | remainder -= divisor; | ||
| 41 | } | ||
| 42 | return {accum, remainder}; | ||
| 43 | } | ||
| 44 | |||
| 45 | } // 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 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <utility> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | |||
| 10 | namespace Common { | ||
| 11 | |||
| 12 | // This function multiplies 2 u64 values and produces a u128 value; | ||
| 13 | u128 Multiply64Into128(u64 a, u64 b); | ||
| 14 | |||
| 15 | // This function divides a u128 by a u32 value and produces two u64 values: | ||
| 16 | // the result of division and the remainder | ||
| 17 | std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor); | ||
| 18 | |||
| 19 | } // 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 @@ | |||
| 33 | #include <cmath> | 33 | #include <cmath> |
| 34 | #include <type_traits> | 34 | #include <type_traits> |
| 35 | 35 | ||
| 36 | namespace Math { | 36 | namespace Common { |
| 37 | 37 | ||
| 38 | template <typename T> | 38 | template <typename T> |
| 39 | class Vec2; | 39 | class Vec2; |
| @@ -690,4 +690,4 @@ constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) { | |||
| 690 | return MakeVec(x, yzw[0], yzw[1], yzw[2]); | 690 | return MakeVec(x, yzw[0], yzw[1], yzw[2]); |
| 691 | } | 691 | } |
| 692 | 692 | ||
| 693 | } // namespace Math | 693 | } // namespace Common |