Merge branch 'yuzu-emu:master' into master
This commit is contained in:
commit
0e19217a47
114 changed files with 27005 additions and 9068 deletions
|
@ -1,7 +1,7 @@
|
||||||
# SPDX-FileCopyrightText: 2019 yuzu Emulator Project
|
# SPDX-FileCopyrightText: 2019 yuzu Emulator Project
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
# Gets a UTC timstamp and sets the provided variable to it
|
# Gets a UTC timestamp and sets the provided variable to it
|
||||||
function(get_timestamp _var)
|
function(get_timestamp _var)
|
||||||
string(TIMESTAMP timestamp UTC)
|
string(TIMESTAMP timestamp UTC)
|
||||||
set(${_var} "${timestamp}" PARENT_SCOPE)
|
set(${_var} "${timestamp}" PARENT_SCOPE)
|
||||||
|
|
7176
dist/languages/ar.ts
vendored
Normal file
7176
dist/languages/ar.ts
vendored
Normal file
File diff suppressed because it is too large
Load diff
798
dist/languages/ca.ts
vendored
798
dist/languages/ca.ts
vendored
File diff suppressed because it is too large
Load diff
798
dist/languages/cs.ts
vendored
798
dist/languages/cs.ts
vendored
File diff suppressed because it is too large
Load diff
798
dist/languages/da.ts
vendored
798
dist/languages/da.ts
vendored
File diff suppressed because it is too large
Load diff
798
dist/languages/de.ts
vendored
798
dist/languages/de.ts
vendored
File diff suppressed because it is too large
Load diff
798
dist/languages/el.ts
vendored
798
dist/languages/el.ts
vendored
File diff suppressed because it is too large
Load diff
804
dist/languages/es.ts
vendored
804
dist/languages/es.ts
vendored
File diff suppressed because it is too large
Load diff
948
dist/languages/fr.ts
vendored
948
dist/languages/fr.ts
vendored
File diff suppressed because it is too large
Load diff
7171
dist/languages/hu.ts
vendored
Normal file
7171
dist/languages/hu.ts
vendored
Normal file
File diff suppressed because it is too large
Load diff
798
dist/languages/id.ts
vendored
798
dist/languages/id.ts
vendored
File diff suppressed because it is too large
Load diff
806
dist/languages/it.ts
vendored
806
dist/languages/it.ts
vendored
File diff suppressed because it is too large
Load diff
830
dist/languages/ja_JP.ts
vendored
830
dist/languages/ja_JP.ts
vendored
File diff suppressed because it is too large
Load diff
798
dist/languages/ko_KR.ts
vendored
798
dist/languages/ko_KR.ts
vendored
File diff suppressed because it is too large
Load diff
804
dist/languages/nb.ts
vendored
804
dist/languages/nb.ts
vendored
File diff suppressed because it is too large
Load diff
857
dist/languages/nl.ts
vendored
857
dist/languages/nl.ts
vendored
File diff suppressed because it is too large
Load diff
798
dist/languages/pl.ts
vendored
798
dist/languages/pl.ts
vendored
File diff suppressed because it is too large
Load diff
966
dist/languages/pt_BR.ts
vendored
966
dist/languages/pt_BR.ts
vendored
File diff suppressed because it is too large
Load diff
965
dist/languages/pt_PT.ts
vendored
965
dist/languages/pt_PT.ts
vendored
File diff suppressed because it is too large
Load diff
798
dist/languages/ru_RU.ts
vendored
798
dist/languages/ru_RU.ts
vendored
File diff suppressed because it is too large
Load diff
798
dist/languages/sv.ts
vendored
798
dist/languages/sv.ts
vendored
File diff suppressed because it is too large
Load diff
798
dist/languages/tr_TR.ts
vendored
798
dist/languages/tr_TR.ts
vendored
File diff suppressed because it is too large
Load diff
798
dist/languages/uk.ts
vendored
798
dist/languages/uk.ts
vendored
File diff suppressed because it is too large
Load diff
802
dist/languages/vi.ts
vendored
802
dist/languages/vi.ts
vendored
File diff suppressed because it is too large
Load diff
802
dist/languages/vi_VN.ts
vendored
802
dist/languages/vi_VN.ts
vendored
File diff suppressed because it is too large
Load diff
802
dist/languages/zh_CN.ts
vendored
802
dist/languages/zh_CN.ts
vendored
File diff suppressed because it is too large
Load diff
800
dist/languages/zh_TW.ts
vendored
800
dist/languages/zh_TW.ts
vendored
File diff suppressed because it is too large
Load diff
|
@ -218,7 +218,6 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_window->OnSurfaceChanged(m_native_window);
|
m_window->OnSurfaceChanged(m_native_window);
|
||||||
m_system.Renderer().NotifySurfaceChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureFilesystemProvider(const std::string& filepath) {
|
void ConfigureFilesystemProvider(const std::string& filepath) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace AudioCore::Renderer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AudioRenderer command for preparing depop.
|
* AudioRenderer command for preparing depop.
|
||||||
* Adds the previusly output last samples to the depop buffer.
|
* Adds the previously output last samples to the depop buffer.
|
||||||
*/
|
*/
|
||||||
struct DepopPrepareCommand : ICommand {
|
struct DepopPrepareCommand : ICommand {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,10 +18,12 @@
|
||||||
#define LOAD_DIR "load"
|
#define LOAD_DIR "load"
|
||||||
#define LOG_DIR "log"
|
#define LOG_DIR "log"
|
||||||
#define NAND_DIR "nand"
|
#define NAND_DIR "nand"
|
||||||
|
#define PLAY_TIME_DIR "play_time"
|
||||||
#define SCREENSHOTS_DIR "screenshots"
|
#define SCREENSHOTS_DIR "screenshots"
|
||||||
#define SDMC_DIR "sdmc"
|
#define SDMC_DIR "sdmc"
|
||||||
#define SHADER_DIR "shader"
|
#define SHADER_DIR "shader"
|
||||||
#define TAS_DIR "tas"
|
#define TAS_DIR "tas"
|
||||||
|
#define ICONS_DIR "icons"
|
||||||
|
|
||||||
// yuzu-specific files
|
// yuzu-specific files
|
||||||
|
|
||||||
|
|
|
@ -124,10 +124,12 @@ public:
|
||||||
GenerateYuzuPath(YuzuPath::LoadDir, yuzu_path / LOAD_DIR);
|
GenerateYuzuPath(YuzuPath::LoadDir, yuzu_path / LOAD_DIR);
|
||||||
GenerateYuzuPath(YuzuPath::LogDir, yuzu_path / LOG_DIR);
|
GenerateYuzuPath(YuzuPath::LogDir, yuzu_path / LOG_DIR);
|
||||||
GenerateYuzuPath(YuzuPath::NANDDir, yuzu_path / NAND_DIR);
|
GenerateYuzuPath(YuzuPath::NANDDir, yuzu_path / NAND_DIR);
|
||||||
|
GenerateYuzuPath(YuzuPath::PlayTimeDir, yuzu_path / PLAY_TIME_DIR);
|
||||||
GenerateYuzuPath(YuzuPath::ScreenshotsDir, yuzu_path / SCREENSHOTS_DIR);
|
GenerateYuzuPath(YuzuPath::ScreenshotsDir, yuzu_path / SCREENSHOTS_DIR);
|
||||||
GenerateYuzuPath(YuzuPath::SDMCDir, yuzu_path / SDMC_DIR);
|
GenerateYuzuPath(YuzuPath::SDMCDir, yuzu_path / SDMC_DIR);
|
||||||
GenerateYuzuPath(YuzuPath::ShaderDir, yuzu_path / SHADER_DIR);
|
GenerateYuzuPath(YuzuPath::ShaderDir, yuzu_path / SHADER_DIR);
|
||||||
GenerateYuzuPath(YuzuPath::TASDir, yuzu_path / TAS_DIR);
|
GenerateYuzuPath(YuzuPath::TASDir, yuzu_path / TAS_DIR);
|
||||||
|
GenerateYuzuPath(YuzuPath::IconsDir, yuzu_path / ICONS_DIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -20,10 +20,12 @@ enum class YuzuPath {
|
||||||
LoadDir, // Where cheat/mod files are stored.
|
LoadDir, // Where cheat/mod files are stored.
|
||||||
LogDir, // Where log files are stored.
|
LogDir, // Where log files are stored.
|
||||||
NANDDir, // Where the emulated NAND is stored.
|
NANDDir, // Where the emulated NAND is stored.
|
||||||
|
PlayTimeDir, // Where play time data is stored.
|
||||||
ScreenshotsDir, // Where yuzu screenshots are stored.
|
ScreenshotsDir, // Where yuzu screenshots are stored.
|
||||||
SDMCDir, // Where the emulated SDMC is stored.
|
SDMCDir, // Where the emulated SDMC is stored.
|
||||||
ShaderDir, // Where shaders are stored.
|
ShaderDir, // Where shaders are stored.
|
||||||
TASDir, // Where TAS scripts are stored.
|
TASDir, // Where TAS scripts are stored.
|
||||||
|
IconsDir, // Where Icons for Windows shortcuts are stored.
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -135,6 +135,11 @@ std::u16string UTF8ToUTF16(std::string_view input) {
|
||||||
return convert.from_bytes(input.data(), input.data() + input.size());
|
return convert.from_bytes(input.data(), input.data() + input.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::u32string UTF8ToUTF32(std::string_view input) {
|
||||||
|
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
|
||||||
|
return convert.from_bytes(input.data(), input.data() + input.size());
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static std::wstring CPToUTF16(u32 code_page, std::string_view input) {
|
static std::wstring CPToUTF16(u32 code_page, std::string_view input) {
|
||||||
const auto size =
|
const auto size =
|
||||||
|
|
|
@ -38,6 +38,7 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
|
||||||
|
|
||||||
[[nodiscard]] std::string UTF16ToUTF8(std::u16string_view input);
|
[[nodiscard]] std::string UTF16ToUTF8(std::u16string_view input);
|
||||||
[[nodiscard]] std::u16string UTF8ToUTF16(std::string_view input);
|
[[nodiscard]] std::u16string UTF8ToUTF16(std::string_view input);
|
||||||
|
[[nodiscard]] std::u32string UTF8ToUTF32(std::string_view input);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
[[nodiscard]] std::string UTF16ToUTF8(std::wstring_view input);
|
[[nodiscard]] std::string UTF16ToUTF8(std::wstring_view input);
|
||||||
|
|
|
@ -698,6 +698,8 @@ add_library(core STATIC
|
||||||
hle/service/nvnflinger/consumer_base.cpp
|
hle/service/nvnflinger/consumer_base.cpp
|
||||||
hle/service/nvnflinger/consumer_base.h
|
hle/service/nvnflinger/consumer_base.h
|
||||||
hle/service/nvnflinger/consumer_listener.h
|
hle/service/nvnflinger/consumer_listener.h
|
||||||
|
hle/service/nvnflinger/fb_share_buffer_manager.cpp
|
||||||
|
hle/service/nvnflinger/fb_share_buffer_manager.h
|
||||||
hle/service/nvnflinger/graphic_buffer_producer.cpp
|
hle/service/nvnflinger/graphic_buffer_producer.cpp
|
||||||
hle/service/nvnflinger/graphic_buffer_producer.h
|
hle/service/nvnflinger/graphic_buffer_producer.h
|
||||||
hle/service/nvnflinger/hos_binder_driver_server.cpp
|
hle/service/nvnflinger/hos_binder_driver_server.cpp
|
||||||
|
|
|
@ -1078,6 +1078,10 @@ void System::ApplySettings() {
|
||||||
impl->RefreshTime();
|
impl->RefreshTime();
|
||||||
|
|
||||||
if (IsPoweredOn()) {
|
if (IsPoweredOn()) {
|
||||||
|
if (Settings::values.custom_rtc_enabled) {
|
||||||
|
const s64 posix_time{Settings::values.custom_rtc.GetValue()};
|
||||||
|
GetTimeManager().UpdateLocalSystemClockTime(posix_time);
|
||||||
|
}
|
||||||
Renderer().RefreshBaseSettings();
|
Renderer().RefreshBaseSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <codecvt>
|
||||||
|
#include <locale>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
@ -12,6 +14,7 @@
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
|
#include "common/string_util.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/debugger/gdbstub.h"
|
#include "core/debugger/gdbstub.h"
|
||||||
|
@ -68,10 +71,16 @@ static std::string EscapeGDB(std::string_view data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string EscapeXML(std::string_view data) {
|
static std::string EscapeXML(std::string_view data) {
|
||||||
|
std::u32string converted = U"[Encoding error]";
|
||||||
|
try {
|
||||||
|
converted = Common::UTF8ToUTF32(data);
|
||||||
|
} catch (std::range_error&) {
|
||||||
|
}
|
||||||
|
|
||||||
std::string escaped;
|
std::string escaped;
|
||||||
escaped.reserve(data.size());
|
escaped.reserve(data.size());
|
||||||
|
|
||||||
for (char c : data) {
|
for (char32_t c : converted) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '&':
|
case '&':
|
||||||
escaped += "&";
|
escaped += "&";
|
||||||
|
@ -86,7 +95,11 @@ static std::string EscapeXML(std::string_view data) {
|
||||||
escaped += ">";
|
escaped += ">";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
escaped += c;
|
if (c > 0x7f) {
|
||||||
|
escaped += fmt::format("&#{};", static_cast<u32>(c));
|
||||||
|
} else {
|
||||||
|
escaped += static_cast<char>(c);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "common/scope_exit.h"
|
||||||
#include "core/file_sys/program_metadata.h"
|
#include "core/file_sys/program_metadata.h"
|
||||||
#include "core/file_sys/vfs.h"
|
#include "core/file_sys/vfs.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
|
@ -95,6 +96,13 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
|
||||||
return Loader::ResultStatus::Success;
|
return Loader::ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loader::ResultStatus ProgramMetadata::Reload(VirtualFile file) {
|
||||||
|
const u64 original_program_id = aci_header.title_id;
|
||||||
|
SCOPE_EXIT({ aci_header.title_id = original_program_id; });
|
||||||
|
|
||||||
|
return this->Load(file);
|
||||||
|
}
|
||||||
|
|
||||||
/*static*/ ProgramMetadata ProgramMetadata::GetDefault() {
|
/*static*/ ProgramMetadata ProgramMetadata::GetDefault() {
|
||||||
// Allow use of cores 0~3 and thread priorities 1~63.
|
// Allow use of cores 0~3 and thread priorities 1~63.
|
||||||
constexpr u32 default_thread_info_capability = 0x30007F7;
|
constexpr u32 default_thread_info_capability = 0x30007F7;
|
||||||
|
|
|
@ -56,6 +56,7 @@ public:
|
||||||
static ProgramMetadata GetDefault();
|
static ProgramMetadata GetDefault();
|
||||||
|
|
||||||
Loader::ResultStatus Load(VirtualFile file);
|
Loader::ResultStatus Load(VirtualFile file);
|
||||||
|
Loader::ResultStatus Reload(VirtualFile file);
|
||||||
|
|
||||||
/// Load from parameters instead of NPDM file, used for KIP
|
/// Load from parameters instead of NPDM file, used for KIP
|
||||||
void LoadManual(bool is_64_bit, ProgramAddressSpaceType address_space, s32 main_thread_prio,
|
void LoadManual(bool is_64_bit, ProgramAddressSpaceType address_space, s32 main_thread_prio,
|
||||||
|
|
|
@ -175,7 +175,7 @@ public:
|
||||||
return Write(reinterpret_cast<const u8*>(&data), sizeof(T), offset);
|
return Write(reinterpret_cast<const u8*>(&data), sizeof(T), offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renames the file to name. Returns whether or not the operation was successsful.
|
// Renames the file to name. Returns whether or not the operation was successful.
|
||||||
virtual bool Rename(std::string_view name) = 0;
|
virtual bool Rename(std::string_view name) = 0;
|
||||||
|
|
||||||
// Returns the full path of this file as a string, recursively
|
// Returns the full path of this file as a string, recursively
|
||||||
|
|
|
@ -61,7 +61,7 @@ bool KMemoryRegionTree::Insert(u64 address, size_t size, u32 type_id, u32 new_at
|
||||||
found->Reset(address, inserted_region_last, old_pair, new_attr, type_id);
|
found->Reset(address, inserted_region_last, old_pair, new_attr, type_id);
|
||||||
this->insert(*found);
|
this->insert(*found);
|
||||||
} else {
|
} else {
|
||||||
// If we can't re-use, adjust the old region.
|
// If we can't reuse, adjust the old region.
|
||||||
found->Reset(old_address, address - 1, old_pair, old_attr, old_type);
|
found->Reset(old_address, address - 1, old_pair, old_attr, old_type);
|
||||||
this->insert(*found);
|
this->insert(*found);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/literals.h"
|
#include "common/literals.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
|
#include "common/settings.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/kernel/k_address_space_info.h"
|
#include "core/hle/kernel/k_address_space_info.h"
|
||||||
#include "core/hle/kernel/k_memory_block.h"
|
#include "core/hle/kernel/k_memory_block.h"
|
||||||
|
@ -337,11 +338,14 @@ Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type
|
||||||
}
|
}
|
||||||
|
|
||||||
void KPageTable::Finalize() {
|
void KPageTable::Finalize() {
|
||||||
|
auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) {
|
||||||
|
if (Settings::IsFastmemEnabled()) {
|
||||||
|
m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Finalize memory blocks.
|
// Finalize memory blocks.
|
||||||
m_memory_block_manager.Finalize(m_memory_block_slab_manager,
|
m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(HostUnmapCallback));
|
||||||
[&](KProcessAddress addr, u64 size) {
|
|
||||||
m_memory->UnmapRegion(*m_page_table_impl, addr, size);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Release any insecure mapped memory.
|
// Release any insecure mapped memory.
|
||||||
if (m_mapped_insecure_memory) {
|
if (m_mapped_insecure_memory) {
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "common/settings_enums.h"
|
#include "common/settings_enums.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/core_timing.h"
|
||||||
#include "core/file_sys/control_metadata.h"
|
#include "core/file_sys/control_metadata.h"
|
||||||
#include "core/file_sys/patch_manager.h"
|
#include "core/file_sys/patch_manager.h"
|
||||||
#include "core/file_sys/registered_cache.h"
|
#include "core/file_sys/registered_cache.h"
|
||||||
|
@ -19,6 +20,7 @@
|
||||||
#include "core/hle/service/am/am.h"
|
#include "core/hle/service/am/am.h"
|
||||||
#include "core/hle/service/am/applet_ae.h"
|
#include "core/hle/service/am/applet_ae.h"
|
||||||
#include "core/hle/service/am/applet_oe.h"
|
#include "core/hle/service/am/applet_oe.h"
|
||||||
|
#include "core/hle/service/am/applets/applet_cabinet.h"
|
||||||
#include "core/hle/service/am/applets/applet_mii_edit_types.h"
|
#include "core/hle/service/am/applets/applet_mii_edit_types.h"
|
||||||
#include "core/hle/service/am/applets/applet_profile_select.h"
|
#include "core/hle/service/am/applets/applet_profile_select.h"
|
||||||
#include "core/hle/service/am/applets/applet_web_browser.h"
|
#include "core/hle/service/am/applets/applet_web_browser.h"
|
||||||
|
@ -33,11 +35,13 @@
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
#include "core/hle/service/ns/ns.h"
|
#include "core/hle/service/ns/ns.h"
|
||||||
|
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
||||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||||
#include "core/hle/service/pm/pm.h"
|
#include "core/hle/service/pm/pm.h"
|
||||||
#include "core/hle/service/server_manager.h"
|
#include "core/hle/service/server_manager.h"
|
||||||
#include "core/hle/service/sm/sm.h"
|
#include "core/hle/service/sm/sm.h"
|
||||||
#include "core/hle/service/vi/vi.h"
|
#include "core/hle/service/vi/vi.h"
|
||||||
|
#include "core/hle/service/vi/vi_results.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
namespace Service::AM {
|
namespace Service::AM {
|
||||||
|
@ -190,7 +194,7 @@ IDisplayController::IDisplayController(Core::System& system_)
|
||||||
{4, nullptr, "UpdateCallerAppletCaptureImage"},
|
{4, nullptr, "UpdateCallerAppletCaptureImage"},
|
||||||
{5, nullptr, "GetLastForegroundCaptureImageEx"},
|
{5, nullptr, "GetLastForegroundCaptureImageEx"},
|
||||||
{6, nullptr, "GetLastApplicationCaptureImageEx"},
|
{6, nullptr, "GetLastApplicationCaptureImageEx"},
|
||||||
{7, nullptr, "GetCallerAppletCaptureImageEx"},
|
{7, &IDisplayController::GetCallerAppletCaptureImageEx, "GetCallerAppletCaptureImageEx"},
|
||||||
{8, &IDisplayController::TakeScreenShotOfOwnLayer, "TakeScreenShotOfOwnLayer"},
|
{8, &IDisplayController::TakeScreenShotOfOwnLayer, "TakeScreenShotOfOwnLayer"},
|
||||||
{9, nullptr, "CopyBetweenCaptureBuffers"},
|
{9, nullptr, "CopyBetweenCaptureBuffers"},
|
||||||
{10, nullptr, "AcquireLastApplicationCaptureBuffer"},
|
{10, nullptr, "AcquireLastApplicationCaptureBuffer"},
|
||||||
|
@ -208,8 +212,8 @@ IDisplayController::IDisplayController(Core::System& system_)
|
||||||
{23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"},
|
{23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"},
|
||||||
{24, nullptr, "AcquireLastForegroundCaptureSharedBuffer"},
|
{24, nullptr, "AcquireLastForegroundCaptureSharedBuffer"},
|
||||||
{25, nullptr, "ReleaseLastForegroundCaptureSharedBuffer"},
|
{25, nullptr, "ReleaseLastForegroundCaptureSharedBuffer"},
|
||||||
{26, nullptr, "AcquireCallerAppletCaptureSharedBuffer"},
|
{26, &IDisplayController::AcquireCallerAppletCaptureSharedBuffer, "AcquireCallerAppletCaptureSharedBuffer"},
|
||||||
{27, nullptr, "ReleaseCallerAppletCaptureSharedBuffer"},
|
{27, &IDisplayController::ReleaseCallerAppletCaptureSharedBuffer, "ReleaseCallerAppletCaptureSharedBuffer"},
|
||||||
{28, nullptr, "TakeScreenShotOfOwnLayerEx"},
|
{28, nullptr, "TakeScreenShotOfOwnLayerEx"},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -219,6 +223,15 @@ IDisplayController::IDisplayController(Core::System& system_)
|
||||||
|
|
||||||
IDisplayController::~IDisplayController() = default;
|
IDisplayController::~IDisplayController() = default;
|
||||||
|
|
||||||
|
void IDisplayController::GetCallerAppletCaptureImageEx(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(1u);
|
||||||
|
rb.Push(0);
|
||||||
|
}
|
||||||
|
|
||||||
void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) {
|
void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
|
@ -226,6 +239,22 @@ void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) {
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IDisplayController::AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(1U);
|
||||||
|
rb.Push(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IDisplayController::ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
IDebugFunctions::IDebugFunctions(Core::System& system_)
|
IDebugFunctions::IDebugFunctions(Core::System& system_)
|
||||||
: ServiceFramework{system_, "IDebugFunctions"} {
|
: ServiceFramework{system_, "IDebugFunctions"} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
@ -285,14 +314,14 @@ ISelfController::ISelfController(Core::System& system_, Nvnflinger::Nvnflinger&
|
||||||
{20, nullptr, "SetDesirableKeyboardLayout"},
|
{20, nullptr, "SetDesirableKeyboardLayout"},
|
||||||
{21, nullptr, "GetScreenShotProgramId"},
|
{21, nullptr, "GetScreenShotProgramId"},
|
||||||
{40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
|
{40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
|
||||||
{41, nullptr, "IsSystemBufferSharingEnabled"},
|
{41, &ISelfController::IsSystemBufferSharingEnabled, "IsSystemBufferSharingEnabled"},
|
||||||
{42, nullptr, "GetSystemSharedLayerHandle"},
|
{42, &ISelfController::GetSystemSharedLayerHandle, "GetSystemSharedLayerHandle"},
|
||||||
{43, nullptr, "GetSystemSharedBufferHandle"},
|
{43, &ISelfController::GetSystemSharedBufferHandle, "GetSystemSharedBufferHandle"},
|
||||||
{44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"},
|
{44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"},
|
||||||
{45, nullptr, "SetManagedDisplayLayerSeparationMode"},
|
{45, nullptr, "SetManagedDisplayLayerSeparationMode"},
|
||||||
{46, nullptr, "SetRecordingLayerCompositionEnabled"},
|
{46, nullptr, "SetRecordingLayerCompositionEnabled"},
|
||||||
{50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
|
{50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
|
||||||
{51, nullptr, "ApproveToDisplay"},
|
{51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"},
|
||||||
{60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
|
{60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
|
||||||
{61, nullptr, "SetMediaPlaybackState"},
|
{61, nullptr, "SetMediaPlaybackState"},
|
||||||
{62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"},
|
{62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"},
|
||||||
|
@ -491,6 +520,50 @@ void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) {
|
||||||
rb.Push(*layer_id);
|
rb.Push(*layer_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(this->EnsureBufferSharingEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 6};
|
||||||
|
rb.Push(this->EnsureBufferSharingEnabled());
|
||||||
|
rb.Push<s64>(system_shared_buffer_id);
|
||||||
|
rb.Push<s64>(system_shared_layer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
|
rb.Push(this->EnsureBufferSharingEnabled());
|
||||||
|
rb.Push<s64>(system_shared_buffer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ISelfController::EnsureBufferSharingEnabled() {
|
||||||
|
if (buffer_sharing_enabled) {
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (system.GetAppletManager().GetCurrentAppletId() <= Applets::AppletId::Application) {
|
||||||
|
return VI::ResultOperationFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto display_id = nvnflinger.OpenDisplay("Default");
|
||||||
|
const auto result = nvnflinger.GetSystemBufferManager().Initialize(
|
||||||
|
&system_shared_buffer_id, &system_shared_layer_id, *display_id);
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
buffer_sharing_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) {
|
void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
|
@ -516,6 +589,13 @@ void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) {
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ISelfController::ApproveToDisplay(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) {
|
void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
idle_time_detection_extension = rp.Pop<u32>();
|
idle_time_detection_extension = rp.Pop<u32>();
|
||||||
|
@ -686,7 +766,8 @@ void AppletMessageQueue::OperationModeChanged() {
|
||||||
|
|
||||||
ICommonStateGetter::ICommonStateGetter(Core::System& system_,
|
ICommonStateGetter::ICommonStateGetter(Core::System& system_,
|
||||||
std::shared_ptr<AppletMessageQueue> msg_queue_)
|
std::shared_ptr<AppletMessageQueue> msg_queue_)
|
||||||
: ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)} {
|
: ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)},
|
||||||
|
service_context{system_, "ICommonStateGetter"} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
|
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
|
||||||
|
@ -699,10 +780,10 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
|
||||||
{7, nullptr, "GetCradleStatus"},
|
{7, nullptr, "GetCradleStatus"},
|
||||||
{8, &ICommonStateGetter::GetBootMode, "GetBootMode"},
|
{8, &ICommonStateGetter::GetBootMode, "GetBootMode"},
|
||||||
{9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"},
|
{9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"},
|
||||||
{10, nullptr, "RequestToAcquireSleepLock"},
|
{10, &ICommonStateGetter::RequestToAcquireSleepLock, "RequestToAcquireSleepLock"},
|
||||||
{11, nullptr, "ReleaseSleepLock"},
|
{11, nullptr, "ReleaseSleepLock"},
|
||||||
{12, nullptr, "ReleaseSleepLockTransiently"},
|
{12, nullptr, "ReleaseSleepLockTransiently"},
|
||||||
{13, nullptr, "GetAcquiredSleepLockEvent"},
|
{13, &ICommonStateGetter::GetAcquiredSleepLockEvent, "GetAcquiredSleepLockEvent"},
|
||||||
{14, nullptr, "GetWakeupCount"},
|
{14, nullptr, "GetWakeupCount"},
|
||||||
{20, nullptr, "PushToGeneralChannel"},
|
{20, nullptr, "PushToGeneralChannel"},
|
||||||
{30, nullptr, "GetHomeButtonReaderLockAccessor"},
|
{30, nullptr, "GetHomeButtonReaderLockAccessor"},
|
||||||
|
@ -745,6 +826,8 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
|
sleep_lock_event = service_context.CreateEvent("ICommonStateGetter::SleepLockEvent");
|
||||||
|
|
||||||
// Configure applets to be in foreground state
|
// Configure applets to be in foreground state
|
||||||
msg_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
|
msg_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
|
||||||
msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
|
msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
|
||||||
|
@ -793,6 +876,24 @@ void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) {
|
||||||
rb.Push(static_cast<u8>(FocusState::InFocus));
|
rb.Push(static_cast<u8>(FocusState::InFocus));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
|
// Sleep lock is acquired immediately.
|
||||||
|
sleep_lock_event->Signal();
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AM, "called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushCopyObjects(sleep_lock_event->GetReadableEvent());
|
||||||
|
}
|
||||||
|
|
||||||
void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) {
|
void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_AM, "called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
|
|
||||||
|
@ -1385,7 +1486,16 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
|
||||||
// clang-format on
|
// clang-format on
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
|
switch (system.GetAppletManager().GetCurrentAppletId()) {
|
||||||
|
case Applets::AppletId::Cabinet:
|
||||||
|
PushInShowCabinetData();
|
||||||
|
break;
|
||||||
|
case Applets::AppletId::MiiEdit:
|
||||||
PushInShowMiiEditData();
|
PushInShowMiiEditData();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default;
|
ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default;
|
||||||
|
@ -1431,7 +1541,7 @@ void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
const LibraryAppletInfo applet_info{
|
const LibraryAppletInfo applet_info{
|
||||||
.applet_id = Applets::AppletId::MiiEdit,
|
.applet_id = system.GetAppletManager().GetCurrentAppletId(),
|
||||||
.library_applet_mode = Applets::LibraryAppletMode::AllForeground,
|
.library_applet_mode = Applets::LibraryAppletMode::AllForeground,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1459,6 +1569,35 @@ void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext&
|
||||||
rb.PushRaw(applet_info);
|
rb.PushRaw(applet_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ILibraryAppletSelfAccessor::PushInShowCabinetData() {
|
||||||
|
const Applets::CommonArguments arguments{
|
||||||
|
.arguments_version = Applets::CommonArgumentVersion::Version3,
|
||||||
|
.size = Applets::CommonArgumentSize::Version3,
|
||||||
|
.library_version = static_cast<u32>(Applets::CabinetAppletVersion::Version1),
|
||||||
|
.theme_color = Applets::ThemeColor::BasicBlack,
|
||||||
|
.play_startup_sound = true,
|
||||||
|
.system_tick = system.CoreTiming().GetClockTicks(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const Applets::StartParamForAmiiboSettings amiibo_settings{
|
||||||
|
.param_1 = 0,
|
||||||
|
.applet_mode = system.GetAppletManager().GetCabinetMode(),
|
||||||
|
.flags = Applets::CabinetFlags::None,
|
||||||
|
.amiibo_settings_1 = 0,
|
||||||
|
.device_handle = 0,
|
||||||
|
.tag_info{},
|
||||||
|
.register_info{},
|
||||||
|
.amiibo_settings_3{},
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<u8> argument_data(sizeof(arguments));
|
||||||
|
std::vector<u8> settings_data(sizeof(amiibo_settings));
|
||||||
|
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
|
||||||
|
std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings));
|
||||||
|
queue_data.emplace_back(std::move(argument_data));
|
||||||
|
queue_data.emplace_back(std::move(settings_data));
|
||||||
|
}
|
||||||
|
|
||||||
void ILibraryAppletSelfAccessor::PushInShowMiiEditData() {
|
void ILibraryAppletSelfAccessor::PushInShowMiiEditData() {
|
||||||
struct MiiEditV3 {
|
struct MiiEditV3 {
|
||||||
Applets::MiiEditAppletInputCommon common;
|
Applets::MiiEditAppletInputCommon common;
|
||||||
|
@ -2235,7 +2374,7 @@ void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) {
|
void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) {
|
||||||
const auto applet_id = Applets::AppletId::MiiEdit;
|
const auto applet_id = system.GetAppletManager().GetCurrentAppletId();
|
||||||
const auto applet_mode = Applets::LibraryAppletMode::AllForeground;
|
const auto applet_mode = Applets::LibraryAppletMode::AllForeground;
|
||||||
|
|
||||||
LOG_WARNING(Service_AM, "(STUBBED) called with applet_id={:08X}, applet_mode={:08X}", applet_id,
|
LOG_WARNING(Service_AM, "(STUBBED) called with applet_id={:08X}, applet_mode={:08X}", applet_id,
|
||||||
|
@ -2256,4 +2395,5 @@ void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx)
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet);
|
rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::AM
|
} // namespace Service::AM
|
||||||
|
|
|
@ -122,7 +122,10 @@ public:
|
||||||
~IDisplayController() override;
|
~IDisplayController() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void GetCallerAppletCaptureImageEx(HLERequestContext& ctx);
|
||||||
void TakeScreenShotOfOwnLayer(HLERequestContext& ctx);
|
void TakeScreenShotOfOwnLayer(HLERequestContext& ctx);
|
||||||
|
void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
|
||||||
|
void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
|
||||||
};
|
};
|
||||||
|
|
||||||
class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
|
class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
|
||||||
|
@ -150,9 +153,13 @@ private:
|
||||||
void SetRestartMessageEnabled(HLERequestContext& ctx);
|
void SetRestartMessageEnabled(HLERequestContext& ctx);
|
||||||
void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx);
|
void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx);
|
||||||
void SetAlbumImageOrientation(HLERequestContext& ctx);
|
void SetAlbumImageOrientation(HLERequestContext& ctx);
|
||||||
|
void IsSystemBufferSharingEnabled(HLERequestContext& ctx);
|
||||||
|
void GetSystemSharedBufferHandle(HLERequestContext& ctx);
|
||||||
|
void GetSystemSharedLayerHandle(HLERequestContext& ctx);
|
||||||
void CreateManagedDisplayLayer(HLERequestContext& ctx);
|
void CreateManagedDisplayLayer(HLERequestContext& ctx);
|
||||||
void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx);
|
void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx);
|
||||||
void SetHandlesRequestToDisplay(HLERequestContext& ctx);
|
void SetHandlesRequestToDisplay(HLERequestContext& ctx);
|
||||||
|
void ApproveToDisplay(HLERequestContext& ctx);
|
||||||
void SetIdleTimeDetectionExtension(HLERequestContext& ctx);
|
void SetIdleTimeDetectionExtension(HLERequestContext& ctx);
|
||||||
void GetIdleTimeDetectionExtension(HLERequestContext& ctx);
|
void GetIdleTimeDetectionExtension(HLERequestContext& ctx);
|
||||||
void ReportUserIsActive(HLERequestContext& ctx);
|
void ReportUserIsActive(HLERequestContext& ctx);
|
||||||
|
@ -164,6 +171,8 @@ private:
|
||||||
void SaveCurrentScreenshot(HLERequestContext& ctx);
|
void SaveCurrentScreenshot(HLERequestContext& ctx);
|
||||||
void SetRecordVolumeMuted(HLERequestContext& ctx);
|
void SetRecordVolumeMuted(HLERequestContext& ctx);
|
||||||
|
|
||||||
|
Result EnsureBufferSharingEnabled();
|
||||||
|
|
||||||
enum class ScreenshotPermission : u32 {
|
enum class ScreenshotPermission : u32 {
|
||||||
Inherit = 0,
|
Inherit = 0,
|
||||||
Enable = 1,
|
Enable = 1,
|
||||||
|
@ -179,7 +188,10 @@ private:
|
||||||
|
|
||||||
u32 idle_time_detection_extension = 0;
|
u32 idle_time_detection_extension = 0;
|
||||||
u64 num_fatal_sections_entered = 0;
|
u64 num_fatal_sections_entered = 0;
|
||||||
|
u64 system_shared_buffer_id = 0;
|
||||||
|
u64 system_shared_layer_id = 0;
|
||||||
bool is_auto_sleep_disabled = false;
|
bool is_auto_sleep_disabled = false;
|
||||||
|
bool buffer_sharing_enabled = false;
|
||||||
ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit;
|
ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -223,6 +235,8 @@ private:
|
||||||
void GetEventHandle(HLERequestContext& ctx);
|
void GetEventHandle(HLERequestContext& ctx);
|
||||||
void ReceiveMessage(HLERequestContext& ctx);
|
void ReceiveMessage(HLERequestContext& ctx);
|
||||||
void GetCurrentFocusState(HLERequestContext& ctx);
|
void GetCurrentFocusState(HLERequestContext& ctx);
|
||||||
|
void RequestToAcquireSleepLock(HLERequestContext& ctx);
|
||||||
|
void GetAcquiredSleepLockEvent(HLERequestContext& ctx);
|
||||||
void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
|
void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
|
||||||
void GetOperationMode(HLERequestContext& ctx);
|
void GetOperationMode(HLERequestContext& ctx);
|
||||||
void GetPerformanceMode(HLERequestContext& ctx);
|
void GetPerformanceMode(HLERequestContext& ctx);
|
||||||
|
@ -240,6 +254,8 @@ private:
|
||||||
|
|
||||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||||
bool vr_mode_state{};
|
bool vr_mode_state{};
|
||||||
|
Kernel::KEvent* sleep_lock_event;
|
||||||
|
KernelHelpers::ServiceContext service_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IStorageImpl {
|
class IStorageImpl {
|
||||||
|
@ -311,6 +327,7 @@ private:
|
||||||
void ExitProcessAndReturn(HLERequestContext& ctx);
|
void ExitProcessAndReturn(HLERequestContext& ctx);
|
||||||
void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
|
void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
|
||||||
|
|
||||||
|
void PushInShowCabinetData();
|
||||||
void PushInShowMiiEditData();
|
void PushInShowMiiEditData();
|
||||||
|
|
||||||
std::deque<std::vector<u8>> queue_data;
|
std::deque<std::vector<u8>> queue_data;
|
||||||
|
|
|
@ -29,6 +29,15 @@ enum class CabinetAppletVersion : u32 {
|
||||||
Version1 = 0x1,
|
Version1 = 0x1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class CabinetFlags : u8 {
|
||||||
|
None = 0,
|
||||||
|
DeviceHandle = 1 << 0,
|
||||||
|
TagInfo = 1 << 1,
|
||||||
|
RegisterInfo = 1 << 2,
|
||||||
|
All = DeviceHandle | TagInfo | RegisterInfo,
|
||||||
|
};
|
||||||
|
DECLARE_ENUM_FLAG_OPERATORS(CabinetFlags)
|
||||||
|
|
||||||
enum class CabinetResult : u8 {
|
enum class CabinetResult : u8 {
|
||||||
Cancel = 0,
|
Cancel = 0,
|
||||||
TagInfo = 1 << 1,
|
TagInfo = 1 << 1,
|
||||||
|
@ -51,7 +60,7 @@ static_assert(sizeof(AmiiboSettingsStartParam) == 0x30,
|
||||||
struct StartParamForAmiiboSettings {
|
struct StartParamForAmiiboSettings {
|
||||||
u8 param_1;
|
u8 param_1;
|
||||||
Service::NFP::CabinetMode applet_mode;
|
Service::NFP::CabinetMode applet_mode;
|
||||||
u8 flags;
|
CabinetFlags flags;
|
||||||
u8 amiibo_settings_1;
|
u8 amiibo_settings_1;
|
||||||
u64 device_handle;
|
u64 device_handle;
|
||||||
Service::NFP::TagInfo tag_info;
|
Service::NFP::TagInfo tag_info;
|
||||||
|
|
|
@ -223,9 +223,9 @@ void StubApplet::Initialize() {
|
||||||
|
|
||||||
const auto data = broker.PeekDataToAppletForDebug();
|
const auto data = broker.PeekDataToAppletForDebug();
|
||||||
system.GetReporter().SaveUnimplementedAppletReport(
|
system.GetReporter().SaveUnimplementedAppletReport(
|
||||||
static_cast<u32>(id), common_args.arguments_version, common_args.library_version,
|
static_cast<u32>(id), static_cast<u32>(common_args.arguments_version),
|
||||||
common_args.theme_color, common_args.play_startup_sound, common_args.system_tick,
|
common_args.library_version, static_cast<u32>(common_args.theme_color),
|
||||||
data.normal, data.interactive);
|
common_args.play_startup_sound, common_args.system_tick, data.normal, data.interactive);
|
||||||
|
|
||||||
LogCurrentStorage(broker, "Initialize");
|
LogCurrentStorage(broker, "Initialize");
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,6 +199,14 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
|
||||||
return frontend;
|
return frontend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NFP::CabinetMode AppletManager::GetCabinetMode() const {
|
||||||
|
return cabinet_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppletId AppletManager::GetCurrentAppletId() const {
|
||||||
|
return current_applet_id;
|
||||||
|
}
|
||||||
|
|
||||||
void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
|
void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
|
||||||
if (set.cabinet != nullptr) {
|
if (set.cabinet != nullptr) {
|
||||||
frontend.cabinet = std::move(set.cabinet);
|
frontend.cabinet = std::move(set.cabinet);
|
||||||
|
@ -237,6 +245,14 @@ void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppletManager::SetCabinetMode(NFP::CabinetMode mode) {
|
||||||
|
cabinet_mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppletManager::SetCurrentAppletId(AppletId applet_id) {
|
||||||
|
current_applet_id = applet_id;
|
||||||
|
}
|
||||||
|
|
||||||
void AppletManager::SetDefaultAppletFrontendSet() {
|
void AppletManager::SetDefaultAppletFrontendSet() {
|
||||||
ClearAll();
|
ClearAll();
|
||||||
SetDefaultAppletsIfMissing();
|
SetDefaultAppletsIfMissing();
|
||||||
|
|
|
@ -34,6 +34,10 @@ class KEvent;
|
||||||
class KReadableEvent;
|
class KReadableEvent;
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
|
namespace Service::NFP {
|
||||||
|
enum class CabinetMode : u8;
|
||||||
|
} // namespace Service::NFP
|
||||||
|
|
||||||
namespace Service::AM {
|
namespace Service::AM {
|
||||||
|
|
||||||
class IStorage;
|
class IStorage;
|
||||||
|
@ -41,6 +45,8 @@ class IStorage;
|
||||||
namespace Applets {
|
namespace Applets {
|
||||||
|
|
||||||
enum class AppletId : u32 {
|
enum class AppletId : u32 {
|
||||||
|
None = 0x00,
|
||||||
|
Application = 0x01,
|
||||||
OverlayDisplay = 0x02,
|
OverlayDisplay = 0x02,
|
||||||
QLaunch = 0x03,
|
QLaunch = 0x03,
|
||||||
Starter = 0x04,
|
Starter = 0x04,
|
||||||
|
@ -71,6 +77,32 @@ enum class LibraryAppletMode : u32 {
|
||||||
AllForegroundInitiallyHidden = 4,
|
AllForegroundInitiallyHidden = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class CommonArgumentVersion : u32 {
|
||||||
|
Version0,
|
||||||
|
Version1,
|
||||||
|
Version2,
|
||||||
|
Version3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CommonArgumentSize : u32 {
|
||||||
|
Version3 = 0x20,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ThemeColor : u32 {
|
||||||
|
BasicWhite = 0,
|
||||||
|
BasicBlack = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CommonArguments {
|
||||||
|
CommonArgumentVersion arguments_version;
|
||||||
|
CommonArgumentSize size;
|
||||||
|
u32 library_version;
|
||||||
|
ThemeColor theme_color;
|
||||||
|
bool play_startup_sound;
|
||||||
|
u64_le system_tick;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
|
||||||
|
|
||||||
class AppletDataBroker final {
|
class AppletDataBroker final {
|
||||||
public:
|
public:
|
||||||
explicit AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_);
|
explicit AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_);
|
||||||
|
@ -161,16 +193,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct CommonArguments {
|
|
||||||
u32_le arguments_version;
|
|
||||||
u32_le size;
|
|
||||||
u32_le library_version;
|
|
||||||
u32_le theme_color;
|
|
||||||
bool play_startup_sound;
|
|
||||||
u64_le system_tick;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
|
|
||||||
|
|
||||||
CommonArguments common_args{};
|
CommonArguments common_args{};
|
||||||
AppletDataBroker broker;
|
AppletDataBroker broker;
|
||||||
LibraryAppletMode applet_mode;
|
LibraryAppletMode applet_mode;
|
||||||
|
@ -219,8 +241,12 @@ public:
|
||||||
~AppletManager();
|
~AppletManager();
|
||||||
|
|
||||||
const AppletFrontendSet& GetAppletFrontendSet() const;
|
const AppletFrontendSet& GetAppletFrontendSet() const;
|
||||||
|
NFP::CabinetMode GetCabinetMode() const;
|
||||||
|
AppletId GetCurrentAppletId() const;
|
||||||
|
|
||||||
void SetAppletFrontendSet(AppletFrontendSet set);
|
void SetAppletFrontendSet(AppletFrontendSet set);
|
||||||
|
void SetCabinetMode(NFP::CabinetMode mode);
|
||||||
|
void SetCurrentAppletId(AppletId applet_id);
|
||||||
void SetDefaultAppletFrontendSet();
|
void SetDefaultAppletFrontendSet();
|
||||||
void SetDefaultAppletsIfMissing();
|
void SetDefaultAppletsIfMissing();
|
||||||
void ClearAll();
|
void ClearAll();
|
||||||
|
@ -228,6 +254,9 @@ public:
|
||||||
std::shared_ptr<Applet> GetApplet(AppletId id, LibraryAppletMode mode) const;
|
std::shared_ptr<Applet> GetApplet(AppletId id, LibraryAppletMode mode) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
AppletId current_applet_id{};
|
||||||
|
NFP::CabinetMode cabinet_mode{};
|
||||||
|
|
||||||
AppletFrontendSet frontend;
|
AppletFrontendSet frontend;
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
};
|
};
|
||||||
|
|
|
@ -855,6 +855,9 @@ FSP_SRV::FSP_SRV(Core::System& system_)
|
||||||
if (Settings::values.enable_fs_access_log) {
|
if (Settings::values.enable_fs_access_log) {
|
||||||
access_log_mode = AccessLogMode::SdCard;
|
access_log_mode = AccessLogMode::SdCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This should be true on creation
|
||||||
|
fsc.SetAutoSaveDataCreation(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
FSP_SRV::~FSP_SRV() = default;
|
FSP_SRV::~FSP_SRV() = default;
|
||||||
|
|
|
@ -23,19 +23,39 @@ public:
|
||||||
explicit IMonitorService(Core::System& system_) : ServiceFramework{system_, "IMonitorService"} {
|
explicit IMonitorService(Core::System& system_) : ServiceFramework{system_, "IMonitorService"} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, nullptr, "GetStateForMonitor"},
|
{0, &IMonitorService::GetStateForMonitor, "GetStateForMonitor"},
|
||||||
{1, nullptr, "GetNetworkInfoForMonitor"},
|
{1, nullptr, "GetNetworkInfoForMonitor"},
|
||||||
{2, nullptr, "GetIpv4AddressForMonitor"},
|
{2, nullptr, "GetIpv4AddressForMonitor"},
|
||||||
{3, nullptr, "GetDisconnectReasonForMonitor"},
|
{3, nullptr, "GetDisconnectReasonForMonitor"},
|
||||||
{4, nullptr, "GetSecurityParameterForMonitor"},
|
{4, nullptr, "GetSecurityParameterForMonitor"},
|
||||||
{5, nullptr, "GetNetworkConfigForMonitor"},
|
{5, nullptr, "GetNetworkConfigForMonitor"},
|
||||||
{100, nullptr, "InitializeMonitor"},
|
{100, &IMonitorService::InitializeMonitor, "InitializeMonitor"},
|
||||||
{101, nullptr, "FinalizeMonitor"},
|
{101, nullptr, "FinalizeMonitor"},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void GetStateForMonitor(HLERequestContext& ctx) {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushEnum(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeMonitor(HLERequestContext& ctx) {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
state = State::Initialized;
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
State state{State::None};
|
||||||
};
|
};
|
||||||
|
|
||||||
class LDNM final : public ServiceFramework<LDNM> {
|
class LDNM final : public ServiceFramework<LDNM> {
|
||||||
|
@ -731,14 +751,81 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ISfMonitorService final : public ServiceFramework<ISfMonitorService> {
|
||||||
|
public:
|
||||||
|
explicit ISfMonitorService(Core::System& system_)
|
||||||
|
: ServiceFramework{system_, "ISfMonitorService"} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, &ISfMonitorService::Initialize, "Initialize"},
|
||||||
|
{288, &ISfMonitorService::GetGroupInfo, "GetGroupInfo"},
|
||||||
|
{320, nullptr, "GetLinkLevel"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Initialize(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetGroupInfo(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
||||||
|
|
||||||
|
struct GroupInfo {
|
||||||
|
std::array<u8, 0x200> info;
|
||||||
|
};
|
||||||
|
|
||||||
|
GroupInfo group_info{};
|
||||||
|
|
||||||
|
ctx.WriteBuffer(group_info);
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class LP2PM final : public ServiceFramework<LP2PM> {
|
||||||
|
public:
|
||||||
|
explicit LP2PM(Core::System& system_) : ServiceFramework{system_, "lp2p:m"} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, &LP2PM::CreateMonitorService, "CreateMonitorService"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void CreateMonitorService(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const u64 reserved_input = rp.Pop<u64>();
|
||||||
|
|
||||||
|
LOG_INFO(Service_LDN, "called, reserved_input={}", reserved_input);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushIpcInterface<ISfMonitorService>(system);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void LoopProcess(Core::System& system) {
|
void LoopProcess(Core::System& system) {
|
||||||
auto server_manager = std::make_unique<ServerManager>(system);
|
auto server_manager = std::make_unique<ServerManager>(system);
|
||||||
|
|
||||||
server_manager->RegisterNamedService("ldn:m", std::make_shared<LDNM>(system));
|
server_manager->RegisterNamedService("ldn:m", std::make_shared<LDNM>(system));
|
||||||
server_manager->RegisterNamedService("ldn:s", std::make_shared<LDNS>(system));
|
server_manager->RegisterNamedService("ldn:s", std::make_shared<LDNS>(system));
|
||||||
server_manager->RegisterNamedService("ldn:u", std::make_shared<LDNU>(system));
|
server_manager->RegisterNamedService("ldn:u", std::make_shared<LDNU>(system));
|
||||||
|
|
||||||
server_manager->RegisterNamedService("lp2p:app", std::make_shared<LP2PAPP>(system));
|
server_manager->RegisterNamedService("lp2p:app", std::make_shared<LP2PAPP>(system));
|
||||||
server_manager->RegisterNamedService("lp2p:sys", std::make_shared<LP2PSYS>(system));
|
server_manager->RegisterNamedService("lp2p:sys", std::make_shared<LP2PSYS>(system));
|
||||||
|
server_manager->RegisterNamedService("lp2p:m", std::make_shared<LP2PM>(system));
|
||||||
|
|
||||||
ServerManager::RunServer(std::move(server_manager));
|
ServerManager::RunServer(std::move(server_manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -830,11 +830,6 @@ Result NfcDevice::SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& registe
|
||||||
return ResultWrongDeviceState;
|
return ResultWrongDeviceState;
|
||||||
}
|
}
|
||||||
|
|
||||||
Service::Mii::StoreData store_data{};
|
|
||||||
Service::Mii::NfpStoreDataExtension extension{};
|
|
||||||
store_data.BuildBase(Mii::Gender::Male);
|
|
||||||
extension.SetFromStoreData(store_data);
|
|
||||||
|
|
||||||
auto& settings = tag_data.settings;
|
auto& settings = tag_data.settings;
|
||||||
|
|
||||||
if (tag_data.settings.settings.amiibo_initialized == 0) {
|
if (tag_data.settings.settings.amiibo_initialized == 0) {
|
||||||
|
@ -843,8 +838,8 @@ Result NfcDevice::SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& registe
|
||||||
}
|
}
|
||||||
|
|
||||||
SetAmiiboName(settings, register_info.amiibo_name);
|
SetAmiiboName(settings, register_info.amiibo_name);
|
||||||
tag_data.owner_mii.BuildFromStoreData(store_data);
|
tag_data.owner_mii.BuildFromStoreData(register_info.mii_store_data);
|
||||||
tag_data.mii_extension = extension;
|
tag_data.mii_extension.SetFromStoreData(register_info.mii_store_data);
|
||||||
tag_data.unknown = 0;
|
tag_data.unknown = 0;
|
||||||
tag_data.unknown2 = {};
|
tag_data.unknown2 = {};
|
||||||
settings.country_code_id = 0;
|
settings.country_code_id = 0;
|
||||||
|
|
|
@ -45,13 +45,6 @@ public:
|
||||||
IsSharedMemMapped = 6
|
IsSharedMemMapped = 6
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
|
||||||
/// Id to use for the next handle that is created.
|
|
||||||
u32 next_handle = 0;
|
|
||||||
|
|
||||||
/// Id to use for the next object that is created.
|
|
||||||
u32 next_id = 0;
|
|
||||||
|
|
||||||
struct IocCreateParams {
|
struct IocCreateParams {
|
||||||
// Input
|
// Input
|
||||||
u32_le size{};
|
u32_le size{};
|
||||||
|
@ -113,6 +106,13 @@ private:
|
||||||
NvResult IocParam(std::span<const u8> input, std::span<u8> output);
|
NvResult IocParam(std::span<const u8> input, std::span<u8> output);
|
||||||
NvResult IocFree(std::span<const u8> input, std::span<u8> output);
|
NvResult IocFree(std::span<const u8> input, std::span<u8> output);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Id to use for the next handle that is created.
|
||||||
|
u32 next_handle = 0;
|
||||||
|
|
||||||
|
/// Id to use for the next object that is created.
|
||||||
|
u32 next_id = 0;
|
||||||
|
|
||||||
NvCore::Container& container;
|
NvCore::Container& container;
|
||||||
NvCore::NvMap& file;
|
NvCore::NvMap& file;
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
namespace Service::android {
|
namespace Service::android {
|
||||||
|
|
||||||
class GraphicBuffer;
|
struct GraphicBuffer;
|
||||||
|
|
||||||
class BufferItem final {
|
class BufferItem final {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
namespace Service::android {
|
namespace Service::android {
|
||||||
|
|
||||||
class GraphicBuffer;
|
struct GraphicBuffer;
|
||||||
|
|
||||||
enum class BufferState : u32 {
|
enum class BufferState : u32 {
|
||||||
Free = 0,
|
Free = 0,
|
||||||
|
|
351
src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
Normal file
351
src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
Normal file
|
@ -0,0 +1,351 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/hle/kernel/k_process.h"
|
||||||
|
#include "core/hle/kernel/k_system_resource.h"
|
||||||
|
#include "core/hle/service/nvdrv/devices/nvmap.h"
|
||||||
|
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||||
|
#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
|
||||||
|
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
||||||
|
#include "core/hle/service/nvnflinger/pixel_format.h"
|
||||||
|
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
|
||||||
|
#include "core/hle/service/vi/layer/vi_layer.h"
|
||||||
|
#include "core/hle/service/vi/vi_results.h"
|
||||||
|
|
||||||
|
namespace Service::Nvnflinger {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
|
||||||
|
std::unique_ptr<Kernel::KPageGroup>* out_page_group,
|
||||||
|
Core::System& system, u32 size) {
|
||||||
|
using Core::Memory::YUZU_PAGESIZE;
|
||||||
|
|
||||||
|
// Allocate memory for the system shared buffer.
|
||||||
|
// FIXME: Because the gmmu can only point to cpu addresses, we need
|
||||||
|
// to map this in the application space to allow it to be used.
|
||||||
|
// FIXME: Add proper smmu emulation.
|
||||||
|
// FIXME: This memory belongs to vi's .data section.
|
||||||
|
auto& kernel = system.Kernel();
|
||||||
|
auto* process = system.ApplicationProcess();
|
||||||
|
auto& page_table = process->GetPageTable();
|
||||||
|
|
||||||
|
// Hold a temporary page group reference while we try to map it.
|
||||||
|
auto pg = std::make_unique<Kernel::KPageGroup>(
|
||||||
|
kernel, std::addressof(kernel.GetSystemSystemResource().GetBlockInfoManager()));
|
||||||
|
|
||||||
|
// Allocate memory from secure pool.
|
||||||
|
R_TRY(kernel.MemoryManager().AllocateAndOpen(
|
||||||
|
pg.get(), size / YUZU_PAGESIZE,
|
||||||
|
Kernel::KMemoryManager::EncodeOption(Kernel::KMemoryManager::Pool::Secure,
|
||||||
|
Kernel::KMemoryManager::Direction::FromBack)));
|
||||||
|
|
||||||
|
// Get bounds of where mapping is possible.
|
||||||
|
const VAddr alias_code_begin = GetInteger(page_table.GetAliasCodeRegionStart());
|
||||||
|
const VAddr alias_code_size = page_table.GetAliasCodeRegionSize() / YUZU_PAGESIZE;
|
||||||
|
const auto state = Kernel::KMemoryState::Io;
|
||||||
|
const auto perm = Kernel::KMemoryPermission::UserReadWrite;
|
||||||
|
std::mt19937_64 rng{process->GetRandomEntropy(0)};
|
||||||
|
|
||||||
|
// Retry up to 64 times to map into alias code range.
|
||||||
|
Result res = ResultSuccess;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 64; i++) {
|
||||||
|
*out_map_address = alias_code_begin + ((rng() % alias_code_size) * YUZU_PAGESIZE);
|
||||||
|
res = page_table.MapPageGroup(*out_map_address, *pg, state, perm);
|
||||||
|
if (R_SUCCEEDED(res)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return failure, if necessary
|
||||||
|
R_UNLESS(i < 64, res);
|
||||||
|
|
||||||
|
// Return the mapped page group.
|
||||||
|
*out_page_group = std::move(pg);
|
||||||
|
|
||||||
|
// We succeeded.
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::span<u8> SerializeIoc(T& params) {
|
||||||
|
return std::span(reinterpret_cast<u8*>(std::addressof(params)), sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, u32 size) {
|
||||||
|
// Create a handle.
|
||||||
|
Nvidia::Devices::nvmap::IocCreateParams create_in_params{
|
||||||
|
.size = size,
|
||||||
|
.handle = 0,
|
||||||
|
};
|
||||||
|
Nvidia::Devices::nvmap::IocCreateParams create_out_params{};
|
||||||
|
R_UNLESS(nvmap.IocCreate(SerializeIoc(create_in_params), SerializeIoc(create_out_params)) ==
|
||||||
|
Nvidia::NvResult::Success,
|
||||||
|
VI::ResultOperationFailed);
|
||||||
|
|
||||||
|
// Assign the output handle.
|
||||||
|
*out_nv_map_handle = create_out_params.handle;
|
||||||
|
|
||||||
|
// We succeeded.
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) {
|
||||||
|
// Free the handle.
|
||||||
|
Nvidia::Devices::nvmap::IocFreeParams free_in_params{
|
||||||
|
.handle = handle,
|
||||||
|
};
|
||||||
|
Nvidia::Devices::nvmap::IocFreeParams free_out_params{};
|
||||||
|
R_UNLESS(nvmap.IocFree(SerializeIoc(free_in_params), SerializeIoc(free_out_params)) ==
|
||||||
|
Nvidia::NvResult::Success,
|
||||||
|
VI::ResultOperationFailed);
|
||||||
|
|
||||||
|
// We succeeded.
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer,
|
||||||
|
u32 size) {
|
||||||
|
// Assign the allocated memory to the handle.
|
||||||
|
Nvidia::Devices::nvmap::IocAllocParams alloc_in_params{
|
||||||
|
.handle = handle,
|
||||||
|
.heap_mask = 0,
|
||||||
|
.flags = {},
|
||||||
|
.align = 0,
|
||||||
|
.kind = 0,
|
||||||
|
.address = GetInteger(buffer),
|
||||||
|
};
|
||||||
|
Nvidia::Devices::nvmap::IocAllocParams alloc_out_params{};
|
||||||
|
R_UNLESS(nvmap.IocAlloc(SerializeIoc(alloc_in_params), SerializeIoc(alloc_out_params)) ==
|
||||||
|
Nvidia::NvResult::Success,
|
||||||
|
VI::ResultOperationFailed);
|
||||||
|
|
||||||
|
// We succeeded.
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv,
|
||||||
|
Common::ProcessAddress buffer, u32 size) {
|
||||||
|
// Get the nvmap device.
|
||||||
|
auto nvmap_fd = nvdrv.Open("/dev/nvmap");
|
||||||
|
auto nvmap = nvdrv.GetDevice<Nvidia::Devices::nvmap>(nvmap_fd);
|
||||||
|
ASSERT(nvmap != nullptr);
|
||||||
|
|
||||||
|
// Create a handle.
|
||||||
|
R_TRY(CreateNvMapHandle(out_handle, *nvmap, size));
|
||||||
|
|
||||||
|
// Ensure we maintain a clean state on failure.
|
||||||
|
ON_RESULT_FAILURE {
|
||||||
|
ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle)));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Assign the allocated memory to the handle.
|
||||||
|
R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888;
|
||||||
|
constexpr u32 SharedBufferBlockLinearBpp = 4;
|
||||||
|
|
||||||
|
constexpr u32 SharedBufferBlockLinearWidth = 1280;
|
||||||
|
constexpr u32 SharedBufferBlockLinearHeight = 768;
|
||||||
|
constexpr u32 SharedBufferBlockLinearStride =
|
||||||
|
SharedBufferBlockLinearWidth * SharedBufferBlockLinearBpp;
|
||||||
|
constexpr u32 SharedBufferNumSlots = 7;
|
||||||
|
|
||||||
|
constexpr u32 SharedBufferWidth = 1280;
|
||||||
|
constexpr u32 SharedBufferHeight = 720;
|
||||||
|
constexpr u32 SharedBufferAsync = false;
|
||||||
|
|
||||||
|
constexpr u32 SharedBufferSlotSize =
|
||||||
|
SharedBufferBlockLinearWidth * SharedBufferBlockLinearHeight * SharedBufferBlockLinearBpp;
|
||||||
|
constexpr u32 SharedBufferSize = SharedBufferSlotSize * SharedBufferNumSlots;
|
||||||
|
|
||||||
|
constexpr SharedMemoryPoolLayout SharedBufferPoolLayout = [] {
|
||||||
|
SharedMemoryPoolLayout layout{};
|
||||||
|
layout.num_slots = SharedBufferNumSlots;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < SharedBufferNumSlots; i++) {
|
||||||
|
layout.slots[i].buffer_offset = i * SharedBufferSlotSize;
|
||||||
|
layout.slots[i].size = SharedBufferSlotSize;
|
||||||
|
layout.slots[i].width = SharedBufferWidth;
|
||||||
|
layout.slots[i].height = SharedBufferHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return layout;
|
||||||
|
}();
|
||||||
|
|
||||||
|
void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) {
|
||||||
|
auto buffer = std::make_shared<android::GraphicBuffer>();
|
||||||
|
buffer->width = SharedBufferWidth;
|
||||||
|
buffer->height = SharedBufferHeight;
|
||||||
|
buffer->stride = SharedBufferBlockLinearStride;
|
||||||
|
buffer->format = SharedBufferBlockLinearFormat;
|
||||||
|
buffer->buffer_id = handle;
|
||||||
|
buffer->offset = slot * SharedBufferSlotSize;
|
||||||
|
ASSERT(producer.SetPreallocatedBuffer(slot, buffer) == android::Status::NoError);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
FbShareBufferManager::FbShareBufferManager(Core::System& system, Nvnflinger& flinger,
|
||||||
|
std::shared_ptr<Nvidia::Module> nvdrv)
|
||||||
|
: m_system(system), m_flinger(flinger), m_nvdrv(std::move(nvdrv)) {}
|
||||||
|
|
||||||
|
FbShareBufferManager::~FbShareBufferManager() = default;
|
||||||
|
|
||||||
|
Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u64 display_id) {
|
||||||
|
std::scoped_lock lk{m_guard};
|
||||||
|
|
||||||
|
// Ensure we have not already created a buffer.
|
||||||
|
R_UNLESS(m_buffer_id == 0, VI::ResultOperationFailed);
|
||||||
|
|
||||||
|
// Allocate memory and space for the shared buffer.
|
||||||
|
Common::ProcessAddress map_address;
|
||||||
|
R_TRY(AllocateIoForProcessAddressSpace(std::addressof(map_address),
|
||||||
|
std::addressof(m_buffer_page_group), m_system,
|
||||||
|
SharedBufferSize));
|
||||||
|
|
||||||
|
// Create an nvmap handle for the buffer and assign the memory to it.
|
||||||
|
R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, map_address,
|
||||||
|
SharedBufferSize));
|
||||||
|
|
||||||
|
// Record the display id.
|
||||||
|
m_display_id = display_id;
|
||||||
|
|
||||||
|
// Create a layer for the display.
|
||||||
|
m_layer_id = m_flinger.CreateLayer(m_display_id).value();
|
||||||
|
|
||||||
|
// Set up the buffer.
|
||||||
|
m_buffer_id = m_next_buffer_id++;
|
||||||
|
|
||||||
|
// Get the layer.
|
||||||
|
VI::Layer* layer = m_flinger.FindLayer(m_display_id, m_layer_id);
|
||||||
|
ASSERT(layer != nullptr);
|
||||||
|
|
||||||
|
// Get the producer and set preallocated buffers.
|
||||||
|
auto& producer = layer->GetBufferQueue();
|
||||||
|
MakeGraphicBuffer(producer, 0, m_buffer_nvmap_handle);
|
||||||
|
MakeGraphicBuffer(producer, 1, m_buffer_nvmap_handle);
|
||||||
|
|
||||||
|
// Assign outputs.
|
||||||
|
*out_buffer_id = m_buffer_id;
|
||||||
|
*out_layer_id = m_layer_id;
|
||||||
|
|
||||||
|
// We succeeded.
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
|
||||||
|
s32* out_nvmap_handle,
|
||||||
|
SharedMemoryPoolLayout* out_pool_layout,
|
||||||
|
u64 buffer_id,
|
||||||
|
u64 applet_resource_user_id) {
|
||||||
|
std::scoped_lock lk{m_guard};
|
||||||
|
|
||||||
|
R_UNLESS(m_buffer_id > 0, VI::ResultNotFound);
|
||||||
|
R_UNLESS(buffer_id == m_buffer_id, VI::ResultNotFound);
|
||||||
|
|
||||||
|
*out_pool_layout = SharedBufferPoolLayout;
|
||||||
|
*out_buffer_size = SharedBufferSize;
|
||||||
|
*out_nvmap_handle = m_buffer_nvmap_handle;
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FbShareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) {
|
||||||
|
// Ensure the layer id is valid.
|
||||||
|
R_UNLESS(m_layer_id > 0 && layer_id == m_layer_id, VI::ResultNotFound);
|
||||||
|
|
||||||
|
// Get the layer.
|
||||||
|
VI::Layer* layer = m_flinger.FindLayer(m_display_id, layer_id);
|
||||||
|
R_UNLESS(layer != nullptr, VI::ResultNotFound);
|
||||||
|
|
||||||
|
// We succeeded.
|
||||||
|
*out_layer = layer;
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FbShareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
|
||||||
|
std::array<s32, 4>& out_slot_indexes,
|
||||||
|
s64* out_target_slot, u64 layer_id) {
|
||||||
|
std::scoped_lock lk{m_guard};
|
||||||
|
|
||||||
|
// Get the layer.
|
||||||
|
VI::Layer* layer;
|
||||||
|
R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
|
||||||
|
|
||||||
|
// Get the producer.
|
||||||
|
auto& producer = layer->GetBufferQueue();
|
||||||
|
|
||||||
|
// Get the next buffer from the producer.
|
||||||
|
s32 slot;
|
||||||
|
R_UNLESS(producer.DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0,
|
||||||
|
SharedBufferWidth, SharedBufferHeight,
|
||||||
|
SharedBufferBlockLinearFormat, 0) == android::Status::NoError,
|
||||||
|
VI::ResultOperationFailed);
|
||||||
|
|
||||||
|
// Assign remaining outputs.
|
||||||
|
*out_target_slot = slot;
|
||||||
|
out_slot_indexes = {0, 1, -1, -1};
|
||||||
|
|
||||||
|
// We succeeded.
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence,
|
||||||
|
Common::Rectangle<s32> crop_region,
|
||||||
|
u32 transform, s32 swap_interval,
|
||||||
|
u64 layer_id, s64 slot) {
|
||||||
|
std::scoped_lock lk{m_guard};
|
||||||
|
|
||||||
|
// Get the layer.
|
||||||
|
VI::Layer* layer;
|
||||||
|
R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
|
||||||
|
|
||||||
|
// Get the producer.
|
||||||
|
auto& producer = layer->GetBufferQueue();
|
||||||
|
|
||||||
|
// Request to queue the buffer.
|
||||||
|
std::shared_ptr<android::GraphicBuffer> buffer;
|
||||||
|
R_UNLESS(producer.RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) ==
|
||||||
|
android::Status::NoError,
|
||||||
|
VI::ResultOperationFailed);
|
||||||
|
|
||||||
|
// Queue the buffer to the producer.
|
||||||
|
android::QueueBufferInput input{};
|
||||||
|
android::QueueBufferOutput output{};
|
||||||
|
input.crop = crop_region;
|
||||||
|
input.fence = fence;
|
||||||
|
input.transform = static_cast<android::NativeWindowTransform>(transform);
|
||||||
|
input.swap_interval = swap_interval;
|
||||||
|
R_UNLESS(producer.QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) ==
|
||||||
|
android::Status::NoError,
|
||||||
|
VI::ResultOperationFailed);
|
||||||
|
|
||||||
|
// We succeeded.
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FbShareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event,
|
||||||
|
u64 layer_id) {
|
||||||
|
std::scoped_lock lk{m_guard};
|
||||||
|
|
||||||
|
// Get the layer.
|
||||||
|
VI::Layer* layer;
|
||||||
|
R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
|
||||||
|
|
||||||
|
// Get the producer.
|
||||||
|
auto& producer = layer->GetBufferQueue();
|
||||||
|
|
||||||
|
// Set the event.
|
||||||
|
*out_event = std::addressof(producer.GetNativeHandle());
|
||||||
|
|
||||||
|
// We succeeded.
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::Nvnflinger
|
65
src/core/hle/service/nvnflinger/fb_share_buffer_manager.h
Normal file
65
src/core/hle/service/nvnflinger/fb_share_buffer_manager.h
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/math_util.h"
|
||||||
|
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||||
|
#include "core/hle/service/nvnflinger/ui/fence.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
class KPageGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::Nvnflinger {
|
||||||
|
|
||||||
|
struct SharedMemorySlot {
|
||||||
|
u64 buffer_offset;
|
||||||
|
u64 size;
|
||||||
|
s32 width;
|
||||||
|
s32 height;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SharedMemorySlot) == 0x18, "SharedMemorySlot has wrong size");
|
||||||
|
|
||||||
|
struct SharedMemoryPoolLayout {
|
||||||
|
s32 num_slots;
|
||||||
|
std::array<SharedMemorySlot, 0x10> slots;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size");
|
||||||
|
|
||||||
|
class FbShareBufferManager final {
|
||||||
|
public:
|
||||||
|
explicit FbShareBufferManager(Core::System& system, Nvnflinger& flinger,
|
||||||
|
std::shared_ptr<Nvidia::Module> nvdrv);
|
||||||
|
~FbShareBufferManager();
|
||||||
|
|
||||||
|
Result Initialize(u64* out_buffer_id, u64* out_layer_handle, u64 display_id);
|
||||||
|
Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle,
|
||||||
|
SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id,
|
||||||
|
u64 applet_resource_user_id);
|
||||||
|
Result AcquireSharedFrameBuffer(android::Fence* out_fence, std::array<s32, 4>& out_slots,
|
||||||
|
s64* out_target_slot, u64 layer_id);
|
||||||
|
Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region,
|
||||||
|
u32 transform, s32 swap_interval, u64 layer_id, s64 slot);
|
||||||
|
Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
u64 m_next_buffer_id = 1;
|
||||||
|
u64 m_display_id = 0;
|
||||||
|
u64 m_buffer_id = 0;
|
||||||
|
u64 m_layer_id = 0;
|
||||||
|
u32 m_buffer_nvmap_handle = 0;
|
||||||
|
SharedMemoryPoolLayout m_pool_layout = {};
|
||||||
|
|
||||||
|
std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
|
||||||
|
|
||||||
|
std::mutex m_guard;
|
||||||
|
Core::System& m_system;
|
||||||
|
Nvnflinger& m_flinger;
|
||||||
|
std::shared_ptr<Nvidia::Module> m_nvdrv;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Nvnflinger
|
|
@ -19,6 +19,7 @@ class InputParcel;
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct QueueBufferInput final {
|
struct QueueBufferInput final {
|
||||||
explicit QueueBufferInput(InputParcel& parcel);
|
explicit QueueBufferInput(InputParcel& parcel);
|
||||||
|
explicit QueueBufferInput() = default;
|
||||||
|
|
||||||
void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Common::Rectangle<s32>* crop_,
|
void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Common::Rectangle<s32>* crop_,
|
||||||
NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_,
|
NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_,
|
||||||
|
@ -34,7 +35,6 @@ struct QueueBufferInput final {
|
||||||
*fence_ = fence;
|
*fence_ = fence;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
s64 timestamp{};
|
s64 timestamp{};
|
||||||
s32 is_auto_timestamp{};
|
s32 is_auto_timestamp{};
|
||||||
Common::Rectangle<s32> crop{};
|
Common::Rectangle<s32> crop{};
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||||
#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
|
#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
|
||||||
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
|
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
|
||||||
|
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
||||||
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
|
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
|
||||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||||
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
|
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
|
||||||
|
@ -331,4 +332,14 @@ s64 Nvnflinger::GetNextTicks() const {
|
||||||
return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
|
return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FbShareBufferManager& Nvnflinger::GetSystemBufferManager() {
|
||||||
|
const auto lock_guard = Lock();
|
||||||
|
|
||||||
|
if (!system_buffer_manager) {
|
||||||
|
system_buffer_manager = std::make_unique<FbShareBufferManager>(system, *this, nvdrv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *system_buffer_manager;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Service::Nvnflinger
|
} // namespace Service::Nvnflinger
|
||||||
|
|
|
@ -45,6 +45,9 @@ class BufferQueueProducer;
|
||||||
|
|
||||||
namespace Service::Nvnflinger {
|
namespace Service::Nvnflinger {
|
||||||
|
|
||||||
|
class FbShareBufferManager;
|
||||||
|
class HosBinderDriverServer;
|
||||||
|
|
||||||
class Nvnflinger final {
|
class Nvnflinger final {
|
||||||
public:
|
public:
|
||||||
explicit Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_);
|
explicit Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_);
|
||||||
|
@ -90,12 +93,16 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] s64 GetNextTicks() const;
|
[[nodiscard]] s64 GetNextTicks() const;
|
||||||
|
|
||||||
|
FbShareBufferManager& GetSystemBufferManager();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Layer {
|
struct Layer {
|
||||||
std::unique_ptr<android::BufferQueueCore> core;
|
std::unique_ptr<android::BufferQueueCore> core;
|
||||||
std::unique_ptr<android::BufferQueueProducer> producer;
|
std::unique_ptr<android::BufferQueueProducer> producer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
friend class FbShareBufferManager;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] std::unique_lock<std::mutex> Lock() const {
|
[[nodiscard]] std::unique_lock<std::mutex> Lock() const {
|
||||||
return std::unique_lock{*guard};
|
return std::unique_lock{*guard};
|
||||||
|
@ -140,6 +147,8 @@ private:
|
||||||
std::shared_ptr<Core::Timing::EventType> multi_composition_event;
|
std::shared_ptr<Core::Timing::EventType> multi_composition_event;
|
||||||
std::shared_ptr<Core::Timing::EventType> single_composition_event;
|
std::shared_ptr<Core::Timing::EventType> single_composition_event;
|
||||||
|
|
||||||
|
std::unique_ptr<FbShareBufferManager> system_buffer_manager;
|
||||||
|
|
||||||
std::shared_ptr<std::mutex> guard;
|
std::shared_ptr<std::mutex> guard;
|
||||||
|
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
|
|
@ -20,6 +20,9 @@ public:
|
||||||
static constexpr Fence NoFence() {
|
static constexpr Fence NoFence() {
|
||||||
Fence fence;
|
Fence fence;
|
||||||
fence.fences[0].id = -1;
|
fence.fences[0].id = -1;
|
||||||
|
fence.fences[1].id = -1;
|
||||||
|
fence.fences[2].id = -1;
|
||||||
|
fence.fences[3].id = -1;
|
||||||
return fence;
|
return fence;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,7 @@
|
||||||
|
|
||||||
namespace Service::android {
|
namespace Service::android {
|
||||||
|
|
||||||
class GraphicBuffer final {
|
struct GraphicBuffer final {
|
||||||
public:
|
|
||||||
constexpr GraphicBuffer() = default;
|
constexpr GraphicBuffer() = default;
|
||||||
|
|
||||||
constexpr GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
|
constexpr GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
|
||||||
|
@ -77,7 +76,6 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
u32 magic{};
|
u32 magic{};
|
||||||
s32 width{};
|
s32 width{};
|
||||||
s32 height{};
|
s32 height{};
|
||||||
|
|
|
@ -20,9 +20,12 @@
|
||||||
#include "core/hle/kernel/k_readable_event.h"
|
#include "core/hle/kernel/k_readable_event.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
|
#include "core/hle/service/nvdrv/devices/nvmap.h"
|
||||||
#include "core/hle/service/nvdrv/nvdata.h"
|
#include "core/hle/service/nvdrv/nvdata.h"
|
||||||
|
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||||
#include "core/hle/service/nvnflinger/binder.h"
|
#include "core/hle/service/nvnflinger/binder.h"
|
||||||
#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
|
#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
|
||||||
|
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
||||||
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
|
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
|
||||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||||
#include "core/hle/service/nvnflinger/parcel.h"
|
#include "core/hle/service/nvnflinger/parcel.h"
|
||||||
|
@ -131,8 +134,9 @@ private:
|
||||||
|
|
||||||
class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
|
class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
|
||||||
public:
|
public:
|
||||||
explicit ISystemDisplayService(Core::System& system_)
|
explicit ISystemDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_)
|
||||||
: ServiceFramework{system_, "ISystemDisplayService"} {
|
: ServiceFramework{system_, "ISystemDisplayService"}, nvnflinger{nvnflinger_} {
|
||||||
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{1200, nullptr, "GetZOrderCountMin"},
|
{1200, nullptr, "GetZOrderCountMin"},
|
||||||
{1202, nullptr, "GetZOrderCountMax"},
|
{1202, nullptr, "GetZOrderCountMax"},
|
||||||
|
@ -170,22 +174,126 @@ public:
|
||||||
{3217, nullptr, "SetDisplayCmuLuma"},
|
{3217, nullptr, "SetDisplayCmuLuma"},
|
||||||
{3218, nullptr, "SetDisplayCrcMode"},
|
{3218, nullptr, "SetDisplayCrcMode"},
|
||||||
{6013, nullptr, "GetLayerPresentationSubmissionTimestamps"},
|
{6013, nullptr, "GetLayerPresentationSubmissionTimestamps"},
|
||||||
{8225, nullptr, "GetSharedBufferMemoryHandleId"},
|
{8225, &ISystemDisplayService::GetSharedBufferMemoryHandleId, "GetSharedBufferMemoryHandleId"},
|
||||||
{8250, nullptr, "OpenSharedLayer"},
|
{8250, &ISystemDisplayService::OpenSharedLayer, "OpenSharedLayer"},
|
||||||
{8251, nullptr, "CloseSharedLayer"},
|
{8251, nullptr, "CloseSharedLayer"},
|
||||||
{8252, nullptr, "ConnectSharedLayer"},
|
{8252, &ISystemDisplayService::ConnectSharedLayer, "ConnectSharedLayer"},
|
||||||
{8253, nullptr, "DisconnectSharedLayer"},
|
{8253, nullptr, "DisconnectSharedLayer"},
|
||||||
{8254, nullptr, "AcquireSharedFrameBuffer"},
|
{8254, &ISystemDisplayService::AcquireSharedFrameBuffer, "AcquireSharedFrameBuffer"},
|
||||||
{8255, nullptr, "PresentSharedFrameBuffer"},
|
{8255, &ISystemDisplayService::PresentSharedFrameBuffer, "PresentSharedFrameBuffer"},
|
||||||
{8256, nullptr, "GetSharedFrameBufferAcquirableEvent"},
|
{8256, &ISystemDisplayService::GetSharedFrameBufferAcquirableEvent, "GetSharedFrameBufferAcquirableEvent"},
|
||||||
{8257, nullptr, "FillSharedFrameBufferColor"},
|
{8257, nullptr, "FillSharedFrameBufferColor"},
|
||||||
{8258, nullptr, "CancelSharedFrameBuffer"},
|
{8258, nullptr, "CancelSharedFrameBuffer"},
|
||||||
{9000, nullptr, "GetDp2hdmiController"},
|
{9000, nullptr, "GetDp2hdmiController"},
|
||||||
};
|
};
|
||||||
|
// clang-format on
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void GetSharedBufferMemoryHandleId(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const u64 buffer_id = rp.PopRaw<u64>();
|
||||||
|
|
||||||
|
LOG_INFO(Service_VI, "called. buffer_id={:#x}", buffer_id);
|
||||||
|
|
||||||
|
struct OutputParameters {
|
||||||
|
s32 nvmap_handle;
|
||||||
|
u64 size;
|
||||||
|
};
|
||||||
|
|
||||||
|
OutputParameters out{};
|
||||||
|
Nvnflinger::SharedMemoryPoolLayout layout{};
|
||||||
|
const auto result = nvnflinger.GetSystemBufferManager().GetSharedBufferMemoryHandleId(
|
||||||
|
&out.size, &out.nvmap_handle, &layout, buffer_id, 0);
|
||||||
|
|
||||||
|
ctx.WriteBuffer(&layout, sizeof(layout));
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 6};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.PushRaw(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenSharedLayer(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const u64 layer_id = rp.PopRaw<u64>();
|
||||||
|
|
||||||
|
LOG_INFO(Service_VI, "(STUBBED) called. layer_id={:#x}", layer_id);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectSharedLayer(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const u64 layer_id = rp.PopRaw<u64>();
|
||||||
|
|
||||||
|
LOG_INFO(Service_VI, "(STUBBED) called. layer_id={:#x}", layer_id);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetSharedFrameBufferAcquirableEvent(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_VI, "called");
|
||||||
|
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const u64 layer_id = rp.PopRaw<u64>();
|
||||||
|
|
||||||
|
Kernel::KReadableEvent* event{};
|
||||||
|
const auto result = nvnflinger.GetSystemBufferManager().GetSharedFrameBufferAcquirableEvent(
|
||||||
|
&event, layer_id);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.PushCopyObjects(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AcquireSharedFrameBuffer(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_VI, "called");
|
||||||
|
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const u64 layer_id = rp.PopRaw<u64>();
|
||||||
|
|
||||||
|
struct OutputParameters {
|
||||||
|
android::Fence fence;
|
||||||
|
std::array<s32, 4> slots;
|
||||||
|
s64 target_slot;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(OutputParameters) == 0x40, "OutputParameters has wrong size");
|
||||||
|
|
||||||
|
OutputParameters out{};
|
||||||
|
const auto result = nvnflinger.GetSystemBufferManager().AcquireSharedFrameBuffer(
|
||||||
|
&out.fence, out.slots, &out.target_slot, layer_id);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 18};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.PushRaw(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PresentSharedFrameBuffer(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_VI, "called");
|
||||||
|
|
||||||
|
struct InputParameters {
|
||||||
|
android::Fence fence;
|
||||||
|
Common::Rectangle<s32> crop_region;
|
||||||
|
u32 window_transform;
|
||||||
|
s32 swap_interval;
|
||||||
|
u64 layer_id;
|
||||||
|
s64 surface_id;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(InputParameters) == 0x50, "InputParameters has wrong size");
|
||||||
|
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
auto input = rp.PopRaw<InputParameters>();
|
||||||
|
|
||||||
|
const auto result = nvnflinger.GetSystemBufferManager().PresentSharedFrameBuffer(
|
||||||
|
input.fence, input.crop_region, input.window_transform, input.swap_interval,
|
||||||
|
input.layer_id, input.surface_id);
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
void SetLayerZ(HLERequestContext& ctx) {
|
void SetLayerZ(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const u64 layer_id = rp.Pop<u64>();
|
const u64 layer_id = rp.Pop<u64>();
|
||||||
|
@ -228,6 +336,9 @@ private:
|
||||||
rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games.
|
rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games.
|
||||||
rb.Push<u32>(0);
|
rb.Push<u32>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Nvnflinger::Nvnflinger& nvnflinger;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
|
class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
|
||||||
|
@ -453,7 +564,7 @@ private:
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushIpcInterface<ISystemDisplayService>(system);
|
rb.PushIpcInterface<ISystemDisplayService>(system, nv_flinger);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetManagerDisplayService(HLERequestContext& ctx) {
|
void GetManagerDisplayService(HLERequestContext& ctx) {
|
||||||
|
|
|
@ -118,7 +118,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
|
||||||
return {ResultStatus::ErrorMissingNPDM, {}};
|
return {ResultStatus::ErrorMissingNPDM, {}};
|
||||||
}
|
}
|
||||||
|
|
||||||
const ResultStatus result2 = metadata.Load(npdm);
|
const ResultStatus result2 = metadata.Reload(npdm);
|
||||||
if (result2 != ResultStatus::Success) {
|
if (result2 != ResultStatus::Success) {
|
||||||
return {result2, {}};
|
return {result2, {}};
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ public:
|
||||||
* @param player_index the player number that will take this action
|
* @param player_index the player number that will take this action
|
||||||
* @param delta_timestamp time passed since last reading
|
* @param delta_timestamp time passed since last reading
|
||||||
* @param gyro_x,gyro_y,gyro_z the gyro sensor readings
|
* @param gyro_x,gyro_y,gyro_z the gyro sensor readings
|
||||||
* @param accel_x,accel_y,accel_z the acelerometer reading
|
* @param accel_x,accel_y,accel_z the accelerometer reading
|
||||||
*/
|
*/
|
||||||
void SetMotionState(std::size_t player_index, u64 delta_timestamp, float gyro_x, float gyro_y,
|
void SetMotionState(std::size_t player_index, u64 delta_timestamp, float gyro_x, float gyro_y,
|
||||||
float gyro_z, float accel_x, float accel_y, float accel_z);
|
float gyro_z, float accel_x, float accel_y, float accel_z);
|
||||||
|
|
|
@ -55,7 +55,7 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the motion sensor with the specified parameters
|
* Configures the motion sensor with the specified parameters
|
||||||
* @param gsen gyroscope sensor sensitvity in degrees per second
|
* @param gsen gyroscope sensor sensitivity in degrees per second
|
||||||
* @param gfrec gyroscope sensor frequency in hertz
|
* @param gfrec gyroscope sensor frequency in hertz
|
||||||
* @param asen accelerometer sensitivity in G force
|
* @param asen accelerometer sensitivity in G force
|
||||||
* @param afrec accelerometer frequency in hertz
|
* @param afrec accelerometer frequency in hertz
|
||||||
|
|
|
@ -55,7 +55,7 @@ void CompositeInsert(EmitContext& ctx, IR::Inst& inst, Register composite, Objec
|
||||||
"MOV.{} {}.{},{};",
|
"MOV.{} {}.{},{};",
|
||||||
type, ret, composite, type, ret, swizzle, object);
|
type, ret, composite, type, ret, swizzle, object);
|
||||||
} else {
|
} else {
|
||||||
// The return value is alised so we can just insert the object, it doesn't matter if it's
|
// The return value is aliased so we can just insert the object, it doesn't matter if it's
|
||||||
// aliased
|
// aliased
|
||||||
ctx.Add("MOV.{} {}.{},{};", type, ret, swizzle, object);
|
ctx.Add("MOV.{} {}.{},{};", type, ret, swizzle, object);
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,7 @@ private:
|
||||||
u32 method_count; ///< Current method count
|
u32 method_count; ///< Current method count
|
||||||
u32 length_pending; ///< Large NI command length pending
|
u32 length_pending; ///< Large NI command length pending
|
||||||
GPUVAddr dma_get; ///< Currently read segment
|
GPUVAddr dma_get; ///< Currently read segment
|
||||||
u64 dma_word_offset; ///< Current word ofset from address
|
u64 dma_word_offset; ///< Current word offset from address
|
||||||
bool non_incrementing; ///< Current command's NI flag
|
bool non_incrementing; ///< Current command's NI flag
|
||||||
bool is_last_call;
|
bool is_last_call;
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,6 +19,7 @@ set(SHADER_FILES
|
||||||
block_linear_unswizzle_2d.comp
|
block_linear_unswizzle_2d.comp
|
||||||
block_linear_unswizzle_3d.comp
|
block_linear_unswizzle_3d.comp
|
||||||
convert_abgr8_to_d24s8.frag
|
convert_abgr8_to_d24s8.frag
|
||||||
|
convert_d32f_to_abgr8.frag
|
||||||
convert_d24s8_to_abgr8.frag
|
convert_d24s8_to_abgr8.frag
|
||||||
convert_depth_to_float.frag
|
convert_depth_to_float.frag
|
||||||
convert_float_to_depth.frag
|
convert_float_to_depth.frag
|
||||||
|
|
14
src/video_core/host_shaders/convert_d32f_to_abgr8.frag
Normal file
14
src/video_core/host_shaders/convert_d32f_to_abgr8.frag
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(binding = 0) uniform sampler2D depth_tex;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
ivec2 coord = ivec2(gl_FragCoord.xy);
|
||||||
|
float depth = textureLod(depth_tex, coord, 0).r;
|
||||||
|
color = vec4(depth, depth, depth, 1.0);
|
||||||
|
}
|
|
@ -82,6 +82,7 @@ public:
|
||||||
size_t new_index = bank_indices.front();
|
size_t new_index = bank_indices.front();
|
||||||
bank_indices.pop_front();
|
bank_indices.pop_front();
|
||||||
bank_pool[new_index].Reset();
|
bank_pool[new_index].Reset();
|
||||||
|
bank_indices.push_back(new_index);
|
||||||
return new_index;
|
return new_index;
|
||||||
}
|
}
|
||||||
size_t new_index = bank_pool.size();
|
size_t new_index = bank_pool.size();
|
||||||
|
|
|
@ -89,9 +89,6 @@ public:
|
||||||
void RequestScreenshot(void* data, std::function<void(bool)> callback,
|
void RequestScreenshot(void* data, std::function<void(bool)> callback,
|
||||||
const Layout::FramebufferLayout& layout);
|
const Layout::FramebufferLayout& layout);
|
||||||
|
|
||||||
/// This is called to notify the rendering backend of a surface change
|
|
||||||
virtual void NotifySurfaceChanged() {}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle.
|
Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle.
|
||||||
std::unique_ptr<Core::Frontend::GraphicsContext> context;
|
std::unique_ptr<Core::Frontend::GraphicsContext> context;
|
||||||
|
|
|
@ -116,6 +116,7 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> FORMAT_TAB
|
||||||
{GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV}, // E5B9G9R9_FLOAT
|
{GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV}, // E5B9G9R9_FLOAT
|
||||||
{GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}, // D32_FLOAT
|
{GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}, // D32_FLOAT
|
||||||
{GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16_UNORM
|
{GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16_UNORM
|
||||||
|
{GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8}, // X8_D24_UNORM
|
||||||
{GL_STENCIL_INDEX8, GL_STENCIL, GL_UNSIGNED_BYTE}, // S8_UINT
|
{GL_STENCIL_INDEX8, GL_STENCIL, GL_UNSIGNED_BYTE}, // S8_UINT
|
||||||
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24_UNORM_S8_UINT
|
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24_UNORM_S8_UINT
|
||||||
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // S8_UINT_D24_UNORM
|
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // S8_UINT_D24_UNORM
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "video_core/host_shaders/blit_color_float_frag_spv.h"
|
#include "video_core/host_shaders/blit_color_float_frag_spv.h"
|
||||||
#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
|
#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
|
||||||
#include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h"
|
#include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h"
|
||||||
|
#include "video_core/host_shaders/convert_d32f_to_abgr8_frag_spv.h"
|
||||||
#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
|
#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
|
||||||
#include "video_core/host_shaders/convert_float_to_depth_frag_spv.h"
|
#include "video_core/host_shaders/convert_float_to_depth_frag_spv.h"
|
||||||
#include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h"
|
#include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h"
|
||||||
|
@ -433,6 +434,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
|
||||||
convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
|
convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
|
||||||
convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
|
convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
|
||||||
convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
|
convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
|
||||||
|
convert_d32f_to_abgr8_frag(BuildShader(device, CONVERT_D32F_TO_ABGR8_FRAG_SPV)),
|
||||||
convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
|
convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
|
||||||
convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)),
|
convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)),
|
||||||
linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)),
|
linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)),
|
||||||
|
@ -557,6 +559,13 @@ void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
|
||||||
Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
|
Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BlitImageHelper::ConvertD32FToABGR8(const Framebuffer* dst_framebuffer,
|
||||||
|
ImageView& src_image_view) {
|
||||||
|
ConvertPipelineColorTargetEx(convert_d32f_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
|
||||||
|
convert_d32f_to_abgr8_frag);
|
||||||
|
ConvertDepthStencil(*convert_d32f_to_abgr8_pipeline, dst_framebuffer, src_image_view);
|
||||||
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
|
||||||
ImageView& src_image_view) {
|
ImageView& src_image_view) {
|
||||||
ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
|
ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
|
||||||
|
@ -609,6 +618,8 @@ void BlitImageHelper::ClearDepthStencil(const Framebuffer* dst_framebuffer, bool
|
||||||
const VkPipelineLayout layout = *clear_color_pipeline_layout;
|
const VkPipelineLayout layout = *clear_color_pipeline_layout;
|
||||||
scheduler.RequestRenderpass(dst_framebuffer);
|
scheduler.RequestRenderpass(dst_framebuffer);
|
||||||
scheduler.Record([pipeline, layout, clear_depth, dst_region](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([pipeline, layout, clear_depth, dst_region](vk::CommandBuffer cmdbuf) {
|
||||||
|
constexpr std::array blend_constants{0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
|
cmdbuf.SetBlendConstants(blend_constants.data());
|
||||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||||
BindBlitState(cmdbuf, dst_region);
|
BindBlitState(cmdbuf, dst_region);
|
||||||
cmdbuf.PushConstants(layout, VK_SHADER_STAGE_FRAGMENT_BIT, clear_depth);
|
cmdbuf.PushConstants(layout, VK_SHADER_STAGE_FRAGMENT_BIT, clear_depth);
|
||||||
|
@ -865,7 +876,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.depthTestEnable = VK_FALSE,
|
.depthTestEnable = key.depth_clear,
|
||||||
.depthWriteEnable = key.depth_clear,
|
.depthWriteEnable = key.depth_clear,
|
||||||
.depthCompareOp = VK_COMPARE_OP_ALWAYS,
|
.depthCompareOp = VK_COMPARE_OP_ALWAYS,
|
||||||
.depthBoundsTestEnable = VK_FALSE,
|
.depthBoundsTestEnable = VK_FALSE,
|
||||||
|
|
|
@ -67,6 +67,8 @@ public:
|
||||||
|
|
||||||
void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
|
void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
|
||||||
|
|
||||||
|
void ConvertD32FToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view);
|
||||||
|
|
||||||
void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view);
|
void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view);
|
||||||
|
|
||||||
void ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view);
|
void ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view);
|
||||||
|
@ -128,6 +130,7 @@ private:
|
||||||
vk::ShaderModule convert_depth_to_float_frag;
|
vk::ShaderModule convert_depth_to_float_frag;
|
||||||
vk::ShaderModule convert_float_to_depth_frag;
|
vk::ShaderModule convert_float_to_depth_frag;
|
||||||
vk::ShaderModule convert_abgr8_to_d24s8_frag;
|
vk::ShaderModule convert_abgr8_to_d24s8_frag;
|
||||||
|
vk::ShaderModule convert_d32f_to_abgr8_frag;
|
||||||
vk::ShaderModule convert_d24s8_to_abgr8_frag;
|
vk::ShaderModule convert_d24s8_to_abgr8_frag;
|
||||||
vk::ShaderModule convert_s8d24_to_abgr8_frag;
|
vk::ShaderModule convert_s8d24_to_abgr8_frag;
|
||||||
vk::Sampler linear_sampler;
|
vk::Sampler linear_sampler;
|
||||||
|
@ -146,6 +149,7 @@ private:
|
||||||
vk::Pipeline convert_d16_to_r16_pipeline;
|
vk::Pipeline convert_d16_to_r16_pipeline;
|
||||||
vk::Pipeline convert_r16_to_d16_pipeline;
|
vk::Pipeline convert_r16_to_d16_pipeline;
|
||||||
vk::Pipeline convert_abgr8_to_d24s8_pipeline;
|
vk::Pipeline convert_abgr8_to_d24s8_pipeline;
|
||||||
|
vk::Pipeline convert_d32f_to_abgr8_pipeline;
|
||||||
vk::Pipeline convert_d24s8_to_abgr8_pipeline;
|
vk::Pipeline convert_d24s8_to_abgr8_pipeline;
|
||||||
vk::Pipeline convert_s8d24_to_abgr8_pipeline;
|
vk::Pipeline convert_s8d24_to_abgr8_pipeline;
|
||||||
};
|
};
|
||||||
|
|
|
@ -216,6 +216,7 @@ struct FormatTuple {
|
||||||
// Depth formats
|
// Depth formats
|
||||||
{VK_FORMAT_D32_SFLOAT, Attachable}, // D32_FLOAT
|
{VK_FORMAT_D32_SFLOAT, Attachable}, // D32_FLOAT
|
||||||
{VK_FORMAT_D16_UNORM, Attachable}, // D16_UNORM
|
{VK_FORMAT_D16_UNORM, Attachable}, // D16_UNORM
|
||||||
|
{VK_FORMAT_X8_D24_UNORM_PACK32, Attachable}, // X8_D24_UNORM
|
||||||
|
|
||||||
// Stencil formats
|
// Stencil formats
|
||||||
{VK_FORMAT_S8_UINT, Attachable}, // S8_UINT
|
{VK_FORMAT_S8_UINT, Attachable}, // S8_UINT
|
||||||
|
|
|
@ -56,10 +56,6 @@ public:
|
||||||
return device.GetDriverName();
|
return device.GetDriverName();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifySurfaceChanged() override {
|
|
||||||
present_manager.NotifySurfaceChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Report() const;
|
void Report() const;
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,7 @@ std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) {
|
||||||
VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) {
|
VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) {
|
||||||
switch (framebuffer.pixel_format) {
|
switch (framebuffer.pixel_format) {
|
||||||
case Service::android::PixelFormat::Rgba8888:
|
case Service::android::PixelFormat::Rgba8888:
|
||||||
|
case Service::android::PixelFormat::Rgbx8888:
|
||||||
return VK_FORMAT_A8B8G8R8_UNORM_PACK32;
|
return VK_FORMAT_A8B8G8R8_UNORM_PACK32;
|
||||||
case Service::android::PixelFormat::Rgb565:
|
case Service::android::PixelFormat::Rgb565:
|
||||||
return VK_FORMAT_R5G6B5_UNORM_PACK16;
|
return VK_FORMAT_R5G6B5_UNORM_PACK16;
|
||||||
|
|
|
@ -103,8 +103,7 @@ PresentManager::PresentManager(const vk::Instance& instance_,
|
||||||
surface{surface_}, blit_supported{CanBlitToSwapchain(device.GetPhysical(),
|
surface{surface_}, blit_supported{CanBlitToSwapchain(device.GetPhysical(),
|
||||||
swapchain.GetImageViewFormat())},
|
swapchain.GetImageViewFormat())},
|
||||||
use_present_thread{Settings::values.async_presentation.GetValue()},
|
use_present_thread{Settings::values.async_presentation.GetValue()},
|
||||||
image_count{swapchain.GetImageCount()}, last_render_surface{
|
image_count{swapchain.GetImageCount()} {
|
||||||
render_window_.GetWindowInfo().render_surface} {
|
|
||||||
|
|
||||||
auto& dld = device.GetLogical();
|
auto& dld = device.GetLogical();
|
||||||
cmdpool = dld.CreateCommandPool({
|
cmdpool = dld.CreateCommandPool({
|
||||||
|
@ -289,44 +288,36 @@ void PresentManager::PresentThread(std::stop_token token) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PresentManager::NotifySurfaceChanged() {
|
void PresentManager::RecreateSwapchain(Frame* frame) {
|
||||||
#ifdef ANDROID
|
swapchain.Create(*surface, frame->width, frame->height, frame->is_srgb);
|
||||||
std::scoped_lock lock{recreate_surface_mutex};
|
image_count = swapchain.GetImageCount();
|
||||||
recreate_surface_cv.notify_one();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PresentManager::CopyToSwapchain(Frame* frame) {
|
void PresentManager::CopyToSwapchain(Frame* frame) {
|
||||||
MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain);
|
bool requires_recreation = false;
|
||||||
|
|
||||||
const auto recreate_swapchain = [&] {
|
while (true) {
|
||||||
swapchain.Create(*surface, frame->width, frame->height, frame->is_srgb);
|
try {
|
||||||
image_count = swapchain.GetImageCount();
|
// Recreate surface and swapchain if needed.
|
||||||
};
|
if (requires_recreation) {
|
||||||
|
|
||||||
#ifdef ANDROID
|
|
||||||
std::unique_lock lock{recreate_surface_mutex};
|
|
||||||
|
|
||||||
const auto needs_recreation = [&] {
|
|
||||||
if (last_render_surface != render_window.GetWindowInfo().render_surface) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (swapchain.NeedsRecreation(frame->is_srgb)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
recreate_surface_cv.wait_for(lock, std::chrono::milliseconds(400),
|
|
||||||
[&]() { return !needs_recreation(); });
|
|
||||||
|
|
||||||
// If the frontend recreated the surface, recreate the renderer surface and swapchain.
|
|
||||||
if (last_render_surface != render_window.GetWindowInfo().render_surface) {
|
|
||||||
last_render_surface = render_window.GetWindowInfo().render_surface;
|
|
||||||
surface = CreateSurface(instance, render_window.GetWindowInfo());
|
surface = CreateSurface(instance, render_window.GetWindowInfo());
|
||||||
recreate_swapchain();
|
RecreateSwapchain(frame);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
// Draw to swapchain.
|
||||||
|
return CopyToSwapchainImpl(frame);
|
||||||
|
} catch (const vk::Exception& except) {
|
||||||
|
if (except.GetResult() != VK_ERROR_SURFACE_LOST_KHR) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
requires_recreation = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PresentManager::CopyToSwapchainImpl(Frame* frame) {
|
||||||
|
MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain);
|
||||||
|
|
||||||
// If the size or colorspace of the incoming frames has changed, recreate the swapchain
|
// If the size or colorspace of the incoming frames has changed, recreate the swapchain
|
||||||
// to account for that.
|
// to account for that.
|
||||||
|
@ -334,11 +325,11 @@ void PresentManager::CopyToSwapchain(Frame* frame) {
|
||||||
const bool size_changed =
|
const bool size_changed =
|
||||||
swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height;
|
swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height;
|
||||||
if (srgb_changed || size_changed) {
|
if (srgb_changed || size_changed) {
|
||||||
recreate_swapchain();
|
RecreateSwapchain(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (swapchain.AcquireNextImage()) {
|
while (swapchain.AcquireNextImage()) {
|
||||||
recreate_swapchain();
|
RecreateSwapchain(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
const vk::CommandBuffer cmdbuf{frame->cmdbuf};
|
const vk::CommandBuffer cmdbuf{frame->cmdbuf};
|
||||||
|
|
|
@ -54,14 +54,15 @@ public:
|
||||||
/// Waits for the present thread to finish presenting all queued frames.
|
/// Waits for the present thread to finish presenting all queued frames.
|
||||||
void WaitPresent();
|
void WaitPresent();
|
||||||
|
|
||||||
/// This is called to notify the rendering backend of a surface change
|
|
||||||
void NotifySurfaceChanged();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void PresentThread(std::stop_token token);
|
void PresentThread(std::stop_token token);
|
||||||
|
|
||||||
void CopyToSwapchain(Frame* frame);
|
void CopyToSwapchain(Frame* frame);
|
||||||
|
|
||||||
|
void CopyToSwapchainImpl(Frame* frame);
|
||||||
|
|
||||||
|
void RecreateSwapchain(Frame* frame);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const vk::Instance& instance;
|
const vk::Instance& instance;
|
||||||
Core::Frontend::EmuWindow& render_window;
|
Core::Frontend::EmuWindow& render_window;
|
||||||
|
@ -76,16 +77,13 @@ private:
|
||||||
std::queue<Frame*> free_queue;
|
std::queue<Frame*> free_queue;
|
||||||
std::condition_variable_any frame_cv;
|
std::condition_variable_any frame_cv;
|
||||||
std::condition_variable free_cv;
|
std::condition_variable free_cv;
|
||||||
std::condition_variable recreate_surface_cv;
|
|
||||||
std::mutex swapchain_mutex;
|
std::mutex swapchain_mutex;
|
||||||
std::mutex recreate_surface_mutex;
|
|
||||||
std::mutex queue_mutex;
|
std::mutex queue_mutex;
|
||||||
std::mutex free_mutex;
|
std::mutex free_mutex;
|
||||||
std::jthread present_thread;
|
std::jthread present_thread;
|
||||||
bool blit_supported;
|
bool blit_supported;
|
||||||
bool use_present_thread;
|
bool use_present_thread;
|
||||||
std::size_t image_count{};
|
std::size_t image_count{};
|
||||||
void* last_render_surface{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
|
@ -506,6 +506,7 @@ private:
|
||||||
SetAccumulationValue(query->value);
|
SetAccumulationValue(query->value);
|
||||||
Free(index);
|
Free(index);
|
||||||
});
|
});
|
||||||
|
rasterizer->SyncOperation(std::move(func));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool is_resolve>
|
template <bool is_resolve>
|
||||||
|
|
|
@ -422,7 +422,8 @@ void RasterizerVulkan::Clear(u32 layer_count) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_stencil && regs.stencil_front_mask != 0xFF && regs.stencil_front_mask != 0) {
|
if (use_stencil && framebuffer->HasAspectStencilBit() && regs.stencil_front_mask != 0xFF &&
|
||||||
|
regs.stencil_front_mask != 0) {
|
||||||
Region2D dst_region = {
|
Region2D dst_region = {
|
||||||
Offset2D{.x = clear_rect.rect.offset.x, .y = clear_rect.rect.offset.y},
|
Offset2D{.x = clear_rect.rect.offset.x, .y = clear_rect.rect.offset.y},
|
||||||
Offset2D{.x = clear_rect.rect.offset.x + static_cast<s32>(clear_rect.rect.extent.width),
|
Offset2D{.x = clear_rect.rect.offset.x + static_cast<s32>(clear_rect.rect.extent.width),
|
||||||
|
|
|
@ -24,25 +24,38 @@ using namespace Common::Literals;
|
||||||
|
|
||||||
// Maximum potential alignment of a Vulkan buffer
|
// Maximum potential alignment of a Vulkan buffer
|
||||||
constexpr VkDeviceSize MAX_ALIGNMENT = 256;
|
constexpr VkDeviceSize MAX_ALIGNMENT = 256;
|
||||||
// Maximum size to put elements in the stream buffer
|
|
||||||
constexpr VkDeviceSize MAX_STREAM_BUFFER_REQUEST_SIZE = 8_MiB;
|
|
||||||
// Stream buffer size in bytes
|
// Stream buffer size in bytes
|
||||||
constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB;
|
constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 128_MiB;
|
||||||
constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS;
|
|
||||||
|
|
||||||
size_t Region(size_t iterator) noexcept {
|
size_t GetStreamBufferSize(const Device& device) {
|
||||||
return iterator / REGION_SIZE;
|
VkDeviceSize size{0};
|
||||||
|
if (device.HasDebuggingToolAttached()) {
|
||||||
|
ForEachDeviceLocalHostVisibleHeap(device, [&size](size_t index, VkMemoryHeap& heap) {
|
||||||
|
size = std::max(size, heap.size);
|
||||||
|
});
|
||||||
|
// If rebar is not supported, cut the max heap size to 40%. This will allow 2 captures to be
|
||||||
|
// loaded at the same time in RenderDoc. If rebar is supported, this shouldn't be an issue
|
||||||
|
// as the heap will be much larger.
|
||||||
|
if (size <= 256_MiB) {
|
||||||
|
size = size * 40 / 100;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size = MAX_STREAM_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
return std::min(Common::AlignUp(size, MAX_ALIGNMENT), MAX_STREAM_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_,
|
StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_,
|
||||||
Scheduler& scheduler_)
|
Scheduler& scheduler_)
|
||||||
: device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} {
|
: device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_},
|
||||||
|
stream_buffer_size{GetStreamBufferSize(device)}, region_size{stream_buffer_size /
|
||||||
|
StagingBufferPool::NUM_SYNCS} {
|
||||||
VkBufferCreateInfo stream_ci = {
|
VkBufferCreateInfo stream_ci = {
|
||||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.size = STREAM_BUFFER_SIZE,
|
.size = stream_buffer_size,
|
||||||
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
|
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
|
||||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
|
||||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||||
|
@ -63,7 +76,7 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem
|
||||||
StagingBufferPool::~StagingBufferPool() = default;
|
StagingBufferPool::~StagingBufferPool() = default;
|
||||||
|
|
||||||
StagingBufferRef StagingBufferPool::Request(size_t size, MemoryUsage usage, bool deferred) {
|
StagingBufferRef StagingBufferPool::Request(size_t size, MemoryUsage usage, bool deferred) {
|
||||||
if (!deferred && usage == MemoryUsage::Upload && size <= MAX_STREAM_BUFFER_REQUEST_SIZE) {
|
if (!deferred && usage == MemoryUsage::Upload && size <= region_size) {
|
||||||
return GetStreamBuffer(size);
|
return GetStreamBuffer(size);
|
||||||
}
|
}
|
||||||
return GetStagingBuffer(size, usage, deferred);
|
return GetStagingBuffer(size, usage, deferred);
|
||||||
|
@ -101,7 +114,7 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
|
||||||
used_iterator = iterator;
|
used_iterator = iterator;
|
||||||
free_iterator = std::max(free_iterator, iterator + size);
|
free_iterator = std::max(free_iterator, iterator + size);
|
||||||
|
|
||||||
if (iterator + size >= STREAM_BUFFER_SIZE) {
|
if (iterator + size >= stream_buffer_size) {
|
||||||
std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + NUM_SYNCS,
|
std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + NUM_SYNCS,
|
||||||
current_tick);
|
current_tick);
|
||||||
used_iterator = 0;
|
used_iterator = 0;
|
||||||
|
|
|
@ -90,6 +90,9 @@ private:
|
||||||
void ReleaseCache(MemoryUsage usage);
|
void ReleaseCache(MemoryUsage usage);
|
||||||
|
|
||||||
void ReleaseLevel(StagingBuffersCache& cache, size_t log2);
|
void ReleaseLevel(StagingBuffersCache& cache, size_t log2);
|
||||||
|
size_t Region(size_t iter) const noexcept {
|
||||||
|
return iter / region_size;
|
||||||
|
}
|
||||||
|
|
||||||
const Device& device;
|
const Device& device;
|
||||||
MemoryAllocator& memory_allocator;
|
MemoryAllocator& memory_allocator;
|
||||||
|
@ -97,6 +100,8 @@ private:
|
||||||
|
|
||||||
vk::Buffer stream_buffer;
|
vk::Buffer stream_buffer;
|
||||||
std::span<u8> stream_pointer;
|
std::span<u8> stream_pointer;
|
||||||
|
VkDeviceSize stream_buffer_size;
|
||||||
|
VkDeviceSize region_size;
|
||||||
|
|
||||||
size_t iterator = 0;
|
size_t iterator = 0;
|
||||||
size_t used_iterator = 0;
|
size_t used_iterator = 0;
|
||||||
|
|
|
@ -238,6 +238,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
|
||||||
return any_r ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT;
|
return any_r ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
case PixelFormat::D16_UNORM:
|
case PixelFormat::D16_UNORM:
|
||||||
case PixelFormat::D32_FLOAT:
|
case PixelFormat::D32_FLOAT:
|
||||||
|
case PixelFormat::X8_D24_UNORM:
|
||||||
return VK_IMAGE_ASPECT_DEPTH_BIT;
|
return VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
case PixelFormat::S8_UINT:
|
case PixelFormat::S8_UINT:
|
||||||
return VK_IMAGE_ASPECT_STENCIL_BIT;
|
return VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
@ -1200,6 +1201,9 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
|
||||||
if (src_view.format == PixelFormat::D24_UNORM_S8_UINT) {
|
if (src_view.format == PixelFormat::D24_UNORM_S8_UINT) {
|
||||||
return blit_image_helper.ConvertS8D24ToABGR8(dst, src_view);
|
return blit_image_helper.ConvertS8D24ToABGR8(dst, src_view);
|
||||||
}
|
}
|
||||||
|
if (src_view.format == PixelFormat::D32_FLOAT) {
|
||||||
|
return blit_image_helper.ConvertD32FToABGR8(dst, src_view);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PixelFormat::R32_FLOAT:
|
case PixelFormat::R32_FLOAT:
|
||||||
if (src_view.format == PixelFormat::D32_FLOAT) {
|
if (src_view.format == PixelFormat::D32_FLOAT) {
|
||||||
|
|
|
@ -85,6 +85,8 @@ PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
|
||||||
return PixelFormat::S8_UINT;
|
return PixelFormat::S8_UINT;
|
||||||
case Tegra::DepthFormat::Z32_FLOAT_X24S8_UINT:
|
case Tegra::DepthFormat::Z32_FLOAT_X24S8_UINT:
|
||||||
return PixelFormat::D32_FLOAT_S8_UINT;
|
return PixelFormat::D32_FLOAT_S8_UINT;
|
||||||
|
case Tegra::DepthFormat::X8Z24_UNORM:
|
||||||
|
return PixelFormat::X8_D24_UNORM;
|
||||||
default:
|
default:
|
||||||
UNIMPLEMENTED_MSG("Unimplemented format={}", format);
|
UNIMPLEMENTED_MSG("Unimplemented format={}", format);
|
||||||
return PixelFormat::S8_UINT_D24_UNORM;
|
return PixelFormat::S8_UINT_D24_UNORM;
|
||||||
|
@ -202,6 +204,7 @@ PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format)
|
||||||
PixelFormat PixelFormatFromGPUPixelFormat(Service::android::PixelFormat format) {
|
PixelFormat PixelFormatFromGPUPixelFormat(Service::android::PixelFormat format) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case Service::android::PixelFormat::Rgba8888:
|
case Service::android::PixelFormat::Rgba8888:
|
||||||
|
case Service::android::PixelFormat::Rgbx8888:
|
||||||
return PixelFormat::A8B8G8R8_UNORM;
|
return PixelFormat::A8B8G8R8_UNORM;
|
||||||
case Service::android::PixelFormat::Rgb565:
|
case Service::android::PixelFormat::Rgb565:
|
||||||
return PixelFormat::R5G6B5_UNORM;
|
return PixelFormat::R5G6B5_UNORM;
|
||||||
|
|
|
@ -115,6 +115,7 @@ enum class PixelFormat {
|
||||||
// Depth formats
|
// Depth formats
|
||||||
D32_FLOAT = MaxColorFormat,
|
D32_FLOAT = MaxColorFormat,
|
||||||
D16_UNORM,
|
D16_UNORM,
|
||||||
|
X8_D24_UNORM,
|
||||||
|
|
||||||
MaxDepthFormat,
|
MaxDepthFormat,
|
||||||
|
|
||||||
|
@ -251,6 +252,7 @@ constexpr std::array<u8, MaxPixelFormat> BLOCK_WIDTH_TABLE = {{
|
||||||
1, // E5B9G9R9_FLOAT
|
1, // E5B9G9R9_FLOAT
|
||||||
1, // D32_FLOAT
|
1, // D32_FLOAT
|
||||||
1, // D16_UNORM
|
1, // D16_UNORM
|
||||||
|
1, // X8_D24_UNORM
|
||||||
1, // S8_UINT
|
1, // S8_UINT
|
||||||
1, // D24_UNORM_S8_UINT
|
1, // D24_UNORM_S8_UINT
|
||||||
1, // S8_UINT_D24_UNORM
|
1, // S8_UINT_D24_UNORM
|
||||||
|
@ -360,6 +362,7 @@ constexpr std::array<u8, MaxPixelFormat> BLOCK_HEIGHT_TABLE = {{
|
||||||
1, // E5B9G9R9_FLOAT
|
1, // E5B9G9R9_FLOAT
|
||||||
1, // D32_FLOAT
|
1, // D32_FLOAT
|
||||||
1, // D16_UNORM
|
1, // D16_UNORM
|
||||||
|
1, // X8_D24_UNORM
|
||||||
1, // S8_UINT
|
1, // S8_UINT
|
||||||
1, // D24_UNORM_S8_UINT
|
1, // D24_UNORM_S8_UINT
|
||||||
1, // S8_UINT_D24_UNORM
|
1, // S8_UINT_D24_UNORM
|
||||||
|
@ -469,6 +472,7 @@ constexpr std::array<u8, MaxPixelFormat> BITS_PER_BLOCK_TABLE = {{
|
||||||
32, // E5B9G9R9_FLOAT
|
32, // E5B9G9R9_FLOAT
|
||||||
32, // D32_FLOAT
|
32, // D32_FLOAT
|
||||||
16, // D16_UNORM
|
16, // D16_UNORM
|
||||||
|
32, // X8_D24_UNORM
|
||||||
8, // S8_UINT
|
8, // S8_UINT
|
||||||
32, // D24_UNORM_S8_UINT
|
32, // D24_UNORM_S8_UINT
|
||||||
32, // S8_UINT_D24_UNORM
|
32, // S8_UINT_D24_UNORM
|
||||||
|
|
|
@ -138,10 +138,16 @@ PixelFormat PixelFormatFromTextureInfo(TextureFormat format, ComponentType red,
|
||||||
return PixelFormat::E5B9G9R9_FLOAT;
|
return PixelFormat::E5B9G9R9_FLOAT;
|
||||||
case Hash(TextureFormat::Z32, FLOAT):
|
case Hash(TextureFormat::Z32, FLOAT):
|
||||||
return PixelFormat::D32_FLOAT;
|
return PixelFormat::D32_FLOAT;
|
||||||
|
case Hash(TextureFormat::Z32, FLOAT, UINT, UINT, UINT, LINEAR):
|
||||||
|
return PixelFormat::D32_FLOAT;
|
||||||
case Hash(TextureFormat::Z16, UNORM):
|
case Hash(TextureFormat::Z16, UNORM):
|
||||||
return PixelFormat::D16_UNORM;
|
return PixelFormat::D16_UNORM;
|
||||||
case Hash(TextureFormat::Z16, UNORM, UINT, UINT, UINT, LINEAR):
|
case Hash(TextureFormat::Z16, UNORM, UINT, UINT, UINT, LINEAR):
|
||||||
return PixelFormat::D16_UNORM;
|
return PixelFormat::D16_UNORM;
|
||||||
|
case Hash(TextureFormat::X8Z24, UNORM):
|
||||||
|
return PixelFormat::X8_D24_UNORM;
|
||||||
|
case Hash(TextureFormat::X8Z24, UNORM, UINT, UINT, UINT, LINEAR):
|
||||||
|
return PixelFormat::X8_D24_UNORM;
|
||||||
case Hash(TextureFormat::Z24S8, UINT, UNORM, UNORM, UNORM, LINEAR):
|
case Hash(TextureFormat::Z24S8, UINT, UNORM, UNORM, UNORM, LINEAR):
|
||||||
return PixelFormat::S8_UINT_D24_UNORM;
|
return PixelFormat::S8_UINT_D24_UNORM;
|
||||||
case Hash(TextureFormat::Z24S8, UINT, UNORM, UINT, UINT, LINEAR):
|
case Hash(TextureFormat::Z24S8, UINT, UNORM, UINT, UINT, LINEAR):
|
||||||
|
|
|
@ -211,6 +211,8 @@ struct fmt::formatter<VideoCore::Surface::PixelFormat> : fmt::formatter<fmt::str
|
||||||
return "D32_FLOAT";
|
return "D32_FLOAT";
|
||||||
case PixelFormat::D16_UNORM:
|
case PixelFormat::D16_UNORM:
|
||||||
return "D16_UNORM";
|
return "D16_UNORM";
|
||||||
|
case PixelFormat::X8_D24_UNORM:
|
||||||
|
return "X8_D24_UNORM";
|
||||||
case PixelFormat::S8_UINT:
|
case PixelFormat::S8_UINT:
|
||||||
return "S8_UINT";
|
return "S8_UINT";
|
||||||
case PixelFormat::D24_UNORM_S8_UINT:
|
case PixelFormat::D24_UNORM_S8_UINT:
|
||||||
|
|
|
@ -41,7 +41,7 @@ enum class ImageFlagBits : u32 {
|
||||||
IsRescalable = 1 << 15,
|
IsRescalable = 1 << 15,
|
||||||
|
|
||||||
AsynchronousDecode = 1 << 16,
|
AsynchronousDecode = 1 << 16,
|
||||||
IsDecoding = 1 << 17, ///< Is currently being decoded asynchornously.
|
IsDecoding = 1 << 17, ///< Is currently being decoded asynchronously.
|
||||||
};
|
};
|
||||||
DECLARE_ENUM_FLAG_OPERATORS(ImageFlagBits)
|
DECLARE_ENUM_FLAG_OPERATORS(ImageFlagBits)
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,7 @@ bool ImageViewBase::SupportsAnisotropy() const noexcept {
|
||||||
// Depth formats
|
// Depth formats
|
||||||
case PixelFormat::D32_FLOAT:
|
case PixelFormat::D32_FLOAT:
|
||||||
case PixelFormat::D16_UNORM:
|
case PixelFormat::D16_UNORM:
|
||||||
|
case PixelFormat::X8_D24_UNORM:
|
||||||
// Stencil formats
|
// Stencil formats
|
||||||
case PixelFormat::S8_UINT:
|
case PixelFormat::S8_UINT:
|
||||||
// DepthStencil formats
|
// DepthStencil formats
|
||||||
|
|
|
@ -1195,7 +1195,7 @@ std::optional<SubresourceBase> FindSubresource(const ImageInfo& candidate, const
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Format comaptibility is not relaxed, ensure we are creating a view on a compatible format
|
// Format compatibility is not relaxed, ensure we are creating a view on a compatible format
|
||||||
if (!IsViewCompatible(existing.format, candidate.format, broken_views, native_bgr)) {
|
if (!IsViewCompatible(existing.format, candidate.format, broken_views, native_bgr)) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,9 +84,12 @@ constexpr std::array VK_FORMAT_A4B4G4R4_UNORM_PACK16{
|
||||||
} // namespace Alternatives
|
} // namespace Alternatives
|
||||||
|
|
||||||
enum class NvidiaArchitecture {
|
enum class NvidiaArchitecture {
|
||||||
AmpereOrNewer,
|
KeplerOrOlder,
|
||||||
|
Maxwell,
|
||||||
|
Pascal,
|
||||||
|
Volta,
|
||||||
Turing,
|
Turing,
|
||||||
VoltaOrOlder,
|
AmpereOrNewer,
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -200,6 +203,7 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::Physica
|
||||||
VK_FORMAT_BC7_UNORM_BLOCK,
|
VK_FORMAT_BC7_UNORM_BLOCK,
|
||||||
VK_FORMAT_D16_UNORM,
|
VK_FORMAT_D16_UNORM,
|
||||||
VK_FORMAT_D16_UNORM_S8_UINT,
|
VK_FORMAT_D16_UNORM_S8_UINT,
|
||||||
|
VK_FORMAT_X8_D24_UNORM_PACK32,
|
||||||
VK_FORMAT_D24_UNORM_S8_UINT,
|
VK_FORMAT_D24_UNORM_S8_UINT,
|
||||||
VK_FORMAT_D32_SFLOAT,
|
VK_FORMAT_D32_SFLOAT,
|
||||||
VK_FORMAT_D32_SFLOAT_S8_UINT,
|
VK_FORMAT_D32_SFLOAT_S8_UINT,
|
||||||
|
@ -321,13 +325,38 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
|
||||||
physical.GetProperties2(physical_properties);
|
physical.GetProperties2(physical_properties);
|
||||||
if (shading_rate_props.primitiveFragmentShadingRateWithMultipleViewports) {
|
if (shading_rate_props.primitiveFragmentShadingRateWithMultipleViewports) {
|
||||||
// Only Ampere and newer support this feature
|
// Only Ampere and newer support this feature
|
||||||
|
// TODO: Find a way to differentiate Ampere and Ada
|
||||||
return NvidiaArchitecture::AmpereOrNewer;
|
return NvidiaArchitecture::AmpereOrNewer;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (exts.contains(VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME)) {
|
|
||||||
return NvidiaArchitecture::Turing;
|
return NvidiaArchitecture::Turing;
|
||||||
}
|
}
|
||||||
return NvidiaArchitecture::VoltaOrOlder;
|
|
||||||
|
if (exts.contains(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME)) {
|
||||||
|
VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT advanced_blending_props{};
|
||||||
|
advanced_blending_props.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT;
|
||||||
|
VkPhysicalDeviceProperties2 physical_properties{};
|
||||||
|
physical_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||||
|
physical_properties.pNext = &advanced_blending_props;
|
||||||
|
physical.GetProperties2(physical_properties);
|
||||||
|
if (advanced_blending_props.advancedBlendMaxColorAttachments == 1) {
|
||||||
|
return NvidiaArchitecture::Maxwell;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exts.contains(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME)) {
|
||||||
|
VkPhysicalDeviceConservativeRasterizationPropertiesEXT conservative_raster_props{};
|
||||||
|
conservative_raster_props.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT;
|
||||||
|
physical_properties.pNext = &conservative_raster_props;
|
||||||
|
physical.GetProperties2(physical_properties);
|
||||||
|
if (conservative_raster_props.degenerateLinesRasterized) {
|
||||||
|
return NvidiaArchitecture::Volta;
|
||||||
|
}
|
||||||
|
return NvidiaArchitecture::Pascal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NvidiaArchitecture::KeplerOrOlder;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const char*> ExtensionListForVulkan(
|
std::vector<const char*> ExtensionListForVulkan(
|
||||||
|
@ -504,19 +533,14 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||||
if (is_nvidia) {
|
if (is_nvidia) {
|
||||||
const u32 nv_major_version = (properties.properties.driverVersion >> 22) & 0x3ff;
|
const u32 nv_major_version = (properties.properties.driverVersion >> 22) & 0x3ff;
|
||||||
const auto arch = GetNvidiaArchitecture(physical, supported_extensions);
|
const auto arch = GetNvidiaArchitecture(physical, supported_extensions);
|
||||||
switch (arch) {
|
if (arch >= NvidiaArchitecture::AmpereOrNewer) {
|
||||||
case NvidiaArchitecture::AmpereOrNewer:
|
|
||||||
LOG_WARNING(Render_Vulkan, "Ampere and newer have broken float16 math");
|
LOG_WARNING(Render_Vulkan, "Ampere and newer have broken float16 math");
|
||||||
features.shader_float16_int8.shaderFloat16 = false;
|
features.shader_float16_int8.shaderFloat16 = false;
|
||||||
break;
|
} else if (arch <= NvidiaArchitecture::Volta) {
|
||||||
case NvidiaArchitecture::Turing:
|
|
||||||
break;
|
|
||||||
case NvidiaArchitecture::VoltaOrOlder:
|
|
||||||
if (nv_major_version < 527) {
|
if (nv_major_version < 527) {
|
||||||
LOG_WARNING(Render_Vulkan, "Volta and older have broken VK_KHR_push_descriptor");
|
LOG_WARNING(Render_Vulkan, "Volta and older have broken VK_KHR_push_descriptor");
|
||||||
RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (nv_major_version >= 510) {
|
if (nv_major_version >= 510) {
|
||||||
LOG_WARNING(Render_Vulkan, "NVIDIA Drivers >= 510 do not support MSAA image blits");
|
LOG_WARNING(Render_Vulkan, "NVIDIA Drivers >= 510 do not support MSAA image blits");
|
||||||
|
@ -661,7 +685,15 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||||
"ANV drivers 22.3.0 to 23.1.0 have broken VK_KHR_push_descriptor");
|
"ANV drivers 22.3.0 to 23.1.0 have broken VK_KHR_push_descriptor");
|
||||||
RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
||||||
}
|
}
|
||||||
|
} else if (extensions.push_descriptor && is_nvidia) {
|
||||||
|
const auto arch = GetNvidiaArchitecture(physical, supported_extensions);
|
||||||
|
if (arch <= NvidiaArchitecture::Pascal) {
|
||||||
|
LOG_WARNING(Render_Vulkan,
|
||||||
|
"Pascal and older architectures have broken VK_KHR_push_descriptor");
|
||||||
|
RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (is_mvk) {
|
if (is_mvk) {
|
||||||
LOG_WARNING(Render_Vulkan,
|
LOG_WARNING(Render_Vulkan,
|
||||||
"MVK driver breaks when using more than 16 vertex attributes/bindings");
|
"MVK driver breaks when using more than 16 vertex attributes/bindings");
|
||||||
|
|
|
@ -314,7 +314,7 @@ public:
|
||||||
return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
|
return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the device suppors float64 natively.
|
/// Returns true if the device supports float64 natively.
|
||||||
bool IsFloat64Supported() const {
|
bool IsFloat64Supported() const {
|
||||||
return features.features.shaderFloat64;
|
return features.features.shaderFloat64;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/literals.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/polyfill_ranges.h"
|
#include "common/polyfill_ranges.h"
|
||||||
#include "video_core/vulkan_common/vma.h"
|
#include "video_core/vulkan_common/vma.h"
|
||||||
|
@ -69,8 +70,7 @@ struct Range {
|
||||||
case MemoryUsage::Download:
|
case MemoryUsage::Download:
|
||||||
return VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
|
return VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
|
||||||
case MemoryUsage::DeviceLocal:
|
case MemoryUsage::DeviceLocal:
|
||||||
return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
|
return {};
|
||||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT;
|
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,20 @@ MemoryAllocator::MemoryAllocator(const Device& device_)
|
||||||
: device{device_}, allocator{device.GetAllocator()},
|
: device{device_}, allocator{device.GetAllocator()},
|
||||||
properties{device_.GetPhysical().GetMemoryProperties().memoryProperties},
|
properties{device_.GetPhysical().GetMemoryProperties().memoryProperties},
|
||||||
buffer_image_granularity{
|
buffer_image_granularity{
|
||||||
device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {}
|
device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {
|
||||||
|
// GPUs not supporting rebar may only have a region with less than 256MB host visible/device
|
||||||
|
// local memory. In that case, opening 2 RenderDoc captures side-by-side is not possible due to
|
||||||
|
// the heap running out of memory. With RenderDoc attached and only a small host/device region,
|
||||||
|
// only allow the stream buffer in this memory heap.
|
||||||
|
if (device.HasDebuggingToolAttached()) {
|
||||||
|
using namespace Common::Literals;
|
||||||
|
ForEachDeviceLocalHostVisibleHeap(device, [this](size_t index, VkMemoryHeap& heap) {
|
||||||
|
if (heap.size <= 256_MiB) {
|
||||||
|
valid_memory_types &= ~(1u << index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MemoryAllocator::~MemoryAllocator() = default;
|
MemoryAllocator::~MemoryAllocator() = default;
|
||||||
|
|
||||||
|
@ -244,7 +257,7 @@ vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsa
|
||||||
.usage = MemoryUsageVma(usage),
|
.usage = MemoryUsageVma(usage),
|
||||||
.requiredFlags = 0,
|
.requiredFlags = 0,
|
||||||
.preferredFlags = MemoryUsagePreferedVmaFlags(usage),
|
.preferredFlags = MemoryUsagePreferedVmaFlags(usage),
|
||||||
.memoryTypeBits = 0,
|
.memoryTypeBits = usage == MemoryUsage::Stream ? 0u : valid_memory_types,
|
||||||
.pool = VK_NULL_HANDLE,
|
.pool = VK_NULL_HANDLE,
|
||||||
.pUserData = nullptr,
|
.pUserData = nullptr,
|
||||||
.priority = 0.f,
|
.priority = 0.f,
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "video_core/vulkan_common/vulkan_device.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
VK_DEFINE_HANDLE(VmaAllocator)
|
VK_DEFINE_HANDLE(VmaAllocator)
|
||||||
|
@ -26,6 +27,18 @@ enum class MemoryUsage {
|
||||||
Stream, ///< Requests device local host visible buffer, falling back host memory.
|
Stream, ///< Requests device local host visible buffer, falling back host memory.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void ForEachDeviceLocalHostVisibleHeap(const Device& device, F&& f) {
|
||||||
|
auto memory_props = device.GetPhysical().GetMemoryProperties().memoryProperties;
|
||||||
|
for (size_t i = 0; i < memory_props.memoryTypeCount; i++) {
|
||||||
|
auto& memory_type = memory_props.memoryTypes[i];
|
||||||
|
if ((memory_type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) &&
|
||||||
|
(memory_type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) {
|
||||||
|
f(memory_type.heapIndex, memory_props.memoryHeaps[memory_type.heapIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Ownership handle of a memory commitment.
|
/// Ownership handle of a memory commitment.
|
||||||
/// Points to a subregion of a memory allocation.
|
/// Points to a subregion of a memory allocation.
|
||||||
class MemoryCommit {
|
class MemoryCommit {
|
||||||
|
@ -124,6 +137,7 @@ private:
|
||||||
std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations.
|
std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations.
|
||||||
VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers
|
VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers
|
||||||
// and optimal images
|
// and optimal images
|
||||||
|
u32 valid_memory_types{~0u};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
|
@ -117,6 +117,9 @@ public:
|
||||||
virtual ~Exception() = default;
|
virtual ~Exception() = default;
|
||||||
|
|
||||||
const char* what() const noexcept override;
|
const char* what() const noexcept override;
|
||||||
|
VkResult GetResult() const noexcept {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VkResult result;
|
VkResult result;
|
||||||
|
|
|
@ -195,6 +195,8 @@ add_executable(yuzu
|
||||||
multiplayer/state.cpp
|
multiplayer/state.cpp
|
||||||
multiplayer/state.h
|
multiplayer/state.h
|
||||||
multiplayer/validation.h
|
multiplayer/validation.h
|
||||||
|
play_time_manager.cpp
|
||||||
|
play_time_manager.h
|
||||||
precompiled_headers.h
|
precompiled_headers.h
|
||||||
qt_common.cpp
|
qt_common.cpp
|
||||||
qt_common.h
|
qt_common.h
|
||||||
|
|
|
@ -42,6 +42,9 @@ void ConfigureAudio::Setup(const ConfigurationShared::Builder& builder) {
|
||||||
for (auto* setting : Settings::values.linkage.by_category[category]) {
|
for (auto* setting : Settings::values.linkage.by_category[category]) {
|
||||||
settings.push_back(setting);
|
settings.push_back(setting);
|
||||||
}
|
}
|
||||||
|
for (auto* setting : UISettings::values.linkage.by_category[category]) {
|
||||||
|
settings.push_back(setting);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
push(Settings::Category::Audio);
|
push(Settings::Category::Audio);
|
||||||
|
|
|
@ -123,6 +123,8 @@ ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent)
|
||||||
connect(ui->show_compat, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
|
connect(ui->show_compat, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
|
||||||
connect(ui->show_size, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
|
connect(ui->show_size, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
|
||||||
connect(ui->show_types, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
|
connect(ui->show_types, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
|
||||||
|
connect(ui->show_play_time, &QCheckBox::stateChanged, this,
|
||||||
|
&ConfigureUi::RequestGameListUpdate);
|
||||||
connect(ui->game_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
connect(ui->game_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
&ConfigureUi::RequestGameListUpdate);
|
&ConfigureUi::RequestGameListUpdate);
|
||||||
connect(ui->folder_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
connect(ui->folder_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||||
|
@ -167,6 +169,7 @@ void ConfigureUi::ApplyConfiguration() {
|
||||||
UISettings::values.show_compat = ui->show_compat->isChecked();
|
UISettings::values.show_compat = ui->show_compat->isChecked();
|
||||||
UISettings::values.show_size = ui->show_size->isChecked();
|
UISettings::values.show_size = ui->show_size->isChecked();
|
||||||
UISettings::values.show_types = ui->show_types->isChecked();
|
UISettings::values.show_types = ui->show_types->isChecked();
|
||||||
|
UISettings::values.show_play_time = ui->show_play_time->isChecked();
|
||||||
UISettings::values.game_icon_size = ui->game_icon_size_combobox->currentData().toUInt();
|
UISettings::values.game_icon_size = ui->game_icon_size_combobox->currentData().toUInt();
|
||||||
UISettings::values.folder_icon_size = ui->folder_icon_size_combobox->currentData().toUInt();
|
UISettings::values.folder_icon_size = ui->folder_icon_size_combobox->currentData().toUInt();
|
||||||
UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
|
UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
|
||||||
|
@ -179,6 +182,7 @@ void ConfigureUi::ApplyConfiguration() {
|
||||||
const u32 height = ScreenshotDimensionToInt(ui->screenshot_height->currentText());
|
const u32 height = ScreenshotDimensionToInt(ui->screenshot_height->currentText());
|
||||||
UISettings::values.screenshot_height.SetValue(height);
|
UISettings::values.screenshot_height.SetValue(height);
|
||||||
|
|
||||||
|
RequestGameListUpdate();
|
||||||
system.ApplySettings();
|
system.ApplySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,6 +198,7 @@ void ConfigureUi::SetConfiguration() {
|
||||||
ui->show_compat->setChecked(UISettings::values.show_compat.GetValue());
|
ui->show_compat->setChecked(UISettings::values.show_compat.GetValue());
|
||||||
ui->show_size->setChecked(UISettings::values.show_size.GetValue());
|
ui->show_size->setChecked(UISettings::values.show_size.GetValue());
|
||||||
ui->show_types->setChecked(UISettings::values.show_types.GetValue());
|
ui->show_types->setChecked(UISettings::values.show_types.GetValue());
|
||||||
|
ui->show_play_time->setChecked(UISettings::values.show_play_time.GetValue());
|
||||||
ui->game_icon_size_combobox->setCurrentIndex(
|
ui->game_icon_size_combobox->setCurrentIndex(
|
||||||
ui->game_icon_size_combobox->findData(UISettings::values.game_icon_size.GetValue()));
|
ui->game_icon_size_combobox->findData(UISettings::values.game_icon_size.GetValue()));
|
||||||
ui->folder_icon_size_combobox->setCurrentIndex(
|
ui->folder_icon_size_combobox->setCurrentIndex(
|
||||||
|
|
|
@ -104,6 +104,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="show_play_time">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show Play Time Column</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="game_icon_size_qhbox_layout_2">
|
<layout class="QHBoxLayout" name="game_icon_size_qhbox_layout_2">
|
||||||
<item>
|
<item>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue