Compare commits

...

51 Commits

Author SHA1 Message Date
Feng Chen bdb70ba692 video_core: Move all function defintions of ProgramManager to cpp 2023-01-05 12:12:22 +08:00
Feng Chen f9cfc2e5c6 video_core: Implement opengl draw_texture 2023-01-05 12:12:22 +08:00
Feng Chen 413a0c2c03 video_core: Implement vulkan draw_texture 2023-01-05 12:12:22 +08:00
Feng Chen 944d2e4154 video_core: Implement maxwell3d draw texture method 2023-01-05 12:12:12 +08:00
Fernando Sahmkow b22892a306 yuzu-ui: Add setting for disabling macro HLE 2023-01-05 12:09:48 +08:00
Fernando Sahmkow 4f0695024c Video_core: Address feedback 2023-01-05 12:09:48 +08:00
Fernando Sahmkow 9307ef73e6 Texture Cache: Implement async texture downloads. 2023-01-05 12:09:48 +08:00
Fernando Sahmkow 8eac3c8fe4 Vulkan: Update blacklisting to latest driver versions. 2023-01-05 12:09:48 +08:00
Fernando Sahmkow 43467dc141 ShaderCompiler: Inline driver specific constants. 2023-01-05 12:09:48 +08:00
Fernando Sahmkow 388e1171d2 Vulkan: rework stencil tracking. 2023-01-05 12:09:48 +08:00
Liam aba560df7e vulkan_common: blacklist radv from extended_dynamic_state2 on drivers before 22.3.1 2023-01-05 12:09:48 +08:00
Liam 2f8fb0f96d video_core: fix build 2023-01-05 12:09:48 +08:00
Fernando Sahmkow b6b18d2a6b MacroHLE: Final cleanup and fixes. 2023-01-05 12:09:48 +08:00
Fernando Sahmkow b146b19b5e Rasterizer: Setup skeleton for Host Conditional rendering 2023-01-05 12:09:48 +08:00
Fernando Sahmkow d7c90f0c2a RasterizerMemory: Add filtering for flushing/invalidation operations. 2023-01-05 12:09:48 +08:00
Fernando Sahmkow 1c15c70fcd Vulkan: Allow stagging buffer deferrals. 2023-01-05 12:09:48 +08:00
Fernando Sahmkow 025af28583 MacroHLE: Add OpenGL Support 2023-01-05 12:09:48 +08:00
Fernando Sahmkow 33b925b2af Vulkan: Add other additional pipeline specs 2023-01-05 12:09:48 +08:00
Fernando Sahmkow a69aad10c1 Vulkan: Implement Dynamic State 3 2023-01-05 12:09:48 +08:00
Fernando Sahmkow e64875e15b Vulkan Implement Dynamic State 2 LogicOp and PatchVertices 2023-01-05 12:09:47 +08:00
Fernando Sahmkow d1636b81f5 Vulkan: Implement Dynamic States 2 2023-01-05 12:09:47 +08:00
Fernando Sahmkow da4faa90e8 DMAPusher: Improve collection of non executing methods 2023-01-05 12:09:47 +08:00
Fernando Sahmkow 7d88ae02e6 Revert Buffer cache changes and setup additional macros. 2023-01-05 12:09:47 +08:00
Fernando Sahmkow 3769e1a66f MacroHLE: Reduce massive calculations on sizing estimation. 2023-01-05 12:09:47 +08:00
Fernando Sahmkow 5f0bb935c4 MacroHLE: Add HLE replacement for base vertex and base instance. 2023-01-05 12:09:47 +08:00
Fernando Sahmkow 661d20f2e7 MacroHLE: Add Index Buffer size estimation. 2023-01-05 12:09:47 +08:00
Fernando Sahmkow 730abf80f4 MacroHLE: Refactor MacroHLE system. 2023-01-05 12:09:47 +08:00
Fernando Sahmkow a471e87912 MacroHLE: Implement DrawIndexedIndirect & DrawArraysIndirect. 2023-01-05 12:09:47 +08:00
Fernando Sahmkow f143d8cd37 MacroHLE: Add MultidrawIndirect HLE Macro. 2023-01-05 12:09:47 +08:00
gidoly f39e11a183 Revert "k_page_group: synchronize" 2023-01-05 12:09:47 +08:00
MonsterDruide1 b20bc73334 TAS: Immediately switch stick to TAS on input
Co-Authored-By: Narr the Reg <5944268+german77@users.noreply.github.com>
2023-01-05 12:09:47 +08:00
Alexandre Bouvier 5c5b6d8e04 cmake: move find-modules to root cmake dir 2023-01-05 12:09:47 +08:00
Alexandre Bouvier f5a27784c6 cmake: allow options shadowing with normal variables 2023-01-05 12:09:47 +08:00
MonsterDruide1 f118d3ba48 TAS: Record sanitized instead of raw stick inputs
Co-Authored-By: Narr the Reg <5944268+german77@users.noreply.github.com>
2023-01-05 12:09:47 +08:00
Alexandre Bouvier 3b26a03b27 cmake: improve find_package failure messages 2023-01-05 12:09:47 +08:00
german77 d725d957bb service: nifm: Initialize request state 2023-01-05 12:09:47 +08:00
german77 d3986f1ed8 service: nifm: Match documentation names 2023-01-05 12:09:46 +08:00
Merry b63f1faae0 vfs: Replace cstr concat with char concat 2023-01-05 12:09:46 +08:00
Merry da0dae3d05 host_memory: Use transparent huge pages where available 2023-01-05 12:09:46 +08:00
Merry 13b7ad86dc host_memory: Allocate virtual_base with MAP_NORESERVE
Specify that we do not require swap to be reserved for this address range;
allow overcommitting.
2023-01-05 12:09:46 +08:00
The yuzu Community 0fc8dbf6d2 Update translations (2023-01-01) 2023-01-05 12:09:46 +08:00
Colin Kinloch b0aca1e8ed settings: comment language blocklist columns 2023-01-05 12:09:46 +08:00
Colin Kinloch 25d139a4e1 settings: added regon/language warning bounds check 2023-01-05 12:09:46 +08:00
Colin Kinloch 7370b0c463 settings: warn on invalid regon/language combinations 2023-01-05 12:09:46 +08:00
Colin Kinloch 3692a01574 ci: Allow setting clang-format binary 2023-01-05 12:09:46 +08:00
bunnei a12b94569a core: hid: emulated_console: Avoid a crash if frontend does not configure touch_from_button_maps. 2023-01-05 12:09:46 +08:00
Liam 82cdc93e25 cmake: make Vulkan-Headers external the default 2023-01-05 12:09:46 +08:00
Liam 462db514df cmake: make cubeb and SDL2 optional 2023-01-05 12:09:46 +08:00
Liam d17f6cceb7 cmake: make libusb optional 2023-01-05 12:09:46 +08:00
Liam 2b22a91dee cmake: ignore missing package finders for packages with submodule fallbacks 2023-01-05 12:09:45 +08:00
Liam d0b2e59b27 cmake: make room server optional 2023-01-05 12:09:45 +08:00
153 changed files with 21794 additions and 15808 deletions
Regular → Executable
+1 -1
View File
@@ -10,7 +10,7 @@ if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dis
fi
# Default clang-format points to default 3.5 version one
CLANG_FORMAT=clang-format-12
CLANG_FORMAT=${CLANG_FORMAT:-clang-format-12}
$CLANG_FORMAT --version
if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then
+24 -16
View File
@@ -3,13 +3,8 @@
cmake_minimum_required(VERSION 3.22)
# Dynarmic has cmake_minimum_required(3.12) and we may want to override
# some of its variables, which is only possible in 3.13+
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/find-modules")
include(DownloadExternals)
include(CMakeDependentOption)
@@ -22,6 +17,8 @@ CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON
# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
CMAKE_DEPENDENT_OPTION(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" ON "ENABLE_SDL2;NOT MSVC" OFF)
option(ENABLE_LIBUSB "Enable the use of LibUSB" ON)
option(ENABLE_OPENGL "Enable OpenGL" ON)
mark_as_advanced(FORCE ENABLE_OPENGL)
option(ENABLE_QT "Enable the Qt frontend" ON)
@@ -35,6 +32,8 @@ option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
option(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled FFmpeg" "${WIN32}")
option(YUZU_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" ON)
option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
@@ -47,6 +46,8 @@ option(YUZU_TESTS "Compile tests" ON)
option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
option(YUZU_ROOM "Compile LDN room server" ON)
CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile Windows crash dump (Minidump) support" OFF "WIN32" OFF)
option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}")
@@ -201,36 +202,43 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
# System imported libraries
# =======================================================================
find_package(enet 1.3)
# Enforce the search mode of non-required packages for better and shorter failure messages
find_package(enet 1.3 MODULE)
find_package(fmt 9 REQUIRED)
find_package(inih)
find_package(libusb 1.0.24)
find_package(inih MODULE)
find_package(lz4 REQUIRED)
find_package(nlohmann_json 3.8 REQUIRED)
find_package(Opus 1.3)
find_package(Vulkan 1.3.238)
find_package(Opus 1.3 MODULE)
find_package(ZLIB 1.2 REQUIRED)
find_package(zstd 1.5 REQUIRED)
if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS)
find_package(Vulkan 1.3.238 REQUIRED)
endif()
if (ENABLE_LIBUSB)
find_package(libusb 1.0.24 MODULE)
endif()
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
find_package(xbyak 6)
find_package(xbyak 6 CONFIG)
endif()
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
find_package(dynarmic 6.4.0)
find_package(dynarmic 6.4.0 CONFIG)
endif()
if (ENABLE_CUBEB)
find_package(cubeb)
find_package(cubeb CONFIG)
endif()
if (USE_DISCORD_PRESENCE)
find_package(DiscordRPC)
find_package(DiscordRPC MODULE)
endif()
if (ENABLE_WEB_SERVICE)
find_package(cpp-jwt 1.4)
find_package(httplib 0.11)
find_package(cpp-jwt 1.4 CONFIG)
find_package(httplib 0.11 MODULE)
endif()
if (YUZU_TESTS)
@@ -5,7 +5,7 @@
include(FindPackageHandleStandardArgs)
find_package(httplib QUIET CONFIG)
if (httplib_FOUND)
if (httplib_CONSIDERED_CONFIGS)
find_package_handle_standard_args(httplib CONFIG_MODE)
else()
find_package(PkgConfig QUIET)
@@ -4,7 +4,7 @@
include(FindPackageHandleStandardArgs)
find_package(lz4 QUIET CONFIG)
if (lz4_FOUND)
if (lz4_CONSIDERED_CONFIGS)
find_package_handle_standard_args(lz4 CONFIG_MODE)
else()
find_package(PkgConfig QUIET)
@@ -4,7 +4,7 @@
include(FindPackageHandleStandardArgs)
find_package(zstd QUIET CONFIG)
if (zstd_FOUND)
if (zstd_CONSIDERED_CONFIGS)
find_package_handle_standard_args(zstd CONFIG_MODE)
else()
find_package(PkgConfig QUIET)
+734 -600
View File
File diff suppressed because it is too large Load Diff
+734 -600
View File
File diff suppressed because it is too large Load Diff
+733 -599
View File
File diff suppressed because it is too large Load Diff
+757 -623
View File
File diff suppressed because it is too large Load Diff
+733 -599
View File
File diff suppressed because it is too large Load Diff
+736 -602
View File
File diff suppressed because it is too large Load Diff
+740 -603
View File
File diff suppressed because it is too large Load Diff
+733 -599
View File
File diff suppressed because it is too large Load Diff
+782 -649
View File
File diff suppressed because it is too large Load Diff
+734 -600
View File
File diff suppressed because it is too large Load Diff
+734 -600
View File
File diff suppressed because it is too large Load Diff
+734 -600
View File
File diff suppressed because it is too large Load Diff
+734 -600
View File
File diff suppressed because it is too large Load Diff
+734 -601
View File
File diff suppressed because it is too large Load Diff
+759 -625
View File
File diff suppressed because it is too large Load Diff
+741 -607
View File
File diff suppressed because it is too large Load Diff
+819 -682
View File
File diff suppressed because it is too large Load Diff
+734 -600
View File
File diff suppressed because it is too large Load Diff
+742 -604
View File
File diff suppressed because it is too large Load Diff
+806 -669
View File
File diff suppressed because it is too large Load Diff
+733 -599
View File
File diff suppressed because it is too large Load Diff
+733 -599
View File
File diff suppressed because it is too large Load Diff
+737 -600
View File
File diff suppressed because it is too large Load Diff
+739 -602
View File
File diff suppressed because it is too large Load Diff
+11 -12
View File
@@ -1,9 +1,9 @@
# SPDX-FileCopyrightText: 2016 Citra Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules")
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/externals/find-modules")
include(DownloadExternals)
# Dynarmic has cmake_minimum_required(3.12) and we may want to override
# some of its variables, which is only possible in 3.13+
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
# xbyak
if ((ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) AND NOT TARGET xbyak::xbyak)
@@ -12,8 +12,7 @@ endif()
# Dynarmic
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) AND NOT TARGET dynarmic::dynarmic)
set(DYNARMIC_NO_BUNDLED_FMT ON)
set(DYNARMIC_IGNORE_ASSERTS ON CACHE BOOL "" FORCE)
set(DYNARMIC_IGNORE_ASSERTS ON)
add_subdirectory(dynarmic EXCLUDE_FROM_ALL)
add_library(dynarmic::dynarmic ALIAS dynarmic)
endif()
@@ -45,7 +44,7 @@ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12" AND CMAKE_CXX_COMPILER
endif()
# libusb
if (NOT TARGET libusb::usb)
if (ENABLE_LIBUSB AND NOT TARGET libusb::usb)
add_subdirectory(libusb EXCLUDE_FROM_ALL)
endif()
@@ -60,10 +59,10 @@ if (YUZU_USE_EXTERNAL_SDL2)
Locale Power Render)
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
string(TOUPPER ${_SUB} _OPT)
option(SDL_${_OPT} "" OFF)
set(SDL_${_OPT} OFF)
endforeach()
option(HIDAPI "" ON)
set(HIDAPI ON)
endif()
set(SDL_STATIC ON)
set(SDL_SHARED OFF)
@@ -83,7 +82,7 @@ endif()
# Cubeb
if (ENABLE_CUBEB AND NOT TARGET cubeb::cubeb)
set(BUILD_TESTS OFF CACHE BOOL "")
set(BUILD_TESTS OFF)
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
add_library(cubeb::cubeb ALIAS cubeb)
endif()
@@ -98,6 +97,7 @@ endif()
# Sirit
add_subdirectory(sirit EXCLUDE_FROM_ALL)
# httplib
if (ENABLE_WEB_SERVICE AND NOT TARGET httplib::httplib)
if (NOT WIN32)
find_package(OpenSSL 1.1)
@@ -108,7 +108,7 @@ if (ENABLE_WEB_SERVICE AND NOT TARGET httplib::httplib)
if (WIN32 OR NOT OPENSSL_FOUND)
# LibreSSL
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
set(LIBRESSL_SKIP_INSTALL ON)
set(OPENSSLDIR "/etc/ssl/")
add_subdirectory(libressl EXCLUDE_FROM_ALL)
target_include_directories(ssl INTERFACE ./libressl/include)
@@ -118,7 +118,6 @@ if (ENABLE_WEB_SERVICE AND NOT TARGET httplib::httplib)
DEFINITION OPENSSL_LIBS)
endif()
# httplib
add_library(httplib INTERFACE)
target_include_directories(httplib INTERFACE ./cpp-httplib)
target_compile_definitions(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT)
@@ -152,6 +151,6 @@ if (YUZU_USE_BUNDLED_FFMPEG)
endif()
# Vulkan-Headers
if (NOT TARGET Vulkan::Headers)
if (YUZU_USE_EXTERNAL_VULKAN_HEADERS)
add_subdirectory(Vulkan-Headers EXCLUDE_FROM_ALL)
endif()
+4 -1
View File
@@ -161,7 +161,10 @@ add_subdirectory(video_core)
add_subdirectory(network)
add_subdirectory(input_common)
add_subdirectory(shader_recompiler)
add_subdirectory(dedicated_room)
if (YUZU_ROOM)
add_subdirectory(dedicated_room)
endif()
if (YUZU_TESTS)
add_subdirectory(tests)
+13 -6
View File
@@ -187,11 +187,7 @@ add_library(audio_core STATIC
renderer/voice/voice_info.cpp
renderer/voice/voice_info.h
renderer/voice/voice_state.h
sink/cubeb_sink.cpp
sink/cubeb_sink.h
sink/null_sink.h
sink/sdl2_sink.cpp
sink/sdl2_sink.h
sink/sink.h
sink/sink_details.cpp
sink/sink_details.h
@@ -222,11 +218,22 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
target_link_libraries(audio_core PRIVATE dynarmic::dynarmic)
endif()
if(ENABLE_CUBEB)
if (ENABLE_CUBEB)
target_sources(audio_core PRIVATE
sink/cubeb_sink.cpp
sink/cubeb_sink.h
)
target_link_libraries(audio_core PRIVATE cubeb::cubeb)
target_compile_definitions(audio_core PRIVATE -DHAVE_CUBEB=1)
endif()
if(ENABLE_SDL2)
if (ENABLE_SDL2)
target_sources(audio_core PRIVATE
sink/sdl2_sink.cpp
sink/sdl2_sink.h
)
target_link_libraries(audio_core PRIVATE SDL2::SDL2)
target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
endif()
+1
View File
@@ -97,6 +97,7 @@ add_library(common STATIC
point.h
precompiled_headers.h
quaternion.h
range_map.h
reader_writer_queue.h
ring_buffer.h
${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp
+17 -2
View File
@@ -393,12 +393,27 @@ public:
}
// Virtual memory initialization
virtual_base = static_cast<u8*>(
mmap(nullptr, virtual_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
#if defined(__FreeBSD__)
virtual_base =
static_cast<u8*>(mmap(nullptr, virtual_size, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER, -1, 0));
if (virtual_base == MAP_FAILED) {
virtual_base = static_cast<u8*>(
mmap(nullptr, virtual_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
if (virtual_base == MAP_FAILED) {
LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno));
throw std::bad_alloc{};
}
}
#else
virtual_base = static_cast<u8*>(mmap(nullptr, virtual_size, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0));
if (virtual_base == MAP_FAILED) {
LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno));
throw std::bad_alloc{};
}
madvise(virtual_base, virtual_size, MADV_HUGEPAGE);
#endif
good = true;
}
+139
View File
@@ -0,0 +1,139 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <map>
#include <type_traits>
#include "common/common_types.h"
namespace Common {
template <typename KeyTBase, typename ValueT>
class RangeMap {
private:
using KeyT =
std::conditional_t<std::is_signed_v<KeyTBase>, KeyTBase, std::make_signed_t<KeyTBase>>;
public:
explicit RangeMap(ValueT null_value_) : null_value{null_value_} {
container.emplace(std::numeric_limits<KeyT>::min(), null_value);
};
~RangeMap() = default;
void Map(KeyTBase address, KeyTBase address_end, ValueT value) {
KeyT new_address = static_cast<KeyT>(address);
KeyT new_address_end = static_cast<KeyT>(address_end);
if (new_address < 0) {
new_address = 0;
}
if (new_address_end < 0) {
new_address_end = 0;
}
InternalMap(new_address, new_address_end, value);
}
void Unmap(KeyTBase address, KeyTBase address_end) {
Map(address, address_end, null_value);
}
[[nodiscard]] size_t GetContinousSizeFrom(KeyTBase address) const {
const KeyT new_address = static_cast<KeyT>(address);
if (new_address < 0) {
return 0;
}
return ContinousSizeInternal(new_address);
}
[[nodiscard]] ValueT GetValueAt(KeyT address) const {
const KeyT new_address = static_cast<KeyT>(address);
if (new_address < 0) {
return null_value;
}
return GetValueInternal(new_address);
}
private:
using MapType = std::map<KeyT, ValueT>;
using IteratorType = typename MapType::iterator;
using ConstIteratorType = typename MapType::const_iterator;
size_t ContinousSizeInternal(KeyT address) const {
const auto it = GetFirstElementBeforeOrOn(address);
if (it == container.end() || it->second == null_value) {
return 0;
}
const auto it_end = std::next(it);
if (it_end == container.end()) {
return std::numeric_limits<KeyT>::max() - address;
}
return it_end->first - address;
}
ValueT GetValueInternal(KeyT address) const {
const auto it = GetFirstElementBeforeOrOn(address);
if (it == container.end()) {
return null_value;
}
return it->second;
}
ConstIteratorType GetFirstElementBeforeOrOn(KeyT address) const {
auto it = container.lower_bound(address);
if (it == container.begin()) {
return it;
}
if (it != container.end() && (it->first == address)) {
return it;
}
--it;
return it;
}
ValueT GetFirstValueWithin(KeyT address) {
auto it = container.lower_bound(address);
if (it == container.begin()) {
return it->second;
}
if (it == container.end()) [[unlikely]] { // this would be a bug
return null_value;
}
--it;
return it->second;
}
ValueT GetLastValueWithin(KeyT address) {
auto it = container.upper_bound(address);
if (it == container.end()) {
return null_value;
}
if (it == container.begin()) [[unlikely]] { // this would be a bug
return it->second;
}
--it;
return it->second;
}
void InternalMap(KeyT address, KeyT address_end, ValueT value) {
const bool must_add_start = GetFirstValueWithin(address) != value;
const ValueT last_value = GetLastValueWithin(address_end);
const bool must_add_end = last_value != value;
auto it = container.lower_bound(address);
const auto it_end = container.upper_bound(address_end);
while (it != it_end) {
it = container.erase(it);
}
if (must_add_start) {
container.emplace(address, value);
}
if (must_add_end) {
container.emplace(address_end, last_value);
}
}
ValueT null_value;
MapType container;
};
} // namespace Common
+1
View File
@@ -531,6 +531,7 @@ struct Values {
Setting<bool> reporting_services{false, "reporting_services"};
Setting<bool> quest_flag{false, "quest_flag"};
Setting<bool> disable_macro_jit{false, "disable_macro_jit"};
Setting<bool> disable_macro_hle{false, "disable_macro_hle"};
Setting<bool> extended_logging{false, "extended_logging"};
Setting<bool> use_debug_asserts{false, "use_debug_asserts"};
Setting<bool> use_auto_stub{false, "use_auto_stub"};
-1
View File
@@ -226,7 +226,6 @@ add_library(core STATIC
hle/kernel/k_page_buffer.h
hle/kernel/k_page_heap.cpp
hle/kernel/k_page_heap.h
hle/kernel/k_page_group.cpp
hle/kernel/k_page_group.h
hle/kernel/k_page_table.cpp
hle/kernel/k_page_table.h
+3 -3
View File
@@ -194,9 +194,9 @@ std::size_t VfsFile::WriteBytes(const std::vector<u8>& data, std::size_t offset)
std::string VfsFile::GetFullPath() const {
if (GetContainingDirectory() == nullptr)
return "/" + GetName();
return '/' + GetName();
return GetContainingDirectory()->GetFullPath() + "/" + GetName();
return GetContainingDirectory()->GetFullPath() + '/' + GetName();
}
VirtualFile VfsDirectory::GetFileRelative(std::string_view path) const {
@@ -435,7 +435,7 @@ std::string VfsDirectory::GetFullPath() const {
if (IsRoot())
return GetName();
return GetParentDirectory()->GetFullPath() + "/" + GetName();
return GetParentDirectory()->GetFullPath() + '/' + GetName();
}
bool ReadOnlyVfsDirectory::IsWritable() const {
+5
View File
@@ -40,6 +40,11 @@ void EmulatedConsole::SetTouchParams() {
touch_params[index++] = std::move(touchscreen_param);
}
if (Settings::values.touch_from_button_maps.empty()) {
LOG_WARNING(Input, "touch_from_button_maps is unset by frontend config");
return;
}
const auto button_index =
static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
const auto& touch_buttons = Settings::values.touch_from_button_maps[button_index].buttons;
+11 -9
View File
@@ -11,6 +11,11 @@
namespace Core::HID {
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
constexpr s32 HID_TRIGGER_MAX = 0x7fff;
// Use a common UUID for TAS and Virtual Gamepad
constexpr Common::UUID TAS_UUID =
Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
constexpr Common::UUID VIRTUAL_UUID =
Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
EmulatedController::EmulatedController(NpadIdType npad_id_type_) : npad_id_type(npad_id_type_) {}
@@ -348,10 +353,6 @@ void EmulatedController::ReloadInput() {
}
}
// Use a common UUID for TAS
static constexpr Common::UUID TAS_UUID = Common::UUID{
{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
// Register TAS devices. No need to force update
for (std::size_t index = 0; index < tas_button_devices.size(); ++index) {
if (!tas_button_devices[index]) {
@@ -377,10 +378,6 @@ void EmulatedController::ReloadInput() {
});
}
// Use a common UUID for Virtual Gamepad
static constexpr Common::UUID VIRTUAL_UUID = Common::UUID{
{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
// Register virtual devices. No need to force update
for (std::size_t index = 0; index < virtual_button_devices.size(); ++index) {
if (!virtual_button_devices[index]) {
@@ -780,7 +777,12 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
// Only read stick values that have the same uuid or are over the threshold to avoid flapping
if (controller.stick_values[index].uuid != uuid) {
if (!stick_value.down && !stick_value.up && !stick_value.left && !stick_value.right) {
const bool is_tas = uuid == TAS_UUID;
if (is_tas && stick_value.x.value == 0 && stick_value.y.value == 0) {
return;
}
if (!is_tas && !stick_value.down && !stick_value.up && !stick_value.left &&
!stick_value.right) {
return;
}
}
+14 -15
View File
@@ -27,13 +27,13 @@ Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, si
auto& page_table = m_owner->PageTable();
// Construct the page group.
m_page_group.emplace(kernel, page_table.GetBlockInfoManager());
m_page_group = {};
// Lock the memory.
R_TRY(page_table.LockForCodeMemory(std::addressof(*m_page_group), addr, size))
R_TRY(page_table.LockForCodeMemory(&m_page_group, addr, size))
// Clear the memory.
for (const auto& block : *m_page_group) {
for (const auto& block : m_page_group.Nodes()) {
std::memset(device_memory.GetPointer<void>(block.GetAddress()), 0xFF, block.GetSize());
}
@@ -51,13 +51,12 @@ Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, si
void KCodeMemory::Finalize() {
// Unlock.
if (!m_is_mapped && !m_is_owner_mapped) {
const size_t size = m_page_group->GetNumPages() * PageSize;
m_owner->PageTable().UnlockForCodeMemory(m_address, size, *m_page_group);
const size_t size = m_page_group.GetNumPages() * PageSize;
m_owner->PageTable().UnlockForCodeMemory(m_address, size, m_page_group);
}
// Close the page group.
m_page_group->Close();
m_page_group->Finalize();
m_page_group = {};
// Close our reference to our owner.
m_owner->Close();
@@ -65,7 +64,7 @@ void KCodeMemory::Finalize() {
Result KCodeMemory::Map(VAddr address, size_t size) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
// Lock ourselves.
KScopedLightLock lk(m_lock);
@@ -75,7 +74,7 @@ Result KCodeMemory::Map(VAddr address, size_t size) {
// Map the memory.
R_TRY(kernel.CurrentProcess()->PageTable().MapPages(
address, *m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite));
address, m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite));
// Mark ourselves as mapped.
m_is_mapped = true;
@@ -85,13 +84,13 @@ Result KCodeMemory::Map(VAddr address, size_t size) {
Result KCodeMemory::Unmap(VAddr address, size_t size) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
// Lock ourselves.
KScopedLightLock lk(m_lock);
// Unmap the memory.
R_TRY(kernel.CurrentProcess()->PageTable().UnmapPages(address, *m_page_group,
R_TRY(kernel.CurrentProcess()->PageTable().UnmapPages(address, m_page_group,
KMemoryState::CodeOut));
// Mark ourselves as unmapped.
@@ -102,7 +101,7 @@ Result KCodeMemory::Unmap(VAddr address, size_t size) {
Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
// Lock ourselves.
KScopedLightLock lk(m_lock);
@@ -126,7 +125,7 @@ Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission
// Map the memory.
R_TRY(
m_owner->PageTable().MapPages(address, *m_page_group, KMemoryState::GeneratedCode, k_perm));
m_owner->PageTable().MapPages(address, m_page_group, KMemoryState::GeneratedCode, k_perm));
// Mark ourselves as mapped.
m_is_owner_mapped = true;
@@ -136,13 +135,13 @@ Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission
Result KCodeMemory::UnmapFromOwner(VAddr address, size_t size) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
// Lock ourselves.
KScopedLightLock lk(m_lock);
// Unmap the memory.
R_TRY(m_owner->PageTable().UnmapPages(address, *m_page_group, KMemoryState::GeneratedCode));
R_TRY(m_owner->PageTable().UnmapPages(address, m_page_group, KMemoryState::GeneratedCode));
// Mark ourselves as unmapped.
m_is_owner_mapped = false;
+2 -4
View File
@@ -3,8 +3,6 @@
#pragma once
#include <optional>
#include "common/common_types.h"
#include "core/device_memory.h"
#include "core/hle/kernel/k_auto_object.h"
@@ -51,11 +49,11 @@ public:
return m_address;
}
size_t GetSize() const {
return m_is_initialized ? m_page_group->GetNumPages() * PageSize : 0;
return m_is_initialized ? m_page_group.GetNumPages() * PageSize : 0;
}
private:
std::optional<KPageGroup> m_page_group{};
KPageGroup m_page_group{};
KProcess* m_owner{};
VAddr m_address{};
KLightLock m_lock;
+4 -4
View File
@@ -223,7 +223,7 @@ Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages,
// Ensure that we don't leave anything un-freed.
ON_RESULT_FAILURE {
for (const auto& it : *out) {
for (const auto& it : out->Nodes()) {
auto& manager = this->GetManager(it.GetAddress());
const size_t node_num_pages = std::min<u64>(
it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize);
@@ -285,7 +285,7 @@ Result KMemoryManager::AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 op
m_has_optimized_process[static_cast<size_t>(pool)], true));
// Open the first reference to the pages.
for (const auto& block : *out) {
for (const auto& block : out->Nodes()) {
PAddr cur_address = block.GetAddress();
size_t remaining_pages = block.GetNumPages();
while (remaining_pages > 0) {
@@ -335,7 +335,7 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32
// Perform optimized memory tracking, if we should.
if (optimized) {
// Iterate over the allocated blocks.
for (const auto& block : *out) {
for (const auto& block : out->Nodes()) {
// Get the block extents.
const PAddr block_address = block.GetAddress();
const size_t block_pages = block.GetNumPages();
@@ -391,7 +391,7 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32
}
} else {
// Set all the allocated memory.
for (const auto& block : *out) {
for (const auto& block : out->Nodes()) {
std::memset(m_system.DeviceMemory().GetPointer<void>(block.GetAddress()), fill_pattern,
block.GetSize());
}
-121
View File
@@ -1,121 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/k_dynamic_resource_manager.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_page_group.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel {
void KPageGroup::Finalize() {
KBlockInfo* cur = m_first_block;
while (cur != nullptr) {
KBlockInfo* next = cur->GetNext();
m_manager->Free(cur);
cur = next;
}
m_first_block = nullptr;
m_last_block = nullptr;
}
void KPageGroup::CloseAndReset() {
auto& mm = m_kernel.MemoryManager();
KBlockInfo* cur = m_first_block;
while (cur != nullptr) {
KBlockInfo* next = cur->GetNext();
mm.Close(cur->GetAddress(), cur->GetNumPages());
m_manager->Free(cur);
cur = next;
}
m_first_block = nullptr;
m_last_block = nullptr;
}
size_t KPageGroup::GetNumPages() const {
size_t num_pages = 0;
for (const auto& it : *this) {
num_pages += it.GetNumPages();
}
return num_pages;
}
Result KPageGroup::AddBlock(KPhysicalAddress addr, size_t num_pages) {
// Succeed immediately if we're adding no pages.
R_SUCCEED_IF(num_pages == 0);
// Check for overflow.
ASSERT(addr < addr + num_pages * PageSize);
// Try to just append to the last block.
if (m_last_block != nullptr) {
R_SUCCEED_IF(m_last_block->TryConcatenate(addr, num_pages));
}
// Allocate a new block.
KBlockInfo* new_block = m_manager->Allocate();
R_UNLESS(new_block != nullptr, ResultOutOfResource);
// Initialize the block.
new_block->Initialize(addr, num_pages);
// Add the block to our list.
if (m_last_block != nullptr) {
m_last_block->SetNext(new_block);
} else {
m_first_block = new_block;
}
m_last_block = new_block;
R_SUCCEED();
}
void KPageGroup::Open() const {
auto& mm = m_kernel.MemoryManager();
for (const auto& it : *this) {
mm.Open(it.GetAddress(), it.GetNumPages());
}
}
void KPageGroup::OpenFirst() const {
auto& mm = m_kernel.MemoryManager();
for (const auto& it : *this) {
mm.OpenFirst(it.GetAddress(), it.GetNumPages());
}
}
void KPageGroup::Close() const {
auto& mm = m_kernel.MemoryManager();
for (const auto& it : *this) {
mm.Close(it.GetAddress(), it.GetNumPages());
}
}
bool KPageGroup::IsEquivalentTo(const KPageGroup& rhs) const {
auto lit = this->begin();
auto rit = rhs.begin();
auto lend = this->end();
auto rend = rhs.end();
while (lit != lend && rit != rend) {
if (*lit != *rit) {
return false;
}
++lit;
++rit;
}
return lit == lend && rit == rend;
}
} // namespace Kernel
+81 -102
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -13,23 +13,24 @@
namespace Kernel {
class KBlockInfoManager;
class KernelCore;
class KPageGroup;
class KBlockInfo {
public:
constexpr explicit KBlockInfo() : m_next(nullptr) {}
private:
friend class KPageGroup;
constexpr void Initialize(KPhysicalAddress addr, size_t np) {
public:
constexpr KBlockInfo() = default;
constexpr void Initialize(PAddr addr, size_t np) {
ASSERT(Common::IsAligned(addr, PageSize));
ASSERT(static_cast<u32>(np) == np);
m_page_index = static_cast<u32>(addr / PageSize);
m_page_index = static_cast<u32>(addr) / PageSize;
m_num_pages = static_cast<u32>(np);
}
constexpr KPhysicalAddress GetAddress() const {
constexpr PAddr GetAddress() const {
return m_page_index * PageSize;
}
constexpr size_t GetNumPages() const {
@@ -38,10 +39,10 @@ public:
constexpr size_t GetSize() const {
return this->GetNumPages() * PageSize;
}
constexpr KPhysicalAddress GetEndAddress() const {
constexpr PAddr GetEndAddress() const {
return (m_page_index + m_num_pages) * PageSize;
}
constexpr KPhysicalAddress GetLastAddress() const {
constexpr PAddr GetLastAddress() const {
return this->GetEndAddress() - 1;
}
@@ -61,8 +62,8 @@ public:
return !(*this == rhs);
}
constexpr bool IsStrictlyBefore(KPhysicalAddress addr) const {
const KPhysicalAddress end = this->GetEndAddress();
constexpr bool IsStrictlyBefore(PAddr addr) const {
const PAddr end = this->GetEndAddress();
if (m_page_index != 0 && end == 0) {
return false;
@@ -71,11 +72,11 @@ public:
return end < addr;
}
constexpr bool operator<(KPhysicalAddress addr) const {
constexpr bool operator<(PAddr addr) const {
return this->IsStrictlyBefore(addr);
}
constexpr bool TryConcatenate(KPhysicalAddress addr, size_t np) {
constexpr bool TryConcatenate(PAddr addr, size_t np) {
if (addr != 0 && addr == this->GetEndAddress()) {
m_num_pages += static_cast<u32>(np);
return true;
@@ -89,118 +90,96 @@ private:
}
private:
friend class KPageGroup;
KBlockInfo* m_next{};
u32 m_page_index{};
u32 m_num_pages{};
};
static_assert(sizeof(KBlockInfo) <= 0x10);
class KPageGroup {
class KPageGroup final {
public:
class Iterator {
class Node final {
public:
using iterator_category = std::forward_iterator_tag;
using value_type = const KBlockInfo;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
constexpr Node(u64 addr_, std::size_t num_pages_) : addr{addr_}, num_pages{num_pages_} {}
constexpr explicit Iterator(pointer n) : m_node(n) {}
constexpr bool operator==(const Iterator& rhs) const {
return m_node == rhs.m_node;
}
constexpr bool operator!=(const Iterator& rhs) const {
return !(*this == rhs);
constexpr u64 GetAddress() const {
return addr;
}
constexpr pointer operator->() const {
return m_node;
}
constexpr reference operator*() const {
return *m_node;
constexpr std::size_t GetNumPages() const {
return num_pages;
}
constexpr Iterator& operator++() {
m_node = m_node->GetNext();
return *this;
}
constexpr Iterator operator++(int) {
const Iterator it{*this};
++(*this);
return it;
constexpr std::size_t GetSize() const {
return GetNumPages() * PageSize;
}
private:
pointer m_node{};
u64 addr{};
std::size_t num_pages{};
};
explicit KPageGroup(KernelCore& kernel, KBlockInfoManager* m)
: m_kernel{kernel}, m_manager{m} {}
~KPageGroup() {
this->Finalize();
}
void CloseAndReset();
void Finalize();
Iterator begin() const {
return Iterator{m_first_block};
}
Iterator end() const {
return Iterator{nullptr};
}
bool empty() const {
return m_first_block == nullptr;
}
Result AddBlock(KPhysicalAddress addr, size_t num_pages);
void Open() const;
void OpenFirst() const;
void Close() const;
size_t GetNumPages() const;
bool IsEquivalentTo(const KPageGroup& rhs) const;
bool operator==(const KPageGroup& rhs) const {
return this->IsEquivalentTo(rhs);
}
bool operator!=(const KPageGroup& rhs) const {
return !(*this == rhs);
}
private:
KernelCore& m_kernel;
KBlockInfo* m_first_block{};
KBlockInfo* m_last_block{};
KBlockInfoManager* m_manager{};
};
class KScopedPageGroup {
public:
explicit KScopedPageGroup(const KPageGroup* gp) : m_pg(gp) {
if (m_pg) {
m_pg->Open();
}
}
explicit KScopedPageGroup(const KPageGroup& gp) : KScopedPageGroup(std::addressof(gp)) {}
~KScopedPageGroup() {
if (m_pg) {
m_pg->Close();
}
KPageGroup() = default;
KPageGroup(u64 address, u64 num_pages) {
ASSERT(AddBlock(address, num_pages).IsSuccess());
}
void CancelClose() {
m_pg = nullptr;
constexpr std::list<Node>& Nodes() {
return nodes;
}
constexpr const std::list<Node>& Nodes() const {
return nodes;
}
std::size_t GetNumPages() const {
std::size_t num_pages = 0;
for (const Node& node : nodes) {
num_pages += node.GetNumPages();
}
return num_pages;
}
bool IsEqual(KPageGroup& other) const {
auto this_node = nodes.begin();
auto other_node = other.nodes.begin();
while (this_node != nodes.end() && other_node != other.nodes.end()) {
if (this_node->GetAddress() != other_node->GetAddress() ||
this_node->GetNumPages() != other_node->GetNumPages()) {
return false;
}
this_node = std::next(this_node);
other_node = std::next(other_node);
}
return this_node == nodes.end() && other_node == other.nodes.end();
}
Result AddBlock(u64 address, u64 num_pages) {
if (!num_pages) {
return ResultSuccess;
}
if (!nodes.empty()) {
const auto node = nodes.back();
if (node.GetAddress() + node.GetNumPages() * PageSize == address) {
address = node.GetAddress();
num_pages += node.GetNumPages();
nodes.pop_back();
}
}
nodes.push_back({address, num_pages});
return ResultSuccess;
}
bool Empty() const {
return nodes.empty();
}
void Finalize() {}
private:
const KPageGroup* m_pg{};
std::list<Node> nodes;
};
} // namespace Kernel
+72 -70
View File
@@ -100,7 +100,7 @@ constexpr size_t GetAddressSpaceWidthFromType(FileSys::ProgramAddressSpaceType a
KPageTable::KPageTable(Core::System& system_)
: m_general_lock{system_.Kernel()},
m_map_physical_memory_lock{system_.Kernel()}, m_system{system_}, m_kernel{system_.Kernel()} {}
m_map_physical_memory_lock{system_.Kernel()}, m_system{system_} {}
KPageTable::~KPageTable() = default;
@@ -373,7 +373,7 @@ Result KPageTable::MapProcessCode(VAddr addr, size_t num_pages, KMemoryState sta
m_memory_block_slab_manager);
// Allocate and open.
KPageGroup pg{m_kernel, m_block_info_manager};
KPageGroup pg;
R_TRY(m_system.Kernel().MemoryManager().AllocateAndOpen(
&pg, num_pages,
KMemoryManager::EncodeOption(KMemoryManager::Pool::Application, m_allocation_option)));
@@ -432,7 +432,7 @@ Result KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, size_t si
const size_t num_pages = size / PageSize;
// Create page groups for the memory being mapped.
KPageGroup pg{m_kernel, m_block_info_manager};
KPageGroup pg;
AddRegionToPages(src_address, num_pages, pg);
// Reprotect the source as kernel-read/not mapped.
@@ -593,7 +593,7 @@ Result KPageTable::MakePageGroup(KPageGroup& pg, VAddr addr, size_t num_pages) {
const size_t size = num_pages * PageSize;
// We're making a new group, not adding to an existing one.
R_UNLESS(pg.empty(), ResultInvalidCurrentMemory);
R_UNLESS(pg.Empty(), ResultInvalidCurrentMemory);
// Begin traversal.
Common::PageTable::TraversalContext context;
@@ -640,10 +640,11 @@ Result KPageTable::MakePageGroup(KPageGroup& pg, VAddr addr, size_t num_pages) {
R_SUCCEED();
}
bool KPageTable::IsValidPageGroup(const KPageGroup& pg, VAddr addr, size_t num_pages) {
bool KPageTable::IsValidPageGroup(const KPageGroup& pg_ll, VAddr addr, size_t num_pages) {
ASSERT(this->IsLockedByCurrentThread());
const size_t size = num_pages * PageSize;
const auto& pg = pg_ll.Nodes();
const auto& memory_layout = m_system.Kernel().MemoryLayout();
// Empty groups are necessarily invalid.
@@ -941,6 +942,9 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add
ON_RESULT_FAILURE {
if (cur_mapped_addr != dst_addr) {
// HACK: Manually close the pages.
HACK_ClosePages(dst_addr, (cur_mapped_addr - dst_addr) / PageSize);
ASSERT(Operate(dst_addr, (cur_mapped_addr - dst_addr) / PageSize,
KMemoryPermission::None, OperationType::Unmap)
.IsSuccess());
@@ -1016,6 +1020,9 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add
// Map the page.
R_TRY(Operate(cur_mapped_addr, 1, test_perm, OperationType::Map, start_partial_page));
// HACK: Manually open the pages.
HACK_OpenPages(start_partial_page, 1);
// Update tracking extents.
cur_mapped_addr += PageSize;
cur_block_addr += PageSize;
@@ -1044,6 +1051,9 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add
R_TRY(Operate(cur_mapped_addr, cur_block_size / PageSize, test_perm, OperationType::Map,
cur_block_addr));
// HACK: Manually open the pages.
HACK_OpenPages(cur_block_addr, cur_block_size / PageSize);
// Update tracking extents.
cur_mapped_addr += cur_block_size;
cur_block_addr = next_entry.phys_addr;
@@ -1063,6 +1073,9 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add
R_TRY(Operate(cur_mapped_addr, last_block_size / PageSize, test_perm, OperationType::Map,
cur_block_addr));
// HACK: Manually open the pages.
HACK_OpenPages(cur_block_addr, last_block_size / PageSize);
// Update tracking extents.
cur_mapped_addr += last_block_size;
cur_block_addr += last_block_size;
@@ -1094,6 +1107,9 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add
// Map the page.
R_TRY(Operate(cur_mapped_addr, 1, test_perm, OperationType::Map, end_partial_page));
// HACK: Manually open the pages.
HACK_OpenPages(end_partial_page, 1);
}
// Update memory blocks to reflect our changes
@@ -1195,6 +1211,9 @@ Result KPageTable::CleanupForIpcServer(VAddr address, size_t size, KMemoryState
const size_t aligned_size = aligned_end - aligned_start;
const size_t aligned_num_pages = aligned_size / PageSize;
// HACK: Manually close the pages.
HACK_ClosePages(aligned_start, aligned_num_pages);
// Unmap the pages.
R_TRY(Operate(aligned_start, aligned_num_pages, KMemoryPermission::None, OperationType::Unmap));
@@ -1482,6 +1501,17 @@ void KPageTable::CleanupForIpcClientOnServerSetupFailure([[maybe_unused]] PageLi
}
}
void KPageTable::HACK_OpenPages(PAddr phys_addr, size_t num_pages) {
m_system.Kernel().MemoryManager().OpenFirst(phys_addr, num_pages);
}
void KPageTable::HACK_ClosePages(VAddr virt_addr, size_t num_pages) {
for (size_t index = 0; index < num_pages; ++index) {
const auto paddr = GetPhysicalAddr(virt_addr + (index * PageSize));
m_system.Kernel().MemoryManager().Close(paddr, 1);
}
}
Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
// Lock the physical memory lock.
KScopedLightLock phys_lk(m_map_physical_memory_lock);
@@ -1542,7 +1572,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
// Allocate pages for the new memory.
KPageGroup pg{m_kernel, m_block_info_manager};
KPageGroup pg;
R_TRY(m_system.Kernel().MemoryManager().AllocateForProcess(
&pg, (size - mapped_size) / PageSize, m_allocate_option, 0, 0));
@@ -1620,7 +1650,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
KScopedPageTableUpdater updater(this);
// Prepare to iterate over the memory.
auto pg_it = pg.begin();
auto pg_it = pg.Nodes().begin();
PAddr pg_phys_addr = pg_it->GetAddress();
size_t pg_pages = pg_it->GetNumPages();
@@ -1650,6 +1680,9 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
last_unmap_address + 1 - cur_address) /
PageSize;
// HACK: Manually close the pages.
HACK_ClosePages(cur_address, cur_pages);
// Unmap.
ASSERT(Operate(cur_address, cur_pages, KMemoryPermission::None,
OperationType::Unmap)
@@ -1670,7 +1703,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
// Release any remaining unmapped memory.
m_system.Kernel().MemoryManager().OpenFirst(pg_phys_addr, pg_pages);
m_system.Kernel().MemoryManager().Close(pg_phys_addr, pg_pages);
for (++pg_it; pg_it != pg.end(); ++pg_it) {
for (++pg_it; pg_it != pg.Nodes().end(); ++pg_it) {
m_system.Kernel().MemoryManager().OpenFirst(pg_it->GetAddress(),
pg_it->GetNumPages());
m_system.Kernel().MemoryManager().Close(pg_it->GetAddress(),
@@ -1698,7 +1731,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
// Check if we're at the end of the physical block.
if (pg_pages == 0) {
// Ensure there are more pages to map.
ASSERT(pg_it != pg.end());
ASSERT(pg_it != pg.Nodes().end());
// Advance our physical block.
++pg_it;
@@ -1709,7 +1742,10 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
// Map whatever we can.
const size_t cur_pages = std::min(pg_pages, map_pages);
R_TRY(Operate(cur_address, cur_pages, KMemoryPermission::UserReadWrite,
OperationType::MapFirst, pg_phys_addr));
OperationType::Map, pg_phys_addr));
// HACK: Manually open the pages.
HACK_OpenPages(pg_phys_addr, cur_pages);
// Advance.
cur_address += cur_pages * PageSize;
@@ -1852,6 +1888,9 @@ Result KPageTable::UnmapPhysicalMemory(VAddr address, size_t size) {
last_address + 1 - cur_address) /
PageSize;
// HACK: Manually close the pages.
HACK_ClosePages(cur_address, cur_pages);
// Unmap.
ASSERT(Operate(cur_address, cur_pages, KMemoryPermission::None, OperationType::Unmap)
.IsSuccess());
@@ -1916,7 +1955,7 @@ Result KPageTable::MapMemory(VAddr dst_address, VAddr src_address, size_t size)
R_TRY(dst_allocator_result);
// Map the memory.
KPageGroup page_linked_list{m_kernel, m_block_info_manager};
KPageGroup page_linked_list;
const size_t num_pages{size / PageSize};
const KMemoryPermission new_src_perm = static_cast<KMemoryPermission>(
KMemoryPermission::KernelRead | KMemoryPermission::NotMapped);
@@ -1983,14 +2022,14 @@ Result KPageTable::UnmapMemory(VAddr dst_address, VAddr src_address, size_t size
num_dst_allocator_blocks);
R_TRY(dst_allocator_result);
KPageGroup src_pages{m_kernel, m_block_info_manager};
KPageGroup dst_pages{m_kernel, m_block_info_manager};
KPageGroup src_pages;
KPageGroup dst_pages;
const size_t num_pages{size / PageSize};
AddRegionToPages(src_address, num_pages, src_pages);
AddRegionToPages(dst_address, num_pages, dst_pages);
R_UNLESS(dst_pages.IsEquivalentTo(src_pages), ResultInvalidMemoryRegion);
R_UNLESS(dst_pages.IsEqual(src_pages), ResultInvalidMemoryRegion);
{
auto block_guard = detail::ScopeExit([&] { MapPages(dst_address, dst_pages, dst_perm); });
@@ -2021,7 +2060,7 @@ Result KPageTable::MapPages(VAddr addr, const KPageGroup& page_linked_list,
VAddr cur_addr{addr};
for (const auto& node : page_linked_list) {
for (const auto& node : page_linked_list.Nodes()) {
if (const auto result{
Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())};
result.IsError()) {
@@ -2121,7 +2160,7 @@ Result KPageTable::UnmapPages(VAddr addr, const KPageGroup& page_linked_list) {
VAddr cur_addr{addr};
for (const auto& node : page_linked_list) {
for (const auto& node : page_linked_list.Nodes()) {
if (const auto result{Operate(cur_addr, node.GetNumPages(), KMemoryPermission::None,
OperationType::Unmap)};
result.IsError()) {
@@ -2488,13 +2527,13 @@ Result KPageTable::SetHeapSize(VAddr* out, size_t size) {
R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
// Allocate pages for the heap extension.
KPageGroup pg{m_kernel, m_block_info_manager};
KPageGroup pg;
R_TRY(m_system.Kernel().MemoryManager().AllocateAndOpen(
&pg, allocation_size / PageSize,
KMemoryManager::EncodeOption(m_memory_pool, m_allocation_option)));
// Clear all the newly allocated pages.
for (const auto& it : pg) {
for (const auto& it : pg.Nodes()) {
std::memset(m_system.DeviceMemory().GetPointer<void>(it.GetAddress()), m_heap_fill_value,
it.GetSize());
}
@@ -2571,23 +2610,11 @@ ResultVal<VAddr> KPageTable::AllocateAndMapMemory(size_t needed_num_pages, size_
if (is_map_only) {
R_TRY(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr));
} else {
// Create a page group tohold the pages we allocate.
KPageGroup pg{m_kernel, m_block_info_manager};
R_TRY(m_system.Kernel().MemoryManager().AllocateAndOpen(
&pg, needed_num_pages,
KMemoryManager::EncodeOption(m_memory_pool, m_allocation_option)));
// Ensure that the page group is closed when we're done working with it.
SCOPE_EXIT({ pg.Close(); });
// Clear all pages.
for (const auto& it : pg) {
std::memset(m_system.DeviceMemory().GetPointer<void>(it.GetAddress()),
m_heap_fill_value, it.GetSize());
}
R_TRY(Operate(addr, needed_num_pages, pg, OperationType::MapGroup));
KPageGroup page_group;
R_TRY(m_system.Kernel().MemoryManager().AllocateForProcess(
&page_group, needed_num_pages,
KMemoryManager::EncodeOption(m_memory_pool, m_allocation_option), 0, 0));
R_TRY(Operate(addr, needed_num_pages, page_group, OperationType::MapGroup));
}
// Update the blocks.
@@ -2768,28 +2795,19 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, const KPageGroup& page_
ASSERT(num_pages > 0);
ASSERT(num_pages == page_group.GetNumPages());
switch (operation) {
case OperationType::MapGroup: {
// We want to maintain a new reference to every page in the group.
KScopedPageGroup spg(page_group);
for (const auto& node : page_group.Nodes()) {
const size_t size{node.GetNumPages() * PageSize};
for (const auto& node : page_group) {
const size_t size{node.GetNumPages() * PageSize};
// Map the pages.
switch (operation) {
case OperationType::MapGroup:
m_system.Memory().MapMemoryRegion(*m_page_table_impl, addr, size, node.GetAddress());
addr += size;
break;
default:
ASSERT(false);
break;
}
// We succeeded! We want to persist the reference to the pages.
spg.CancelClose();
break;
}
default:
ASSERT(false);
break;
addr += size;
}
R_SUCCEED();
@@ -2804,29 +2822,13 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, KMemoryPermission perm,
ASSERT(ContainsPages(addr, num_pages));
switch (operation) {
case OperationType::Unmap: {
// Ensure that any pages we track close on exit.
KPageGroup pages_to_close{m_kernel, this->GetBlockInfoManager()};
SCOPE_EXIT({ pages_to_close.CloseAndReset(); });
this->AddRegionToPages(addr, num_pages, pages_to_close);
case OperationType::Unmap:
m_system.Memory().UnmapRegion(*m_page_table_impl, addr, num_pages * PageSize);
break;
}
case OperationType::MapFirst:
case OperationType::Map: {
ASSERT(map_addr);
ASSERT(Common::IsAligned(map_addr, PageSize));
m_system.Memory().MapMemoryRegion(*m_page_table_impl, addr, num_pages * PageSize, map_addr);
// Open references to pages, if we should.
if (IsHeapPhysicalAddress(m_kernel.MemoryLayout(), map_addr)) {
if (operation == OperationType::MapFirst) {
m_kernel.MemoryManager().OpenFirst(map_addr, num_pages);
} else {
m_kernel.MemoryManager().Open(map_addr, num_pages);
}
}
break;
}
case OperationType::Separate: {
+4 -5
View File
@@ -107,10 +107,6 @@ public:
return *m_page_table_impl;
}
KBlockInfoManager* GetBlockInfoManager() {
return m_block_info_manager;
}
bool CanContain(VAddr addr, size_t size, KMemoryState state) const;
protected:
@@ -265,6 +261,10 @@ private:
void CleanupForIpcClientOnServerSetupFailure(PageLinkedList* page_list, VAddr address,
size_t size, KMemoryPermission prot_perm);
// HACK: These will be removed once we automatically manage page reference counts.
void HACK_OpenPages(PAddr phys_addr, size_t num_pages);
void HACK_ClosePages(VAddr virt_addr, size_t num_pages);
mutable KLightLock m_general_lock;
mutable KLightLock m_map_physical_memory_lock;
@@ -488,7 +488,6 @@ private:
std::unique_ptr<Common::PageTable> m_page_table_impl;
Core::System& m_system;
KernelCore& m_kernel;
};
} // namespace Kernel
+13 -6
View File
@@ -13,7 +13,10 @@
namespace Kernel {
KSharedMemory::KSharedMemory(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
KSharedMemory::~KSharedMemory() = default;
KSharedMemory::~KSharedMemory() {
kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemoryMax, size);
}
Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_,
Svc::MemoryPermission owner_permission_,
@@ -46,8 +49,7 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o
R_UNLESS(physical_address != 0, ResultOutOfMemory);
//! Insert the result into our page group.
page_group.emplace(kernel, &kernel.GetSystemSystemResource().GetBlockInfoManager());
page_group->AddBlock(physical_address, num_pages);
page_group.emplace(physical_address, num_pages);
// Commit our reservation.
memory_reservation.Commit();
@@ -60,7 +62,7 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o
is_initialized = true;
// Clear all pages in the memory.
for (const auto& block : *page_group) {
for (const auto& block : page_group->Nodes()) {
std::memset(device_memory_.GetPointer<void>(block.GetAddress()), 0, block.GetSize());
}
@@ -69,8 +71,13 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o
void KSharedMemory::Finalize() {
// Close and finalize the page group.
page_group->Close();
page_group->Finalize();
// page_group->Close();
// page_group->Finalize();
//! HACK: Manually close.
for (const auto& block : page_group->Nodes()) {
kernel.MemoryManager().Close(block.GetAddress(), block.GetNumPages());
}
// Release the memory reservation.
resource_limit->Release(LimitableResource::PhysicalMemoryMax, size);
-3
View File
@@ -14,7 +14,4 @@ constexpr std::size_t PageSize{1 << PageBits};
using Page = std::array<u8, PageSize>;
using KPhysicalAddress = PAddr;
using KProcessAddress = VAddr;
} // namespace Kernel
+1 -1
View File
@@ -1485,7 +1485,7 @@ static Result MapProcessMemory(Core::System& system, VAddr dst_address, Handle p
ResultInvalidMemoryRegion);
// Create a new page group.
KPageGroup pg{system.Kernel(), dst_pt.GetBlockInfoManager()};
KPageGroup pg;
R_TRY(src_pt.MakeAndOpenPageGroup(
std::addressof(pg), src_address, size / PageSize, KMemoryState::FlagCanMapProcess,
KMemoryState::FlagCanMapProcess, KMemoryPermission::None, KMemoryPermission::None,
+57 -31
View File
@@ -22,15 +22,19 @@ namespace {
namespace Service::NIFM {
// This is nn::nifm::RequestState
enum class RequestState : u32 {
NotSubmitted = 1,
Error = 1, ///< The duplicate 1 is intentional; it means both not submitted and error on HW.
Pending = 2,
Connected = 3,
Invalid = 1, ///< The duplicate 1 is intentional; it means both not submitted and error on HW.
OnHold = 2,
Accepted = 3,
Blocking = 4,
};
enum class InternetConnectionType : u8 {
WiFi = 1,
// This is nn::nifm::NetworkInterfaceType
enum class NetworkInterfaceType : u32 {
Invalid = 0,
WiFi_Ieee80211 = 1,
Ethernet = 2,
};
@@ -42,14 +46,23 @@ enum class InternetConnectionStatus : u8 {
Connected,
};
// This is nn::nifm::NetworkProfileType
enum class NetworkProfileType : u32 {
User,
SsidList,
Temporary,
};
// This is nn::nifm::IpAddressSetting
struct IpAddressSetting {
bool is_automatic{};
Network::IPv4Address current_address{};
Network::IPv4Address ip_address{};
Network::IPv4Address subnet_mask{};
Network::IPv4Address gateway{};
Network::IPv4Address default_gateway{};
};
static_assert(sizeof(IpAddressSetting) == 0xD, "IpAddressSetting has incorrect size.");
// This is nn::nifm::DnsSetting
struct DnsSetting {
bool is_automatic{};
Network::IPv4Address primary_dns{};
@@ -57,18 +70,26 @@ struct DnsSetting {
};
static_assert(sizeof(DnsSetting) == 0x9, "DnsSetting has incorrect size.");
// This is nn::nifm::AuthenticationSetting
struct AuthenticationSetting {
bool is_enabled{};
std::array<char, 0x20> user{};
std::array<char, 0x20> password{};
};
static_assert(sizeof(AuthenticationSetting) == 0x41, "AuthenticationSetting has incorrect size.");
// This is nn::nifm::ProxySetting
struct ProxySetting {
bool enabled{};
bool is_enabled{};
INSERT_PADDING_BYTES(1);
u16 port{};
std::array<char, 0x64> proxy_server{};
bool automatic_auth_enabled{};
std::array<char, 0x20> user{};
std::array<char, 0x20> password{};
AuthenticationSetting authentication{};
INSERT_PADDING_BYTES(1);
};
static_assert(sizeof(ProxySetting) == 0xAA, "ProxySetting has incorrect size.");
// This is nn::nifm::IpSettingData
struct IpSettingData {
IpAddressSetting ip_address_setting{};
DnsSetting dns_setting{};
@@ -101,6 +122,7 @@ static_assert(sizeof(NifmWirelessSettingData) == 0x70,
"NifmWirelessSettingData has incorrect size.");
#pragma pack(push, 1)
// This is nn::nifm::detail::sf::NetworkProfileData
struct SfNetworkProfileData {
IpSettingData ip_setting_data{};
u128 uuid{};
@@ -114,13 +136,14 @@ struct SfNetworkProfileData {
};
static_assert(sizeof(SfNetworkProfileData) == 0x17C, "SfNetworkProfileData has incorrect size.");
// This is nn::nifm::NetworkProfileData
struct NifmNetworkProfileData {
u128 uuid{};
std::array<char, 0x40> network_name{};
u32 unknown_1{};
u32 unknown_2{};
u8 unknown_3{};
u8 unknown_4{};
NetworkProfileType network_profile_type{};
NetworkInterfaceType network_interface_type{};
bool is_auto_connect{};
bool is_large_capacity{};
INSERT_PADDING_BYTES(2);
NifmWirelessSettingData wireless_setting_data{};
IpSettingData ip_setting_data{};
@@ -184,6 +207,7 @@ public:
event1 = CreateKEvent(service_context, "IRequest:Event1");
event2 = CreateKEvent(service_context, "IRequest:Event2");
state = RequestState::NotSubmitted;
}
~IRequest() override {
@@ -196,7 +220,7 @@ private:
LOG_WARNING(Service_NIFM, "(STUBBED) called");
if (state == RequestState::NotSubmitted) {
UpdateState(RequestState::Pending);
UpdateState(RequestState::OnHold);
}
IPC::ResponseBuilder rb{ctx, 2};
@@ -219,14 +243,14 @@ private:
switch (state) {
case RequestState::NotSubmitted:
return has_connection ? ResultSuccess : ResultNetworkCommunicationDisabled;
case RequestState::Pending:
case RequestState::OnHold:
if (has_connection) {
UpdateState(RequestState::Connected);
UpdateState(RequestState::Accepted);
} else {
UpdateState(RequestState::Error);
UpdateState(RequestState::Invalid);
}
return ResultPendingConnection;
case RequestState::Connected:
case RequestState::Accepted:
default:
return ResultSuccess;
}
@@ -338,9 +362,9 @@ void IGeneralService::GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
.ip_setting_data{
.ip_address_setting{
.is_automatic{true},
.current_address{Network::TranslateIPv4(net_iface->ip_address)},
.ip_address{Network::TranslateIPv4(net_iface->ip_address)},
.subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
.gateway{Network::TranslateIPv4(net_iface->gateway)},
.default_gateway{Network::TranslateIPv4(net_iface->gateway)},
},
.dns_setting{
.is_automatic{true},
@@ -348,12 +372,14 @@ void IGeneralService::GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
.secondary_dns{1, 0, 0, 1},
},
.proxy_setting{
.enabled{false},
.is_enabled{false},
.port{},
.proxy_server{},
.automatic_auth_enabled{},
.user{},
.password{},
.authentication{
.is_enabled{},
.user{},
.password{},
},
},
.mtu{1500},
},
@@ -370,7 +396,7 @@ void IGeneralService::GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
// When we're connected to a room, spoof the hosts IP address
if (auto room_member = network.GetRoomMember().lock()) {
if (room_member->IsConnected()) {
network_profile_data.ip_setting_data.ip_address_setting.current_address =
network_profile_data.ip_setting_data.ip_address_setting.ip_address =
room_member->GetFakeIpAddress();
}
}
@@ -444,9 +470,9 @@ void IGeneralService::GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) {
return IpConfigInfo{
.ip_address_setting{
.is_automatic{true},
.current_address{Network::TranslateIPv4(net_iface->ip_address)},
.ip_address{Network::TranslateIPv4(net_iface->ip_address)},
.subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
.gateway{Network::TranslateIPv4(net_iface->gateway)},
.default_gateway{Network::TranslateIPv4(net_iface->gateway)},
},
.dns_setting{
.is_automatic{true},
@@ -459,7 +485,7 @@ void IGeneralService::GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) {
// When we're connected to a room, spoof the hosts IP address
if (auto room_member = network.GetRoomMember().lock()) {
if (room_member->IsConnected()) {
ip_config_info.ip_address_setting.current_address = room_member->GetFakeIpAddress();
ip_config_info.ip_address_setting.ip_address = room_member->GetFakeIpAddress();
}
}
@@ -480,7 +506,7 @@ void IGeneralService::GetInternetConnectionStatus(Kernel::HLERequestContext& ctx
LOG_WARNING(Service_NIFM, "(STUBBED) called");
struct Output {
InternetConnectionType type{InternetConnectionType::WiFi};
u8 type{static_cast<u8>(NetworkInterfaceType::WiFi_Ieee80211)};
u8 wifi_strength{3};
InternetConnectionStatus state{InternetConnectionStatus::Connected};
};
-2
View File
@@ -1,8 +1,6 @@
# SPDX-FileCopyrightText: 2017 Citra Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)
add_executable(yuzu-room
precompiled_headers.h
yuzu_room.cpp
+10 -5
View File
@@ -4,14 +4,10 @@
add_library(input_common STATIC
drivers/camera.cpp
drivers/camera.h
drivers/gc_adapter.cpp
drivers/gc_adapter.h
drivers/keyboard.cpp
drivers/keyboard.h
drivers/mouse.cpp
drivers/mouse.h
drivers/sdl_driver.cpp
drivers/sdl_driver.h
drivers/tas_input.cpp
drivers/tas_input.h
drivers/touch_screen.cpp
@@ -62,8 +58,17 @@ if (ENABLE_SDL2)
target_compile_definitions(input_common PRIVATE HAVE_SDL2)
endif()
if (ENABLE_LIBUSB)
target_sources(input_common PRIVATE
drivers/gc_adapter.cpp
drivers/gc_adapter.h
)
target_link_libraries(input_common PRIVATE libusb::usb)
target_compile_definitions(input_common PRIVATE HAVE_LIBUSB)
endif()
create_target_directory_groups(input_common)
target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost libusb::usb)
target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost)
if (YUZU_USE_PRECOMPILED_HEADERS)
target_precompile_headers(input_common PRIVATE precompiled_headers.h)
+22 -2
View File
@@ -5,7 +5,6 @@
#include "common/input.h"
#include "common/param_package.h"
#include "input_common/drivers/camera.h"
#include "input_common/drivers/gc_adapter.h"
#include "input_common/drivers/keyboard.h"
#include "input_common/drivers/mouse.h"
#include "input_common/drivers/tas_input.h"
@@ -19,6 +18,10 @@
#include "input_common/input_mapping.h"
#include "input_common/input_poller.h"
#include "input_common/main.h"
#ifdef HAVE_LIBUSB
#include "input_common/drivers/gc_adapter.h"
#endif
#ifdef HAVE_SDL2
#include "input_common/drivers/sdl_driver.h"
#endif
@@ -45,7 +48,9 @@ struct InputSubsystem::Impl {
RegisterEngine("keyboard", keyboard);
RegisterEngine("mouse", mouse);
RegisterEngine("touch", touch_screen);
#ifdef HAVE_LIBUSB
RegisterEngine("gcpad", gcadapter);
#endif
RegisterEngine("cemuhookudp", udp_client);
RegisterEngine("tas", tas_input);
RegisterEngine("camera", camera);
@@ -72,7 +77,9 @@ struct InputSubsystem::Impl {
UnregisterEngine(keyboard);
UnregisterEngine(mouse);
UnregisterEngine(touch_screen);
#ifdef HAVE_LIBUSB
UnregisterEngine(gcadapter);
#endif
UnregisterEngine(udp_client);
UnregisterEngine(tas_input);
UnregisterEngine(camera);
@@ -95,8 +102,10 @@ struct InputSubsystem::Impl {
devices.insert(devices.end(), keyboard_devices.begin(), keyboard_devices.end());
auto mouse_devices = mouse->GetInputDevices();
devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end());
#ifdef HAVE_LIBUSB
auto gcadapter_devices = gcadapter->GetInputDevices();
devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end());
#endif
auto udp_devices = udp_client->GetInputDevices();
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
#ifdef HAVE_SDL2
@@ -119,9 +128,11 @@ struct InputSubsystem::Impl {
if (engine == mouse->GetEngineName()) {
return mouse;
}
#ifdef HAVE_LIBUSB
if (engine == gcadapter->GetEngineName()) {
return gcadapter;
}
#endif
if (engine == udp_client->GetEngineName()) {
return udp_client;
}
@@ -194,9 +205,11 @@ struct InputSubsystem::Impl {
if (engine == mouse->GetEngineName()) {
return true;
}
#ifdef HAVE_LIBUSB
if (engine == gcadapter->GetEngineName()) {
return true;
}
#endif
if (engine == udp_client->GetEngineName()) {
return true;
}
@@ -217,7 +230,9 @@ struct InputSubsystem::Impl {
void BeginConfiguration() {
keyboard->BeginConfiguration();
mouse->BeginConfiguration();
#ifdef HAVE_LIBUSB
gcadapter->BeginConfiguration();
#endif
udp_client->BeginConfiguration();
#ifdef HAVE_SDL2
sdl->BeginConfiguration();
@@ -227,7 +242,9 @@ struct InputSubsystem::Impl {
void EndConfiguration() {
keyboard->EndConfiguration();
mouse->EndConfiguration();
#ifdef HAVE_LIBUSB
gcadapter->EndConfiguration();
#endif
udp_client->EndConfiguration();
#ifdef HAVE_SDL2
sdl->EndConfiguration();
@@ -248,7 +265,6 @@ struct InputSubsystem::Impl {
std::shared_ptr<Keyboard> keyboard;
std::shared_ptr<Mouse> mouse;
std::shared_ptr<GCAdapter> gcadapter;
std::shared_ptr<TouchScreen> touch_screen;
std::shared_ptr<TasInput::Tas> tas_input;
std::shared_ptr<CemuhookUDP::UDPClient> udp_client;
@@ -256,6 +272,10 @@ struct InputSubsystem::Impl {
std::shared_ptr<VirtualAmiibo> virtual_amiibo;
std::shared_ptr<VirtualGamepad> virtual_gamepad;
#ifdef HAVE_LIBUSB
std::shared_ptr<GCAdapter> gcadapter;
#endif
#ifdef HAVE_SDL2
std::shared_ptr<SDLDriver> sdl;
#endif
@@ -137,6 +137,15 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal
case IR::Attribute::VertexId:
ctx.Add("MOV.F {}.x,{}.id;", inst, ctx.attrib_name);
break;
case IR::Attribute::BaseInstance:
ctx.Add("MOV.F {}.x,{}.baseInstance;", inst, ctx.attrib_name);
break;
case IR::Attribute::BaseVertex:
ctx.Add("MOV.F {}.x,{}.baseVertex;", inst, ctx.attrib_name);
break;
case IR::Attribute::DrawID:
ctx.Add("MOV.F {}.x,{}.draw.id;", inst, ctx.attrib_name);
break;
case IR::Attribute::FrontFace:
ctx.Add("CMP.F {}.x,{}.facing.x,0,-1;", inst, ctx.attrib_name);
break;
@@ -156,6 +165,15 @@ void EmitGetAttributeU32(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, S
case IR::Attribute::VertexId:
ctx.Add("MOV.S {}.x,{}.id;", inst, ctx.attrib_name);
break;
case IR::Attribute::BaseInstance:
ctx.Add("MOV.S {}.x,{}.baseInstance;", inst, ctx.attrib_name);
break;
case IR::Attribute::BaseVertex:
ctx.Add("MOV.S {}.x,{}.baseVertex;", inst, ctx.attrib_name);
break;
case IR::Attribute::DrawID:
ctx.Add("MOV.S {}.x,{}.draw.id;", inst, ctx.attrib_name);
break;
default:
throw NotImplementedException("Get U32 attribute {}", attr);
}
@@ -219,7 +219,7 @@ std::string EmitGLSL(const Profile& profile, const RuntimeInfo& runtime_info, IR
EmitContext ctx{program, bindings, profile, runtime_info};
Precolor(program);
EmitCode(ctx, program);
const std::string version{fmt::format("#version 450{}\n", GlslVersionSpecifier(ctx))};
const std::string version{fmt::format("#version 460{}\n", GlslVersionSpecifier(ctx))};
ctx.header.insert(0, version);
if (program.shared_memory_size > 0) {
const auto requested_size{program.shared_memory_size};
@@ -234,6 +234,15 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
case IR::Attribute::FrontFace:
ctx.AddF32("{}=itof(gl_FrontFacing?-1:0);", inst);
break;
case IR::Attribute::BaseInstance:
ctx.AddF32("{}=itof(gl_BaseInstance);", inst);
break;
case IR::Attribute::BaseVertex:
ctx.AddF32("{}=itof(gl_BaseVertex);", inst);
break;
case IR::Attribute::DrawID:
ctx.AddF32("{}=itof(gl_DrawID);", inst);
break;
default:
throw NotImplementedException("Get attribute {}", attr);
}
@@ -250,6 +259,15 @@ void EmitGetAttributeU32(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, s
case IR::Attribute::VertexId:
ctx.AddU32("{}=uint(gl_VertexID);", inst);
break;
case IR::Attribute::BaseInstance:
ctx.AddU32("{}=uint(gl_BaseInstance);", inst);
break;
case IR::Attribute::BaseVertex:
ctx.AddU32("{}=uint(gl_BaseVertex);", inst);
break;
case IR::Attribute::DrawID:
ctx.AddU32("{}=uint(gl_DrawID);", inst);
break;
default:
throw NotImplementedException("Get U32 attribute {}", attr);
}
@@ -339,6 +339,12 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_vertex)};
return ctx.OpBitcast(ctx.F32[1], ctx.OpISub(ctx.U32[1], index, base));
}
case IR::Attribute::BaseInstance:
return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.base_instance));
case IR::Attribute::BaseVertex:
return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.base_vertex));
case IR::Attribute::DrawID:
return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.draw_index));
case IR::Attribute::FrontFace:
return ctx.OpSelect(ctx.F32[1], ctx.OpLoad(ctx.U1, ctx.front_face),
ctx.OpBitcast(ctx.F32[1], ctx.Const(std::numeric_limits<u32>::max())),
@@ -380,6 +386,12 @@ Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, Id) {
const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_vertex)};
return ctx.OpISub(ctx.U32[1], index, base);
}
case IR::Attribute::BaseInstance:
return ctx.OpLoad(ctx.U32[1], ctx.base_instance);
case IR::Attribute::BaseVertex:
return ctx.OpLoad(ctx.U32[1], ctx.base_vertex);
case IR::Attribute::DrawID:
return ctx.OpLoad(ctx.U32[1], ctx.draw_index);
default:
throw NotImplementedException("Read U32 attribute {}", attr);
}
@@ -1379,18 +1379,31 @@ void EmitContext::DefineInputs(const IR::Program& program) {
if (loads[IR::Attribute::InstanceId]) {
if (profile.support_vertex_instance_id) {
instance_id = DefineInput(*this, U32[1], true, spv::BuiltIn::InstanceId);
if (loads[IR::Attribute::BaseInstance]) {
base_instance = DefineInput(*this, U32[1], true, spv::BuiltIn::BaseVertex);
}
} else {
instance_index = DefineInput(*this, U32[1], true, spv::BuiltIn::InstanceIndex);
base_instance = DefineInput(*this, U32[1], true, spv::BuiltIn::BaseInstance);
}
} else if (loads[IR::Attribute::BaseInstance]) {
base_instance = DefineInput(*this, U32[1], true, spv::BuiltIn::BaseInstance);
}
if (loads[IR::Attribute::VertexId]) {
if (profile.support_vertex_instance_id) {
vertex_id = DefineInput(*this, U32[1], true, spv::BuiltIn::VertexId);
if (loads[IR::Attribute::BaseVertex]) {
base_vertex = DefineInput(*this, U32[1], true, spv::BuiltIn::BaseVertex);
}
} else {
vertex_index = DefineInput(*this, U32[1], true, spv::BuiltIn::VertexIndex);
base_vertex = DefineInput(*this, U32[1], true, spv::BuiltIn::BaseVertex);
}
} else if (loads[IR::Attribute::BaseVertex]) {
base_vertex = DefineInput(*this, U32[1], true, spv::BuiltIn::BaseVertex);
}
if (loads[IR::Attribute::DrawID]) {
draw_index = DefineInput(*this, U32[1], true, spv::BuiltIn::DrawIndex);
}
if (loads[IR::Attribute::FrontFace]) {
front_face = DefineInput(*this, U1, true, spv::BuiltIn::FrontFacing);
@@ -218,6 +218,7 @@ public:
Id base_instance{};
Id vertex_id{};
Id vertex_index{};
Id draw_index{};
Id base_vertex{};
Id front_face{};
Id point_coord{};
+10
View File
@@ -34,6 +34,11 @@ public:
[[nodiscard]] virtual std::array<u32, 3> WorkgroupSize() const = 0;
[[nodiscard]] virtual bool HasHLEMacroState() const = 0;
[[nodiscard]] virtual std::optional<ReplaceConstant> GetReplaceConstBuffer(u32 bank,
u32 offset) = 0;
virtual void Dump(u64 hash) = 0;
[[nodiscard]] const ProgramHeader& SPH() const noexcept {
@@ -52,11 +57,16 @@ public:
return start_address;
}
[[nodiscard]] bool IsPropietaryDriver() const noexcept {
return is_propietary_driver;
}
protected:
ProgramHeader sph{};
std::array<u32, 8> gp_passthrough_mask{};
Stage stage{};
u32 start_address{};
bool is_propietary_driver{};
};
} // namespace Shader
@@ -446,6 +446,12 @@ std::string NameOf(Attribute attribute) {
return "ViewportMask";
case Attribute::FrontFace:
return "FrontFace";
case Attribute::BaseInstance:
return "BaseInstance";
case Attribute::BaseVertex:
return "BaseVertex";
case Attribute::DrawID:
return "DrawID";
}
return fmt::format("<reserved attribute {}>", static_cast<int>(attribute));
}
@@ -219,6 +219,11 @@ enum class Attribute : u64 {
FixedFncTexture9Q = 231,
ViewportMask = 232,
FrontFace = 255,
// Implementation attributes
BaseInstance = 256,
BaseVertex = 257,
DrawID = 258,
};
constexpr size_t NUM_GENERICS = 32;
@@ -294,6 +294,14 @@ F32 IREmitter::GetAttribute(IR::Attribute attribute, const U32& vertex) {
return Inst<F32>(Opcode::GetAttribute, attribute, vertex);
}
U32 IREmitter::GetAttributeU32(IR::Attribute attribute) {
return GetAttributeU32(attribute, Imm32(0));
}
U32 IREmitter::GetAttributeU32(IR::Attribute attribute, const U32& vertex) {
return Inst<U32>(Opcode::GetAttributeU32, attribute, vertex);
}
void IREmitter::SetAttribute(IR::Attribute attribute, const F32& value, const U32& vertex) {
Inst(Opcode::SetAttribute, attribute, value, vertex);
}
@@ -74,6 +74,8 @@ public:
[[nodiscard]] F32 GetAttribute(IR::Attribute attribute);
[[nodiscard]] F32 GetAttribute(IR::Attribute attribute, const U32& vertex);
[[nodiscard]] U32 GetAttributeU32(IR::Attribute attribute);
[[nodiscard]] U32 GetAttributeU32(IR::Attribute attribute, const U32& vertex);
void SetAttribute(IR::Attribute attribute, const F32& value, const U32& vertex);
[[nodiscard]] F32 GetAttributeIndexed(const U32& phys_address);
@@ -219,7 +219,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
}
Optimization::SsaRewritePass(program);
Optimization::ConstantPropagationPass(program);
Optimization::ConstantPropagationPass(env, program);
Optimization::PositionPass(env, program);
@@ -7,6 +7,7 @@
#include <type_traits>
#include "common/bit_cast.h"
#include "shader_recompiler/environment.h"
#include "shader_recompiler/exception.h"
#include "shader_recompiler/frontend/ir/ir_emitter.h"
#include "shader_recompiler/frontend/ir/value.h"
@@ -515,6 +516,9 @@ void FoldBitCast(IR::Inst& inst, IR::Opcode reverse) {
case IR::Attribute::PrimitiveId:
case IR::Attribute::InstanceId:
case IR::Attribute::VertexId:
case IR::Attribute::BaseVertex:
case IR::Attribute::BaseInstance:
case IR::Attribute::DrawID:
break;
default:
return;
@@ -644,7 +648,63 @@ void FoldFSwizzleAdd(IR::Block& block, IR::Inst& inst) {
}
}
void ConstantPropagation(IR::Block& block, IR::Inst& inst) {
void FoldConstBuffer(Environment& env, IR::Block& block, IR::Inst& inst) {
const IR::Value bank{inst.Arg(0)};
const IR::Value offset{inst.Arg(1)};
if (!bank.IsImmediate() || !offset.IsImmediate()) {
return;
}
const auto bank_value = bank.U32();
const auto offset_value = offset.U32();
auto replacement = env.GetReplaceConstBuffer(bank_value, offset_value);
if (!replacement) {
return;
}
const auto new_attribute = [replacement]() {
switch (*replacement) {
case ReplaceConstant::BaseInstance:
return IR::Attribute::BaseInstance;
case ReplaceConstant::BaseVertex:
return IR::Attribute::BaseVertex;
case ReplaceConstant::DrawID:
return IR::Attribute::DrawID;
default:
throw NotImplementedException("Not implemented replacement variable {}", *replacement);
}
}();
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
if (inst.GetOpcode() == IR::Opcode::GetCbufU32) {
inst.ReplaceUsesWith(ir.GetAttributeU32(new_attribute));
} else {
inst.ReplaceUsesWith(ir.GetAttribute(new_attribute));
}
}
void FoldDriverConstBuffer(Environment& env, IR::Block& block, IR::Inst& inst, u32 which_bank,
u32 offset_start = 0, u32 offset_end = std::numeric_limits<u16>::max()) {
const IR::Value bank{inst.Arg(0)};
const IR::Value offset{inst.Arg(1)};
if (!bank.IsImmediate() || !offset.IsImmediate()) {
return;
}
const auto bank_value = bank.U32();
if (bank_value != which_bank) {
return;
}
const auto offset_value = offset.U32();
if (offset_value < offset_start || offset_value >= offset_end) {
return;
}
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
if (inst.GetOpcode() == IR::Opcode::GetCbufU32) {
inst.ReplaceUsesWith(IR::Value{env.ReadCbufValue(bank_value, offset_value)});
} else {
inst.ReplaceUsesWith(
IR::Value{Common::BitCast<f32>(env.ReadCbufValue(bank_value, offset_value))});
}
}
void ConstantPropagation(Environment& env, IR::Block& block, IR::Inst& inst) {
switch (inst.GetOpcode()) {
case IR::Opcode::GetRegister:
return FoldGetRegister(inst);
@@ -789,18 +849,28 @@ void ConstantPropagation(IR::Block& block, IR::Inst& inst) {
IR::Opcode::CompositeInsertF16x4);
case IR::Opcode::FSwizzleAdd:
return FoldFSwizzleAdd(block, inst);
case IR::Opcode::GetCbufF32:
case IR::Opcode::GetCbufU32:
if (env.HasHLEMacroState()) {
FoldConstBuffer(env, block, inst);
}
if (env.IsPropietaryDriver()) {
FoldDriverConstBuffer(env, block, inst, 1);
}
break;
default:
break;
}
}
} // Anonymous namespace
void ConstantPropagationPass(IR::Program& program) {
void ConstantPropagationPass(Environment& env, IR::Program& program) {
const auto end{program.post_order_blocks.rend()};
for (auto it = program.post_order_blocks.rbegin(); it != end; ++it) {
IR::Block* const block{*it};
for (IR::Inst& inst : block->Instructions()) {
ConstantPropagation(*block, inst);
ConstantPropagation(env, *block, inst);
}
}
}
+1 -1
View File
@@ -13,7 +13,7 @@ struct HostTranslateInfo;
namespace Shader::Optimization {
void CollectShaderInfoPass(Environment& env, IR::Program& program);
void ConstantPropagationPass(IR::Program& program);
void ConstantPropagationPass(Environment& env, IR::Program& program);
void DeadCodeEliminationPass(IR::Program& program);
void GlobalMemoryToStorageBufferPass(IR::Program& program);
void IdentityRemovalPass(IR::Program& program);
+6
View File
@@ -16,6 +16,12 @@
namespace Shader {
enum class ReplaceConstant : u32 {
BaseInstance,
BaseVertex,
DrawID,
};
enum class TextureType : u32 {
Color1D,
ColorArray1D,
+1 -1
View File
@@ -11,7 +11,7 @@
namespace Shader {
struct VaryingState {
std::bitset<256> mask{};
std::bitset<512> mask{};
void Set(IR::Attribute attribute, bool state = true) {
mask[static_cast<size_t>(attribute)] = state;
+1
View File
@@ -7,6 +7,7 @@ add_executable(tests
common/fibers.cpp
common/host_memory.cpp
common/param_package.cpp
common/range_map.cpp
common/ring_buffer.cpp
common/scratch_buffer.cpp
common/unique_function.cpp
+70
View File
@@ -0,0 +1,70 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <stdexcept>
#include <catch2/catch.hpp>
#include "common/range_map.h"
enum class MappedEnum : u32 {
Invalid = 0,
Valid_1 = 1,
Valid_2 = 2,
Valid_3 = 3,
};
TEST_CASE("Range Map: Setup", "[video_core]") {
Common::RangeMap<u64, MappedEnum> my_map(MappedEnum::Invalid);
my_map.Map(3000, 3500, MappedEnum::Valid_1);
my_map.Unmap(3200, 3600);
my_map.Map(4000, 4500, MappedEnum::Valid_2);
my_map.Map(4200, 4400, MappedEnum::Valid_2);
my_map.Map(4200, 4400, MappedEnum::Valid_1);
REQUIRE(my_map.GetContinousSizeFrom(4200) == 200);
REQUIRE(my_map.GetContinousSizeFrom(3000) == 200);
REQUIRE(my_map.GetContinousSizeFrom(2900) == 0);
REQUIRE(my_map.GetValueAt(2900) == MappedEnum::Invalid);
REQUIRE(my_map.GetValueAt(3100) == MappedEnum::Valid_1);
REQUIRE(my_map.GetValueAt(3000) == MappedEnum::Valid_1);
REQUIRE(my_map.GetValueAt(3200) == MappedEnum::Invalid);
REQUIRE(my_map.GetValueAt(4199) == MappedEnum::Valid_2);
REQUIRE(my_map.GetValueAt(4200) == MappedEnum::Valid_1);
REQUIRE(my_map.GetValueAt(4400) == MappedEnum::Valid_2);
REQUIRE(my_map.GetValueAt(4500) == MappedEnum::Invalid);
REQUIRE(my_map.GetValueAt(4600) == MappedEnum::Invalid);
my_map.Unmap(0, 6000);
for (u64 address = 0; address < 10000; address += 1000) {
REQUIRE(my_map.GetContinousSizeFrom(address) == 0);
}
my_map.Map(1000, 3000, MappedEnum::Valid_1);
my_map.Map(4000, 5000, MappedEnum::Valid_1);
my_map.Map(2500, 4100, MappedEnum::Valid_1);
REQUIRE(my_map.GetContinousSizeFrom(1000) == 4000);
my_map.Map(1000, 3000, MappedEnum::Valid_1);
my_map.Map(4000, 5000, MappedEnum::Valid_2);
my_map.Map(2500, 4100, MappedEnum::Valid_3);
REQUIRE(my_map.GetContinousSizeFrom(1000) == 1500);
REQUIRE(my_map.GetContinousSizeFrom(2500) == 1600);
REQUIRE(my_map.GetContinousSizeFrom(4100) == 900);
REQUIRE(my_map.GetValueAt(900) == MappedEnum::Invalid);
REQUIRE(my_map.GetValueAt(1000) == MappedEnum::Valid_1);
REQUIRE(my_map.GetValueAt(2500) == MappedEnum::Valid_3);
REQUIRE(my_map.GetValueAt(4100) == MappedEnum::Valid_2);
REQUIRE(my_map.GetValueAt(5000) == MappedEnum::Invalid);
my_map.Map(2000, 6000, MappedEnum::Valid_3);
REQUIRE(my_map.GetContinousSizeFrom(1000) == 1000);
REQUIRE(my_map.GetContinousSizeFrom(3000) == 3000);
REQUIRE(my_map.GetValueAt(1000) == MappedEnum::Valid_1);
REQUIRE(my_map.GetValueAt(1999) == MappedEnum::Valid_1);
REQUIRE(my_map.GetValueAt(1500) == MappedEnum::Valid_1);
REQUIRE(my_map.GetValueAt(2001) == MappedEnum::Valid_3);
REQUIRE(my_map.GetValueAt(5999) == MappedEnum::Valid_3);
REQUIRE(my_map.GetValueAt(6000) == MappedEnum::Invalid);
}
+3
View File
@@ -13,6 +13,7 @@ add_library(video_core STATIC
buffer_cache/buffer_base.h
buffer_cache/buffer_cache.cpp
buffer_cache/buffer_cache.h
cache_types.h
cdma_pusher.cpp
cdma_pusher.h
compatible_formats.cpp
@@ -98,6 +99,8 @@ add_library(video_core STATIC
renderer_null/null_rasterizer.h
renderer_null/renderer_null.cpp
renderer_null/renderer_null.h
renderer_opengl/blit_image.cpp
renderer_opengl/blit_image.h
renderer_opengl/gl_buffer_cache.cpp
renderer_opengl/gl_buffer_cache.h
renderer_opengl/gl_compute_pipeline.cpp
+73 -3
View File
@@ -200,7 +200,16 @@ public:
/// Return true when a CPU region is modified from the CPU
[[nodiscard]] bool IsRegionCpuModified(VAddr addr, size_t size);
std::mutex mutex;
void SetDrawIndirect(
const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect_) {
current_draw_indirect = current_draw_indirect_;
}
[[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectCount();
[[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectBuffer();
std::recursive_mutex mutex;
Runtime& runtime;
private:
@@ -272,6 +281,8 @@ private:
void BindHostVertexBuffers();
void BindHostDrawIndirectBuffers();
void BindHostGraphicsUniformBuffers(size_t stage);
void BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32 binding_index, bool needs_bind);
@@ -298,6 +309,8 @@ private:
void UpdateVertexBuffer(u32 index);
void UpdateDrawIndirect();
void UpdateUniformBuffers(size_t stage);
void UpdateStorageBuffers(size_t stage);
@@ -372,6 +385,8 @@ private:
SlotVector<Buffer> slot_buffers;
DelayedDestructionRing<Buffer, 8> delayed_destruction_ring;
const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect{};
u32 last_index_count = 0;
Binding index_buffer;
@@ -380,6 +395,8 @@ private:
std::array<std::array<Binding, NUM_STORAGE_BUFFERS>, NUM_STAGES> storage_buffers;
std::array<std::array<TextureBufferBinding, NUM_TEXTURE_BUFFERS>, NUM_STAGES> texture_buffers;
std::array<Binding, NUM_TRANSFORM_FEEDBACK_BUFFERS> transform_feedback_buffers;
Binding count_buffer_binding;
Binding indirect_buffer_binding;
std::array<Binding, NUM_COMPUTE_UNIFORM_BUFFERS> compute_uniform_buffers;
std::array<Binding, NUM_STORAGE_BUFFERS> compute_storage_buffers;
@@ -674,6 +691,9 @@ void BufferCache<P>::BindHostGeometryBuffers(bool is_indexed) {
}
BindHostVertexBuffers();
BindHostTransformFeedbackBuffers();
if (current_draw_indirect) {
BindHostDrawIndirectBuffers();
}
}
template <class P>
@@ -823,6 +843,7 @@ bool BufferCache<P>::ShouldWaitAsyncFlushes() const noexcept {
template <class P>
void BufferCache<P>::CommitAsyncFlushesHigh() {
AccumulateFlushes();
if (committed_ranges.empty()) {
return;
}
@@ -869,7 +890,7 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
buffer_id,
});
// Align up to avoid cache conflicts
constexpr u64 align = 256ULL;
constexpr u64 align = 8ULL;
constexpr u64 mask = ~(align - 1ULL);
total_size_bytes += (new_size + align - 1) & mask;
largest_copy = std::max(largest_copy, new_size);
@@ -1041,6 +1062,19 @@ void BufferCache<P>::BindHostVertexBuffers() {
}
}
template <class P>
void BufferCache<P>::BindHostDrawIndirectBuffers() {
const auto bind_buffer = [this](const Binding& binding) {
Buffer& buffer = slot_buffers[binding.buffer_id];
TouchBuffer(buffer, binding.buffer_id);
SynchronizeBuffer(buffer, binding.cpu_addr, binding.size);
};
if (current_draw_indirect->include_count) {
bind_buffer(count_buffer_binding);
}
bind_buffer(indirect_buffer_binding);
}
template <class P>
void BufferCache<P>::BindHostGraphicsUniformBuffers(size_t stage) {
u32 dirty = ~0U;
@@ -1272,6 +1306,9 @@ void BufferCache<P>::DoUpdateGraphicsBuffers(bool is_indexed) {
UpdateStorageBuffers(stage);
UpdateTextureBuffers(stage);
}
if (current_draw_indirect) {
UpdateDrawIndirect();
}
} while (has_deleted_buffers);
}
@@ -1289,7 +1326,7 @@ void BufferCache<P>::UpdateIndexBuffer() {
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
const auto& index_array = draw_state.index_buffer;
auto& flags = maxwell3d->dirty.flags;
if (!flags[Dirty::IndexBuffer] && last_index_count == index_array.count) {
if (!flags[Dirty::IndexBuffer]) {
return;
}
flags[Dirty::IndexBuffer] = false;
@@ -1361,6 +1398,27 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) {
};
}
template <class P>
void BufferCache<P>::UpdateDrawIndirect() {
const auto update = [this](GPUVAddr gpu_addr, size_t size, Binding& binding) {
const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
if (!cpu_addr) {
binding = NULL_BINDING;
return;
}
binding = Binding{
.cpu_addr = *cpu_addr,
.size = static_cast<u32>(size),
.buffer_id = FindBuffer(*cpu_addr, static_cast<u32>(size)),
};
};
if (current_draw_indirect->include_count) {
update(current_draw_indirect->count_start_address, sizeof(u32), count_buffer_binding);
}
update(current_draw_indirect->indirect_start_address, current_draw_indirect->buffer_size,
indirect_buffer_binding);
}
template <class P>
void BufferCache<P>::UpdateUniformBuffers(size_t stage) {
ForEachEnabledBit(enabled_uniform_buffer_masks[stage], [&](u32 index) {
@@ -1941,4 +1999,16 @@ bool BufferCache<P>::HasFastUniformBufferBound(size_t stage, u32 binding_index)
}
}
template <class P>
std::pair<typename BufferCache<P>::Buffer*, u32> BufferCache<P>::GetDrawIndirectCount() {
auto& buffer = slot_buffers[count_buffer_binding.buffer_id];
return std::make_pair(&buffer, buffer.Offset(count_buffer_binding.cpu_addr));
}
template <class P>
std::pair<typename BufferCache<P>::Buffer*, u32> BufferCache<P>::GetDrawIndirectBuffer() {
auto& buffer = slot_buffers[indirect_buffer_binding.buffer_id];
return std::make_pair(&buffer, buffer.Offset(indirect_buffer_binding.cpu_addr));
}
} // namespace VideoCommon
+24
View File
@@ -0,0 +1,24 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace VideoCommon {
enum class CacheType : u32 {
None = 0,
TextureCache = 1 << 0,
QueryCache = 1 << 1,
BufferCache = 1 << 2,
ShaderCache = 1 << 3,
NoTextureCache = QueryCache | BufferCache | ShaderCache,
NoBufferCache = TextureCache | QueryCache | ShaderCache,
NoQueryCache = TextureCache | BufferCache | ShaderCache,
All = TextureCache | QueryCache | BufferCache | ShaderCache,
};
DECLARE_ENUM_FLAG_OPERATORS(CacheType)
} // namespace VideoCommon
+32 -10
View File
@@ -61,7 +61,7 @@ bool DmaPusher::Step() {
} else {
const CommandListHeader command_list_header{
command_list.command_lists[dma_pushbuffer_subindex++]};
const GPUVAddr dma_get = command_list_header.addr;
dma_state.dma_get = command_list_header.addr;
if (dma_pushbuffer_subindex >= command_list.command_lists.size()) {
// We've gone through the current list, remove it from the queue
@@ -75,12 +75,22 @@ bool DmaPusher::Step() {
// Push buffer non-empty, read a word
command_headers.resize_destructive(command_list_header.size);
if (Settings::IsGPULevelHigh()) {
memory_manager.ReadBlock(dma_get, command_headers.data(),
command_list_header.size * sizeof(u32));
constexpr u32 MacroRegistersStart = 0xE00;
if (dma_state.method < MacroRegistersStart) {
if (Settings::IsGPULevelHigh()) {
memory_manager.ReadBlock(dma_state.dma_get, command_headers.data(),
command_list_header.size * sizeof(u32));
} else {
memory_manager.ReadBlockUnsafe(dma_state.dma_get, command_headers.data(),
command_list_header.size * sizeof(u32));
}
} else {
memory_manager.ReadBlockUnsafe(dma_get, command_headers.data(),
command_list_header.size * sizeof(u32));
const size_t copy_size = command_list_header.size * sizeof(u32);
if (subchannels[dma_state.subchannel]) {
subchannels[dma_state.subchannel]->current_dirty =
memory_manager.IsMemoryDirty(dma_state.dma_get, copy_size);
}
memory_manager.ReadBlockUnsafe(dma_state.dma_get, command_headers.data(), copy_size);
}
ProcessCommands(command_headers);
}
@@ -94,6 +104,7 @@ void DmaPusher::ProcessCommands(std::span<const CommandHeader> commands) {
if (dma_state.method_count) {
// Data word of methods command
dma_state.dma_word_offset = static_cast<u32>(index * sizeof(u32));
if (dma_state.non_incrementing) {
const u32 max_write = static_cast<u32>(
std::min<std::size_t>(index + dma_state.method_count, commands.size()) - index);
@@ -132,6 +143,8 @@ void DmaPusher::ProcessCommands(std::span<const CommandHeader> commands) {
case SubmissionMode::Inline:
dma_state.method = command_header.method;
dma_state.subchannel = command_header.subchannel;
dma_state.dma_word_offset = static_cast<u64>(
-static_cast<s64>(dma_state.dma_get)); // negate to set address as 0
CallMethod(command_header.arg_count);
dma_state.non_incrementing = true;
dma_increment_once = false;
@@ -164,8 +177,14 @@ void DmaPusher::CallMethod(u32 argument) const {
dma_state.method_count,
});
} else {
subchannels[dma_state.subchannel]->CallMethod(dma_state.method, argument,
dma_state.is_last_call);
auto subchannel = subchannels[dma_state.subchannel];
if (!subchannel->execution_mask[dma_state.method]) [[likely]] {
subchannel->method_sink.emplace_back(dma_state.method, argument);
return;
}
subchannel->ConsumeSink();
subchannel->current_dma_segment = dma_state.dma_get + dma_state.dma_word_offset;
subchannel->CallMethod(dma_state.method, argument, dma_state.is_last_call);
}
}
@@ -174,8 +193,11 @@ void DmaPusher::CallMultiMethod(const u32* base_start, u32 num_methods) const {
puller.CallMultiMethod(dma_state.method, dma_state.subchannel, base_start, num_methods,
dma_state.method_count);
} else {
subchannels[dma_state.subchannel]->CallMultiMethod(dma_state.method, base_start,
num_methods, dma_state.method_count);
auto subchannel = subchannels[dma_state.subchannel];
subchannel->ConsumeSink();
subchannel->current_dma_segment = dma_state.dma_get + dma_state.dma_word_offset;
subchannel->CallMultiMethod(dma_state.method, base_start, num_methods,
dma_state.method_count);
}
}
+2
View File
@@ -156,6 +156,8 @@ private:
u32 subchannel; ///< Current subchannel
u32 method_count; ///< Current method count
u32 length_pending; ///< Large NI command length pending
GPUVAddr dma_get; ///< Currently read segment
u64 dma_word_offset; ///< Current word ofset from address
bool non_incrementing; ///< Current command's NI flag
bool is_last_call;
};
+62
View File
@@ -51,6 +51,10 @@ void DrawManager::ProcessMethodCall(u32 method, u32 argument) {
LOG_WARNING(HW_GPU, "(STUBBED) called");
break;
}
case MAXWELL3D_REG_INDEX(draw_texture.src_y0): {
DrawTexture();
break;
}
default:
break;
}
@@ -91,6 +95,23 @@ void DrawManager::DrawIndex(PrimitiveTopology topology, u32 index_first, u32 ind
ProcessDraw(true, num_instances);
}
void DrawManager::DrawArrayIndirect(PrimitiveTopology topology) {
draw_state.topology = topology;
ProcessDrawIndirect();
}
void DrawManager::DrawIndexedIndirect(PrimitiveTopology topology, u32 index_first,
u32 index_count) {
const auto& regs{maxwell3d->regs};
draw_state.topology = topology;
draw_state.index_buffer = regs.index_buffer;
draw_state.index_buffer.first = index_first;
draw_state.index_buffer.count = index_count;
ProcessDrawIndirect();
}
void DrawManager::SetInlineIndexBuffer(u32 index) {
draw_state.inline_index_draw_indexes.push_back(static_cast<u8>(index & 0x000000ff));
draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x0000ff00) >> 8));
@@ -162,6 +183,33 @@ void DrawManager::DrawIndexSmall(u32 argument) {
ProcessDraw(true, 1);
}
void DrawManager::DrawTexture() {
const auto& regs{maxwell3d->regs};
draw_texture_state.dst_x0 = static_cast<float>(regs.draw_texture.dst_x0) / 4096.f;
draw_texture_state.dst_y0 = static_cast<float>(regs.draw_texture.dst_y0) / 4096.f;
const auto dst_width = static_cast<float>(regs.draw_texture.dst_width) / 4096.f;
const auto dst_height = static_cast<float>(regs.draw_texture.dst_height) / 4096.f;
const bool lower_left{regs.window_origin.mode !=
Maxwell3D::Regs::WindowOrigin::Mode::UpperLeft};
if (lower_left) {
draw_texture_state.dst_y0 -= dst_height;
}
draw_texture_state.dst_x1 = draw_texture_state.dst_x0 + dst_width;
draw_texture_state.dst_y1 = draw_texture_state.dst_y0 + dst_height;
draw_texture_state.src_x0 = static_cast<float>(regs.draw_texture.src_x0) / 4096.f;
draw_texture_state.src_y0 = static_cast<float>(regs.draw_texture.src_y0) / 4096.f;
draw_texture_state.src_x1 =
(static_cast<float>(regs.draw_texture.dx_du) / 4294967295.f) * dst_width +
draw_texture_state.src_x0;
draw_texture_state.src_y1 =
(static_cast<float>(regs.draw_texture.dy_dv) / 4294967295.f) * dst_height +
draw_texture_state.src_y0;
draw_texture_state.src_sampler = regs.draw_texture.src_sampler;
draw_texture_state.src_texture = regs.draw_texture.src_texture;
maxwell3d->rasterizer->DrawTexture();
}
void DrawManager::UpdateTopology() {
const auto& regs{maxwell3d->regs};
switch (regs.primitive_topology_control) {
@@ -198,4 +246,18 @@ void DrawManager::ProcessDraw(bool draw_indexed, u32 instance_count) {
maxwell3d->rasterizer->Draw(draw_indexed, instance_count);
}
}
void DrawManager::ProcessDrawIndirect() {
LOG_TRACE(
HW_GPU,
"called, topology={}, is_indexed={}, includes_count={}, buffer_size={}, max_draw_count={}",
draw_state.topology, indirect_state.is_indexed, indirect_state.include_count,
indirect_state.buffer_size, indirect_state.max_draw_counts);
UpdateTopology();
if (maxwell3d->ShouldExecute()) {
maxwell3d->rasterizer->DrawIndirect();
}
}
} // namespace Tegra::Engines
+45
View File
@@ -32,6 +32,29 @@ public:
std::vector<u8> inline_index_draw_indexes;
};
struct DrawTextureState {
f32 dst_x0;
f32 dst_y0;
f32 dst_x1;
f32 dst_y1;
f32 src_x0;
f32 src_y0;
f32 src_x1;
f32 src_y1;
u32 src_sampler;
u32 src_texture;
};
struct IndirectParams {
bool is_indexed;
bool include_count;
GPUVAddr count_start_address;
GPUVAddr indirect_start_address;
size_t buffer_size;
size_t max_draw_counts;
size_t stride;
};
explicit DrawManager(Maxwell3D* maxwell_3d);
void ProcessMethodCall(u32 method, u32 argument);
@@ -46,10 +69,26 @@ public:
void DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index,
u32 base_instance, u32 num_instances);
void DrawArrayIndirect(PrimitiveTopology topology);
void DrawIndexedIndirect(PrimitiveTopology topology, u32 index_first, u32 index_count);
const State& GetDrawState() const {
return draw_state;
}
const DrawTextureState& GetDrawTextureState() const {
return draw_texture_state;
}
IndirectParams& GetIndirectParams() {
return indirect_state;
}
const IndirectParams& GetIndirectParams() const {
return indirect_state;
}
private:
void SetInlineIndexBuffer(u32 index);
@@ -59,11 +98,17 @@ private:
void DrawIndexSmall(u32 argument);
void DrawTexture();
void UpdateTopology();
void ProcessDraw(bool draw_indexed, u32 instance_count);
void ProcessDrawIndirect();
Maxwell3D* maxwell3d{};
State draw_state{};
DrawTextureState draw_texture_state{};
IndirectParams indirect_state{};
};
} // namespace Tegra::Engines
+24
View File
@@ -3,6 +3,10 @@
#pragma once
#include <bitset>
#include <limits>
#include <vector>
#include "common/common_types.h"
namespace Tegra::Engines {
@@ -17,6 +21,26 @@ public:
/// Write multiple values to the register identified by method.
virtual void CallMultiMethod(u32 method, const u32* base_start, u32 amount,
u32 methods_pending) = 0;
void ConsumeSink() {
if (method_sink.empty()) {
return;
}
ConsumeSinkImpl();
}
std::bitset<std::numeric_limits<u16>::max()> execution_mask{};
std::vector<std::pair<u32, u32>> method_sink{};
bool current_dirty{};
GPUVAddr current_dma_segment;
protected:
virtual void ConsumeSinkImpl() {
for (auto [method, value] : method_sink) {
CallMethod(method, value, true);
}
method_sink.clear();
}
};
} // namespace Tegra::Engines
+10
View File
@@ -25,6 +25,9 @@ Fermi2D::Fermi2D(MemoryManager& memory_manager_) {
// Nvidia's OpenGL driver seems to assume these values
regs.src.depth = 1;
regs.dst.depth = 1;
execution_mask.reset();
execution_mask[FERMI2D_REG_INDEX(pixels_from_memory.src_y0) + 1] = true;
}
Fermi2D::~Fermi2D() = default;
@@ -49,6 +52,13 @@ void Fermi2D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, u32
}
}
void Fermi2D::ConsumeSinkImpl() {
for (auto [method, value] : method_sink) {
regs.reg_array[method] = value;
}
method_sink.clear();
}
void Fermi2D::Blit() {
MICROPROFILE_SCOPE(GPU_BlitEngine);
LOG_DEBUG(HW_GPU, "called. source address=0x{:x}, destination address=0x{:x}",
+2
View File
@@ -309,6 +309,8 @@ private:
/// Performs the copy from the source surface to the destination surface as configured in the
/// registers.
void Blit();
void ConsumeSinkImpl() override;
};
#define ASSERT_REG_POSITION(field_name, position) \
+13 -1
View File
@@ -14,7 +14,12 @@
namespace Tegra::Engines {
KeplerCompute::KeplerCompute(Core::System& system_, MemoryManager& memory_manager_)
: system{system_}, memory_manager{memory_manager_}, upload_state{memory_manager, regs.upload} {}
: system{system_}, memory_manager{memory_manager_}, upload_state{memory_manager, regs.upload} {
execution_mask.reset();
execution_mask[KEPLER_COMPUTE_REG_INDEX(exec_upload)] = true;
execution_mask[KEPLER_COMPUTE_REG_INDEX(data_upload)] = true;
execution_mask[KEPLER_COMPUTE_REG_INDEX(launch)] = true;
}
KeplerCompute::~KeplerCompute() = default;
@@ -23,6 +28,13 @@ void KeplerCompute::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_)
upload_state.BindRasterizer(rasterizer);
}
void KeplerCompute::ConsumeSinkImpl() {
for (auto [method, value] : method_sink) {
regs.reg_array[method] = value;
}
method_sink.clear();
}
void KeplerCompute::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
ASSERT_MSG(method < Regs::NUM_REGS,
"Invalid KeplerCompute register, increase the size of the Regs structure");
+2
View File
@@ -204,6 +204,8 @@ public:
private:
void ProcessLaunch();
void ConsumeSinkImpl() override;
/// Retrieves information about a specific TIC entry from the TIC buffer.
Texture::TICEntry GetTICEntry(u32 tic_index) const;
+11
View File
@@ -18,6 +18,17 @@ KeplerMemory::~KeplerMemory() = default;
void KeplerMemory::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
upload_state.BindRasterizer(rasterizer_);
execution_mask.reset();
execution_mask[KEPLERMEMORY_REG_INDEX(exec)] = true;
execution_mask[KEPLERMEMORY_REG_INDEX(data)] = true;
}
void KeplerMemory::ConsumeSinkImpl() {
for (auto [method, value] : method_sink) {
regs.reg_array[method] = value;
}
method_sink.clear();
}
void KeplerMemory::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
+2
View File
@@ -73,6 +73,8 @@ public:
} regs{};
private:
void ConsumeSinkImpl() override;
Core::System& system;
Upload::State upload_state;
};
+169 -4
View File
@@ -4,6 +4,8 @@
#include <cstring>
#include <optional>
#include "common/assert.h"
#include "common/scope_exit.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "video_core/dirty_flags.h"
@@ -28,6 +30,10 @@ Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_)
regs.upload} {
dirty.flags.flip();
InitializeRegisterDefaults();
execution_mask.reset();
for (size_t i = 0; i < execution_mask.size(); i++) {
execution_mask[i] = IsMethodExecutable(static_cast<u32>(i));
}
}
Maxwell3D::~Maxwell3D() = default;
@@ -121,6 +127,71 @@ void Maxwell3D::InitializeRegisterDefaults() {
shadow_state = regs;
}
bool Maxwell3D::IsMethodExecutable(u32 method) {
if (method >= MacroRegistersStart) {
return true;
}
switch (method) {
case MAXWELL3D_REG_INDEX(draw.end):
case MAXWELL3D_REG_INDEX(draw.begin):
case MAXWELL3D_REG_INDEX(vertex_buffer.first):
case MAXWELL3D_REG_INDEX(vertex_buffer.count):
case MAXWELL3D_REG_INDEX(index_buffer.first):
case MAXWELL3D_REG_INDEX(index_buffer.count):
case MAXWELL3D_REG_INDEX(draw_inline_index):
case MAXWELL3D_REG_INDEX(index_buffer32_subsequent):
case MAXWELL3D_REG_INDEX(index_buffer16_subsequent):
case MAXWELL3D_REG_INDEX(index_buffer8_subsequent):
case MAXWELL3D_REG_INDEX(index_buffer32_first):
case MAXWELL3D_REG_INDEX(index_buffer16_first):
case MAXWELL3D_REG_INDEX(index_buffer8_first):
case MAXWELL3D_REG_INDEX(inline_index_2x16.even):
case MAXWELL3D_REG_INDEX(inline_index_4x8.index0):
case MAXWELL3D_REG_INDEX(vertex_array_instance_first):
case MAXWELL3D_REG_INDEX(vertex_array_instance_subsequent):
case MAXWELL3D_REG_INDEX(wait_for_idle):
case MAXWELL3D_REG_INDEX(shadow_ram_control):
case MAXWELL3D_REG_INDEX(load_mme.instruction_ptr):
case MAXWELL3D_REG_INDEX(load_mme.instruction):
case MAXWELL3D_REG_INDEX(load_mme.start_address):
case MAXWELL3D_REG_INDEX(falcon[4]):
case MAXWELL3D_REG_INDEX(const_buffer.buffer):
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 1:
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 2:
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 3:
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 4:
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 5:
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 6:
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 7:
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 8:
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 9:
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 10:
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 11:
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 12:
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 13:
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 14:
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 15:
case MAXWELL3D_REG_INDEX(bind_groups[0].raw_config):
case MAXWELL3D_REG_INDEX(bind_groups[1].raw_config):
case MAXWELL3D_REG_INDEX(bind_groups[2].raw_config):
case MAXWELL3D_REG_INDEX(bind_groups[3].raw_config):
case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config):
case MAXWELL3D_REG_INDEX(topology_override):
case MAXWELL3D_REG_INDEX(clear_surface):
case MAXWELL3D_REG_INDEX(report_semaphore.query):
case MAXWELL3D_REG_INDEX(render_enable.mode):
case MAXWELL3D_REG_INDEX(clear_report_value):
case MAXWELL3D_REG_INDEX(sync_info):
case MAXWELL3D_REG_INDEX(launch_dma):
case MAXWELL3D_REG_INDEX(inline_data):
case MAXWELL3D_REG_INDEX(fragment_barrier):
case MAXWELL3D_REG_INDEX(tiled_cache_barrier):
return true;
default:
return false;
}
}
void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) {
if (executing_macro == 0) {
// A macro call must begin by writing the macro method's register, not its argument.
@@ -130,14 +201,72 @@ void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool
}
macro_params.insert(macro_params.end(), base_start, base_start + amount);
for (size_t i = 0; i < amount; i++) {
macro_addresses.push_back(current_dma_segment + i * sizeof(u32));
}
macro_segments.emplace_back(current_dma_segment, amount);
current_macro_dirty |= current_dirty;
current_dirty = false;
// Call the macro when there are no more parameters in the command buffer
if (is_last_call) {
ConsumeSink();
CallMacroMethod(executing_macro, macro_params);
macro_params.clear();
macro_addresses.clear();
macro_segments.clear();
current_macro_dirty = false;
}
}
void Maxwell3D::RefreshParametersImpl() {
size_t current_index = 0;
for (auto& segment : macro_segments) {
if (segment.first == 0) {
current_index += segment.second;
continue;
}
memory_manager.ReadBlock(segment.first, &macro_params[current_index],
sizeof(u32) * segment.second);
current_index += segment.second;
}
}
u32 Maxwell3D::GetMaxCurrentVertices() {
u32 num_vertices = 0;
for (size_t index = 0; index < Regs::NumVertexArrays; ++index) {
const auto& array = regs.vertex_streams[index];
if (array.enable == 0) {
continue;
}
const auto& attribute = regs.vertex_attrib_format[index];
if (attribute.constant) {
num_vertices = std::max(num_vertices, 1U);
continue;
}
const auto& limit = regs.vertex_stream_limits[index];
const GPUVAddr gpu_addr_begin = array.Address();
const GPUVAddr gpu_addr_end = limit.Address() + 1;
const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin);
num_vertices = std::max(
num_vertices, address_size / std::max(attribute.SizeInBytes(), array.stride.Value()));
}
return num_vertices;
}
size_t Maxwell3D::EstimateIndexBufferSize() {
GPUVAddr start_address = regs.index_buffer.StartAddress();
GPUVAddr end_address = regs.index_buffer.EndAddress();
constexpr std::array<size_t, 4> max_sizes = {
std::numeric_limits<u8>::max(), std::numeric_limits<u16>::max(),
std::numeric_limits<u32>::max(), std::numeric_limits<u32>::max()};
const size_t byte_size = regs.index_buffer.FormatSizeInBytes();
return std::min<size_t>(
memory_manager.GetMemoryLayoutSize(start_address, byte_size * max_sizes[byte_size]) /
byte_size,
static_cast<size_t>(end_address - start_address));
}
u32 Maxwell3D::ProcessShadowRam(u32 method, u32 argument) {
// Keep track of the register value in shadow_state when requested.
const auto control = shadow_state.shadow_ram_control;
@@ -152,6 +281,29 @@ u32 Maxwell3D::ProcessShadowRam(u32 method, u32 argument) {
return argument;
}
void Maxwell3D::ConsumeSinkImpl() {
SCOPE_EXIT({ method_sink.clear(); });
const auto control = shadow_state.shadow_ram_control;
if (control == Regs::ShadowRamControl::Track ||
control == Regs::ShadowRamControl::TrackWithFilter) {
for (auto [method, value] : method_sink) {
shadow_state.reg_array[method] = value;
ProcessDirtyRegisters(method, value);
}
return;
}
if (control == Regs::ShadowRamControl::Replay) {
for (auto [method, value] : method_sink) {
ProcessDirtyRegisters(method, shadow_state.reg_array[method]);
}
return;
}
for (auto [method, value] : method_sink) {
ProcessDirtyRegisters(method, value);
}
}
void Maxwell3D::ProcessDirtyRegisters(u32 method, u32 argument) {
if (regs.reg_array[method] == argument) {
return;
@@ -263,7 +415,6 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
const u32 argument = ProcessShadowRam(method, method_argument);
ProcessDirtyRegisters(method, argument);
ProcessMethodCall(method, argument, method_argument, is_last_call);
}
@@ -294,9 +445,11 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 15:
ProcessCBMultiData(base_start, amount);
break;
case MAXWELL3D_REG_INDEX(inline_data):
case MAXWELL3D_REG_INDEX(inline_data): {
ASSERT(methods_pending == amount);
upload_state.ProcessData(base_start, amount);
return;
}
default:
for (u32 i = 0; i < amount; i++) {
CallMethod(method, base_start[i], methods_pending - i <= 1);
@@ -389,7 +542,11 @@ void Maxwell3D::ProcessQueryCondition() {
case Regs::RenderEnable::Override::NeverRender:
execute_on = false;
break;
case Regs::RenderEnable::Override::UseRenderEnable:
case Regs::RenderEnable::Override::UseRenderEnable: {
if (rasterizer->AccelerateConditionalRendering()) {
execute_on = true;
return;
}
switch (regs.render_enable.mode) {
case Regs::RenderEnable::Mode::True: {
execute_on = true;
@@ -427,6 +584,7 @@ void Maxwell3D::ProcessQueryCondition() {
}
break;
}
}
}
void Maxwell3D::ProcessCounterReset() {
@@ -463,7 +621,8 @@ std::optional<u64> Maxwell3D::GetQueryResult() {
}
void Maxwell3D::ProcessCBBind(size_t stage_index) {
// Bind the buffer currently in CB_ADDRESS to the specified index in the desired shader stage.
// Bind the buffer currently in CB_ADDRESS to the specified index in the desired shader
// stage.
const auto& bind_data = regs.bind_groups[stage_index];
auto& buffer = state.shader_stages[stage_index].const_buffers[bind_data.shader_slot];
buffer.enabled = bind_data.valid.Value() != 0;
@@ -524,4 +683,10 @@ u32 Maxwell3D::GetRegisterValue(u32 method) const {
return regs.reg_array[method];
}
void Maxwell3D::SetHLEReplacementAttributeType(u32 bank, u32 offset,
HLEReplacementAttributeType name) {
const u64 key = (static_cast<u64>(bank) << 32) | offset;
replace_table.emplace(key, name);
}
} // namespace Tegra::Engines
+79 -12
View File
@@ -272,6 +272,7 @@ public:
};
union {
u32 raw;
BitField<0, 1, Mode> mode;
BitField<4, 8, u32> pad;
};
@@ -1217,10 +1218,12 @@ public:
struct Window {
union {
u32 raw_x;
BitField<0, 16, u32> x_min;
BitField<16, 16, u32> x_max;
};
union {
u32 raw_y;
BitField<0, 16, u32> y_min;
BitField<16, 16, u32> y_max;
};
@@ -1596,6 +1599,20 @@ public:
};
static_assert(sizeof(TIRModulationCoeff) == 0x4);
struct DrawTexture {
s32 dst_x0;
s32 dst_y0;
s32 dst_width;
s32 dst_height;
s64 dx_du;
s64 dy_dv;
u32 src_sampler;
u32 src_texture;
s32 src_x0;
s32 src_y0;
};
static_assert(sizeof(DrawTexture) == 0x30);
struct ReduceColorThreshold {
union {
BitField<0, 8, u32> all_hit_once;
@@ -2708,7 +2725,7 @@ public:
u32 post_z_pixel_imask; ///< 0x0F1C
INSERT_PADDING_BYTES_NOINIT(0x20);
ConstantColorRendering const_color_rendering; ///< 0x0F40
s32 stencil_back_ref; ///< 0x0F54
u32 stencil_back_ref; ///< 0x0F54
u32 stencil_back_mask; ///< 0x0F58
u32 stencil_back_func_mask; ///< 0x0F5C
INSERT_PADDING_BYTES_NOINIT(0x14);
@@ -2748,7 +2765,7 @@ public:
u32 reserved_sw_method2; ///< 0x102C
std::array<TIRModulationCoeff, 5> tir_modulation_coeff; ///< 0x1030
std::array<u32, 15> spare_nop; ///< 0x1044
INSERT_PADDING_BYTES_NOINIT(0x30);
DrawTexture draw_texture; ///< 0x1080
std::array<u32, 7> reserved_sw_method3_to_7; ///< 0x10B0
ReduceColorThreshold reduce_color_thresholds_unorm8; ///< 0x10CC
std::array<u32, 4> reserved_sw_method10_to_13; ///< 0x10D0
@@ -2832,9 +2849,9 @@ public:
Blend blend; ///< 0x133C
u32 stencil_enable; ///< 0x1380
StencilOp stencil_front_op; ///< 0x1384
s32 stencil_front_ref; ///< 0x1394
s32 stencil_front_func_mask; ///< 0x1398
s32 stencil_front_mask; ///< 0x139C
u32 stencil_front_ref; ///< 0x1394
u32 stencil_front_func_mask; ///< 0x1398
u32 stencil_front_mask; ///< 0x139C
INSERT_PADDING_BYTES_NOINIT(0x4);
u32 draw_auto_start_byte_count; ///< 0x13A4
PsSaturate frag_color_clamp; ///< 0x13A8
@@ -3020,6 +3037,24 @@ public:
/// Store temporary hw register values, used by some calls to restore state after a operation
Regs shadow_state;
// None Engine
enum class EngineHint : u32 {
None = 0x0,
OnHLEMacro = 0x1,
};
EngineHint engine_state{EngineHint::None};
enum class HLEReplacementAttributeType : u32 {
BaseVertex = 0x0,
BaseInstance = 0x1,
DrawID = 0x2,
};
void SetHLEReplacementAttributeType(u32 bank, u32 offset, HLEReplacementAttributeType name);
std::unordered_map<u64, HLEReplacementAttributeType> replace_table;
static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32), "Maxwell3D Regs has wrong size");
static_assert(std::is_trivially_copyable_v<Regs>, "Maxwell3D Regs must be trivially copyable");
@@ -3067,6 +3102,35 @@ public:
std::unique_ptr<DrawManager> draw_manager;
friend class DrawManager;
GPUVAddr GetMacroAddress(size_t index) const {
return macro_addresses[index];
}
void RefreshParameters() {
if (!current_macro_dirty) {
return;
}
RefreshParametersImpl();
}
bool AnyParametersDirty() const {
return current_macro_dirty;
}
u32 GetMaxCurrentVertices();
size_t EstimateIndexBufferSize();
/// Handles a write to the CLEAR_BUFFERS register.
void ProcessClearBuffers(u32 layer_count);
/// Handles a write to the CB_BIND register.
void ProcessCBBind(size_t stage_index);
/// Handles a write to the CB_DATA[i] register.
void ProcessCBData(u32 value);
void ProcessCBMultiData(const u32* start_base, u32 amount);
private:
void InitializeRegisterDefaults();
@@ -3076,6 +3140,8 @@ private:
void ProcessDirtyRegisters(u32 method, u32 argument);
void ConsumeSinkImpl() override;
void ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argument, bool is_last_call);
/// Retrieves information about a specific TIC entry from the TIC buffer.
@@ -3116,16 +3182,13 @@ private:
/// Handles writes to syncing register.
void ProcessSyncPoint();
/// Handles a write to the CB_DATA[i] register.
void ProcessCBData(u32 value);
void ProcessCBMultiData(const u32* start_base, u32 amount);
/// Handles a write to the CB_BIND register.
void ProcessCBBind(size_t stage_index);
/// Returns a query's value or an empty object if the value will be deferred through a cache.
std::optional<u64> GetQueryResult();
void RefreshParametersImpl();
bool IsMethodExecutable(u32 method);
Core::System& system;
MemoryManager& memory_manager;
@@ -3145,6 +3208,10 @@ private:
Upload::State upload_state;
bool execute_on{true};
std::vector<std::pair<GPUVAddr, size_t>> macro_segments;
std::vector<GPUVAddr> macro_addresses;
bool current_macro_dirty{};
};
#define ASSERT_REG_POSITION(field_name, position) \
+11 -1
View File
@@ -21,7 +21,10 @@ namespace Tegra::Engines {
using namespace Texture;
MaxwellDMA::MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_)
: system{system_}, memory_manager{memory_manager_} {}
: system{system_}, memory_manager{memory_manager_} {
execution_mask.reset();
execution_mask[offsetof(Regs, launch_dma) / sizeof(u32)] = true;
}
MaxwellDMA::~MaxwellDMA() = default;
@@ -29,6 +32,13 @@ void MaxwellDMA::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
rasterizer = rasterizer_;
}
void MaxwellDMA::ConsumeSinkImpl() {
for (auto [method, value] : method_sink) {
regs.reg_array[method] = value;
}
method_sink.clear();
}
void MaxwellDMA::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
ASSERT_MSG(method < NUM_REGS, "Invalid MaxwellDMA register");
+2
View File
@@ -231,6 +231,8 @@ private:
void ReleaseSemaphore();
void ConsumeSinkImpl() override;
Core::System& system;
MemoryManager& memory_manager;
+1 -1
View File
@@ -11,6 +11,7 @@ set(GLSL_INCLUDES
set(SHADER_FILES
astc_decoder.comp
blit_color_float.frag
block_linear_unswizzle_2d.comp
block_linear_unswizzle_3d.comp
convert_abgr8_to_d24s8.frag
@@ -36,7 +37,6 @@ set(SHADER_FILES
smaa_blending_weight_calculation.frag
smaa_neighborhood_blending.vert
smaa_neighborhood_blending.frag
vulkan_blit_color_float.frag
vulkan_blit_depth_stencil.frag
vulkan_fidelityfx_fsr_easu_fp16.comp
vulkan_fidelityfx_fsr_easu_fp32.comp
@@ -4,13 +4,20 @@
#version 450
#ifdef VULKAN
#define VERTEX_ID gl_VertexIndex
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
#define END_PUSH_CONSTANTS };
#define UNIFORM(n)
#define FLIPY 1
#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv
#define VERTEX_ID gl_VertexID
#define BEGIN_PUSH_CONSTANTS
#define END_PUSH_CONSTANTS
#define FLIPY -1
#define UNIFORM(n) layout (location = n) uniform
out gl_PerVertex {
vec4 gl_Position;
};
#endif
BEGIN_PUSH_CONSTANTS
@@ -21,8 +28,8 @@ END_PUSH_CONSTANTS
layout(location = 0) out vec2 texcoord;
void main() {
float x = float((gl_VertexIndex & 1) << 2);
float y = float((gl_VertexIndex & 2) << 1);
gl_Position = vec4(x - 1.0, y - 1.0, 0.0, 1.0);
float x = float((VERTEX_ID & 1) << 2);
float y = float((VERTEX_ID & 2) << 1);
gl_Position = vec4(x - 1.0, FLIPY * (y - 1.0), 0.0, 1.0);
texcoord = fma(vec2(x, y) / 2.0, tex_scale, tex_offset);
}
}

Some files were not shown because too many files have changed in this diff Show More