Compare commits
4 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3862511a9a | ||
|
|
e9cf08c241 | ||
|
|
7737bdfd1a | ||
|
|
a1f19b61f8 |
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
@@ -81,7 +82,7 @@ public:
|
||||
*
|
||||
* @returns A reference to the setting
|
||||
*/
|
||||
[[nodiscard]] const Type& GetValue() const {
|
||||
[[nodiscard]] virtual const Type& GetValue() const {
|
||||
return global;
|
||||
}
|
||||
|
||||
@@ -90,7 +91,7 @@ public:
|
||||
*
|
||||
* @param value The desired value
|
||||
*/
|
||||
void SetValue(const Type& value) {
|
||||
virtual void SetValue(const Type& value) {
|
||||
Type temp{value};
|
||||
std::swap(global, temp);
|
||||
}
|
||||
@@ -120,7 +121,7 @@ public:
|
||||
*
|
||||
* @returns A reference to the setting
|
||||
*/
|
||||
const Type& operator=(const Type& value) {
|
||||
virtual const Type& operator=(const Type& value) {
|
||||
Type temp{value};
|
||||
std::swap(global, temp);
|
||||
return global;
|
||||
@@ -131,7 +132,7 @@ public:
|
||||
*
|
||||
* @returns A reference to the setting
|
||||
*/
|
||||
explicit operator const Type&() const {
|
||||
explicit virtual operator const Type&() const {
|
||||
return global;
|
||||
}
|
||||
|
||||
@@ -141,6 +142,51 @@ protected:
|
||||
const std::string label{}; ///< The setting's label
|
||||
};
|
||||
|
||||
/**
|
||||
* BasicRangedSetting class is intended for use with quantifiable settings that need a more
|
||||
* restrictive range than implicitly defined by its type. Implements a minimum and maximum that is
|
||||
* simply used to sanitize SetValue and the assignment overload.
|
||||
*/
|
||||
template <typename Type>
|
||||
class BasicRangedSetting : virtual public BasicSetting<Type> {
|
||||
public:
|
||||
/**
|
||||
* Sets a default value, minimum value, maximum value, and label.
|
||||
*
|
||||
* @param default_val Intial value of the setting, and default value of the setting
|
||||
* @param min_val Sets the minimum allowed value of the setting
|
||||
* @param max_val Sets the maximum allowed value of the setting
|
||||
* @param name Label for the setting
|
||||
*/
|
||||
explicit BasicRangedSetting(const Type& default_val, const Type& min_val, const Type& max_val,
|
||||
const std::string& name)
|
||||
: BasicSetting<Type>{default_val, name}, minimum{min_val}, maximum{max_val} {}
|
||||
~BasicRangedSetting() = default;
|
||||
|
||||
/**
|
||||
* Like BasicSetting's SetValue, except value is clamped to the range of the setting.
|
||||
*
|
||||
* @param value The desired value
|
||||
*/
|
||||
void SetValue(const Type& value) override {
|
||||
this->global = std::clamp(value, minimum, maximum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like BasicSetting's assignment overload, except value is clamped to the range of the setting.
|
||||
*
|
||||
* @param value The desired value
|
||||
* @returns A reference to the setting's value
|
||||
*/
|
||||
const Type& operator=(const Type& value) override {
|
||||
this->global = std::clamp(value, minimum, maximum);
|
||||
return this->global;
|
||||
}
|
||||
|
||||
const Type minimum; ///< Minimum allowed value of the setting
|
||||
const Type maximum; ///< Maximum allowed value of the setting
|
||||
};
|
||||
|
||||
/**
|
||||
* The Setting class is a slightly more complex version of the BasicSetting class. This adds a
|
||||
* custom setting to switch to when a guest application specifically requires it. The effect is that
|
||||
@@ -152,7 +198,7 @@ protected:
|
||||
* Like the BasicSetting, this requires setting a default value and label to use.
|
||||
*/
|
||||
template <typename Type>
|
||||
class Setting final : public BasicSetting<Type> {
|
||||
class Setting : virtual public BasicSetting<Type> {
|
||||
public:
|
||||
/**
|
||||
* Sets a default value, label, and setting value.
|
||||
@@ -191,7 +237,13 @@ public:
|
||||
*
|
||||
* @returns The required value of the setting
|
||||
*/
|
||||
[[nodiscard]] const Type& GetValue(bool need_global = false) const {
|
||||
[[nodiscard]] const Type& GetValue() const override {
|
||||
if (use_global) {
|
||||
return this->global;
|
||||
}
|
||||
return custom;
|
||||
}
|
||||
[[nodiscard]] const Type& GetValue(bool need_global) const {
|
||||
if (use_global || need_global) {
|
||||
return this->global;
|
||||
}
|
||||
@@ -203,7 +255,7 @@ public:
|
||||
*
|
||||
* @param value The new value
|
||||
*/
|
||||
void SetValue(const Type& value) {
|
||||
void SetValue(const Type& value) override {
|
||||
Type temp{value};
|
||||
if (use_global) {
|
||||
std::swap(this->global, temp);
|
||||
@@ -219,7 +271,7 @@ public:
|
||||
*
|
||||
* @returns A reference to the current setting value
|
||||
*/
|
||||
const Type& operator=(const Type& value) {
|
||||
const Type& operator=(const Type& value) override {
|
||||
Type temp{value};
|
||||
if (use_global) {
|
||||
std::swap(this->global, temp);
|
||||
@@ -234,18 +286,72 @@ public:
|
||||
*
|
||||
* @returns A reference to the current setting value
|
||||
*/
|
||||
explicit operator const Type&() const {
|
||||
explicit operator const Type&() const override {
|
||||
if (use_global) {
|
||||
return this->global;
|
||||
}
|
||||
return custom;
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
bool use_global{true}; ///< The setting's global state
|
||||
Type custom{}; ///< The custom value of the setting
|
||||
};
|
||||
|
||||
/**
|
||||
* RangedSetting is a Setting that implements a maximum and minimum value for its setting. Intended
|
||||
* for use with quantifiable settings.
|
||||
*/
|
||||
template <typename Type>
|
||||
class RangedSetting final : public BasicRangedSetting<Type>, public Setting<Type> {
|
||||
public:
|
||||
/**
|
||||
* Sets a default value, minimum value, maximum value, and label.
|
||||
*
|
||||
* @param default_val Intial value of the setting, and default value of the setting
|
||||
* @param min_val Sets the minimum allowed value of the setting
|
||||
* @param max_val Sets the maximum allowed value of the setting
|
||||
* @param name Label for the setting
|
||||
*/
|
||||
explicit RangedSetting(const Type& default_val, const Type& min_val, const Type& max_val,
|
||||
const std::string& name)
|
||||
: BasicSetting<Type>{default_val, name},
|
||||
BasicRangedSetting<Type>{default_val, min_val, max_val, name}, Setting<Type>{default_val,
|
||||
name} {}
|
||||
~RangedSetting() = default;
|
||||
|
||||
/**
|
||||
* Like BasicSetting's SetValue, except value is clamped to the range of the setting. Sets the
|
||||
* appropriate value depending on the global state.
|
||||
*
|
||||
* @param value The desired value
|
||||
*/
|
||||
void SetValue(const Type& value) override {
|
||||
const Type temp = std::clamp(value, this->minimum, this->maximum);
|
||||
if (this->use_global) {
|
||||
this->global = temp;
|
||||
}
|
||||
this->custom = temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like BasicSetting's assignment overload, except value is clamped to the range of the setting.
|
||||
* Uses the appropriate value depending on the global state.
|
||||
*
|
||||
* @param value The desired value
|
||||
* @returns A reference to the setting's value
|
||||
*/
|
||||
const Type& operator=(const Type& value) override {
|
||||
const Type temp = std::clamp(value, this->minimum, this->maximum);
|
||||
if (this->use_global) {
|
||||
this->global = temp;
|
||||
return this->global;
|
||||
}
|
||||
this->custom = temp;
|
||||
return this->custom;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The InputSetting class allows for getting a reference to either the global or custom members.
|
||||
* This is required as we cannot easily modify the values of user-defined types within containers
|
||||
@@ -289,13 +395,14 @@ struct Values {
|
||||
BasicSetting<std::string> sink_id{"auto", "output_engine"};
|
||||
BasicSetting<bool> audio_muted{false, "audio_muted"};
|
||||
Setting<bool> enable_audio_stretching{true, "enable_audio_stretching"};
|
||||
Setting<u8> volume{100, "volume"};
|
||||
RangedSetting<u8> volume{100, 0, 100, "volume"};
|
||||
|
||||
// Core
|
||||
Setting<bool> use_multi_core{true, "use_multi_core"};
|
||||
|
||||
// Cpu
|
||||
Setting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, "cpu_accuracy"};
|
||||
RangedSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
|
||||
CPUAccuracy::Unsafe, "cpu_accuracy"};
|
||||
// TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021
|
||||
BasicSetting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"};
|
||||
BasicSetting<bool> cpu_debug_mode{false, "cpu_debug_mode"};
|
||||
@@ -317,9 +424,9 @@ struct Values {
|
||||
Setting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"};
|
||||
|
||||
// Renderer
|
||||
Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL, "backend"};
|
||||
RangedSetting<RendererBackend> renderer_backend{
|
||||
RendererBackend::OpenGL, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"};
|
||||
BasicSetting<bool> renderer_debug{false, "debug"};
|
||||
BasicSetting<bool> renderer_shader_feedback{false, "shader_feedback"};
|
||||
BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"};
|
||||
BasicSetting<bool> disable_shader_loop_safety_checks{false,
|
||||
"disable_shader_loop_safety_checks"};
|
||||
@@ -328,26 +435,28 @@ struct Values {
|
||||
Setting<u16> resolution_factor{1, "resolution_factor"};
|
||||
// *nix platforms may have issues with the borderless windowed fullscreen mode.
|
||||
// Default to exclusive fullscreen on these platforms for now.
|
||||
Setting<FullscreenMode> fullscreen_mode{
|
||||
RangedSetting<FullscreenMode> fullscreen_mode{
|
||||
#ifdef _WIN32
|
||||
FullscreenMode::Borderless,
|
||||
#else
|
||||
FullscreenMode::Exclusive,
|
||||
#endif
|
||||
"fullscreen_mode"};
|
||||
Setting<int> aspect_ratio{0, "aspect_ratio"};
|
||||
Setting<int> max_anisotropy{0, "max_anisotropy"};
|
||||
FullscreenMode::Borderless, FullscreenMode::Exclusive, "fullscreen_mode"};
|
||||
RangedSetting<int> aspect_ratio{0, 0, 3, "aspect_ratio"};
|
||||
RangedSetting<int> max_anisotropy{0, 0, 4, "max_anisotropy"};
|
||||
Setting<bool> use_speed_limit{true, "use_speed_limit"};
|
||||
Setting<u16> speed_limit{100, "speed_limit"};
|
||||
RangedSetting<u16> speed_limit{100, 0, 9999, "speed_limit"};
|
||||
Setting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
|
||||
Setting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, "gpu_accuracy"};
|
||||
RangedSetting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal,
|
||||
GPUAccuracy::Extreme, "gpu_accuracy"};
|
||||
Setting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
|
||||
Setting<bool> use_nvdec_emulation{true, "use_nvdec_emulation"};
|
||||
Setting<bool> accelerate_astc{true, "accelerate_astc"};
|
||||
Setting<bool> use_vsync{true, "use_vsync"};
|
||||
BasicSetting<u16> fps_cap{1000, "fps_cap"};
|
||||
BasicRangedSetting<u16> fps_cap{1000, 1, 1000, "fps_cap"};
|
||||
BasicSetting<bool> disable_fps_limit{false, "disable_fps_limit"};
|
||||
Setting<ShaderBackend> shader_backend{ShaderBackend::GLASM, "shader_backend"};
|
||||
RangedSetting<ShaderBackend> shader_backend{ShaderBackend::GLASM, ShaderBackend::GLSL,
|
||||
ShaderBackend::SPIRV, "shader_backend"};
|
||||
Setting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
|
||||
Setting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
|
||||
Setting<bool> use_caches_gc{false, "use_caches_gc"};
|
||||
@@ -364,10 +473,10 @@ struct Values {
|
||||
std::chrono::seconds custom_rtc_differential;
|
||||
|
||||
BasicSetting<s32> current_user{0, "current_user"};
|
||||
Setting<s32> language_index{1, "language_index"};
|
||||
Setting<s32> region_index{1, "region_index"};
|
||||
Setting<s32> time_zone_index{0, "time_zone_index"};
|
||||
Setting<s32> sound_index{1, "sound_index"};
|
||||
RangedSetting<s32> language_index{1, 0, 16, "language_index"};
|
||||
RangedSetting<s32> region_index{1, 0, 6, "region_index"};
|
||||
RangedSetting<s32> time_zone_index{0, 0, 45, "time_zone_index"};
|
||||
RangedSetting<s32> sound_index{1, 0, 2, "sound_index"};
|
||||
|
||||
// Controls
|
||||
InputSetting<std::array<PlayerInput, 10>> players;
|
||||
@@ -384,7 +493,7 @@ struct Values {
|
||||
"udp_input_servers"};
|
||||
|
||||
BasicSetting<bool> mouse_panning{false, "mouse_panning"};
|
||||
BasicSetting<u8> mouse_panning_sensitivity{10, "mouse_panning_sensitivity"};
|
||||
BasicRangedSetting<u8> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"};
|
||||
BasicSetting<bool> mouse_enabled{false, "mouse_enabled"};
|
||||
std::string mouse_device;
|
||||
MouseButtonsRaw mouse_buttons;
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace HLE::ApiVersion {
|
||||
|
||||
// Horizon OS version constants.
|
||||
|
||||
constexpr u8 HOS_VERSION_MAJOR = 12;
|
||||
constexpr u8 HOS_VERSION_MINOR = 1;
|
||||
constexpr u8 HOS_VERSION_MICRO = 0;
|
||||
constexpr u8 HOS_VERSION_MAJOR = 11;
|
||||
constexpr u8 HOS_VERSION_MINOR = 0;
|
||||
constexpr u8 HOS_VERSION_MICRO = 1;
|
||||
|
||||
// NintendoSDK version constants.
|
||||
|
||||
@@ -22,15 +22,15 @@ constexpr u8 SDK_REVISION_MAJOR = 1;
|
||||
constexpr u8 SDK_REVISION_MINOR = 0;
|
||||
|
||||
constexpr char PLATFORM_STRING[] = "NX";
|
||||
constexpr char VERSION_HASH[] = "76b10c2dab7d3aa73fc162f8dff1655e6a21caf4";
|
||||
constexpr char DISPLAY_VERSION[] = "12.1.0";
|
||||
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 12.1.0-1.0";
|
||||
constexpr char VERSION_HASH[] = "69103fcb2004dace877094c2f8c29e6113be5dbf";
|
||||
constexpr char DISPLAY_VERSION[] = "11.0.1";
|
||||
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.1-1.0";
|
||||
|
||||
// Atmosphere version constants.
|
||||
|
||||
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MAJOR = 0;
|
||||
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MINOR = 19;
|
||||
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MICRO = 5;
|
||||
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MICRO = 4;
|
||||
|
||||
constexpr u32 GetTargetFirmware() {
|
||||
return u32{HOS_VERSION_MAJOR} << 24 | u32{HOS_VERSION_MINOR} << 16 |
|
||||
|
||||
@@ -377,7 +377,7 @@ void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) {
|
||||
|
||||
if (swkbd_config_common.use_utf8) {
|
||||
std::string utf8_submitted_text = Common::UTF16ToUTF8(current_text);
|
||||
const u64 buffer_size = utf8_submitted_text.size();
|
||||
const u64 buffer_size = sizeof(u64) + utf8_submitted_text.size();
|
||||
|
||||
LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-8 Submitted Text: {}", buffer_size,
|
||||
utf8_submitted_text);
|
||||
@@ -386,7 +386,7 @@ void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) {
|
||||
std::memcpy(out_data.data() + sizeof(u64), utf8_submitted_text.data(),
|
||||
utf8_submitted_text.size());
|
||||
} else {
|
||||
const u64 buffer_size = current_text.size() * sizeof(char16_t);
|
||||
const u64 buffer_size = sizeof(u64) + current_text.size() * sizeof(char16_t);
|
||||
|
||||
LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-16 Submitted Text: {}", buffer_size,
|
||||
Common::UTF16ToUTF8(current_text));
|
||||
|
||||
@@ -339,7 +339,6 @@ std::optional<ApplicationLanguage> ConvertToApplicationLanguage(
|
||||
case Set::LanguageCode::FR_CA:
|
||||
return ApplicationLanguage::CanadianFrench;
|
||||
case Set::LanguageCode::PT:
|
||||
case Set::LanguageCode::PT_BR:
|
||||
return ApplicationLanguage::Portuguese;
|
||||
case Set::LanguageCode::RU:
|
||||
return ApplicationLanguage::Russian;
|
||||
|
||||
@@ -166,6 +166,8 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vecto
|
||||
LOG_ERROR(Service_NVDRV, "failed to map size={}", object->size);
|
||||
} else {
|
||||
cmd_buffer.map_address = object->dma_map_addr;
|
||||
AddBufferMap(object->dma_map_addr, object->size, object->addr,
|
||||
object->status == nvmap::Object::Status::Allocated);
|
||||
}
|
||||
}
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlMapBuffer));
|
||||
@@ -176,11 +178,30 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vecto
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
// This is intntionally stubbed.
|
||||
// Skip unmapping buffers here, as to not break the continuity of the VP9 reference frame
|
||||
// addresses, and risk invalidating data before the async GPU thread is done with it
|
||||
IoctlMapBuffer params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));
|
||||
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
|
||||
SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
|
||||
|
||||
auto& gpu = system.GPU();
|
||||
|
||||
for (auto& cmd_buffer : cmd_buffer_handles) {
|
||||
const auto object{nvmap_dev->GetObject(cmd_buffer.map_handle)};
|
||||
if (!object) {
|
||||
LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmd_buffer.map_handle);
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::InvalidState;
|
||||
}
|
||||
if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
|
||||
gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
|
||||
} else {
|
||||
// This occurs quite frequently, however does not seem to impact functionality
|
||||
LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr,
|
||||
object->dma_map_addr);
|
||||
}
|
||||
object->dma_map_addr = 0;
|
||||
}
|
||||
std::memset(output.data(), 0, output.size());
|
||||
LOG_DEBUG(Service_NVDRV, "(STUBBED) called");
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
@@ -191,4 +212,33 @@ NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input,
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap(
|
||||
GPUVAddr gpu_addr) const {
|
||||
const auto it = std::find_if(
|
||||
buffer_mappings.begin(), buffer_mappings.upper_bound(gpu_addr), [&](const auto& entry) {
|
||||
return (gpu_addr >= entry.second.StartAddr() && gpu_addr < entry.second.EndAddr());
|
||||
});
|
||||
|
||||
ASSERT(it != buffer_mappings.end());
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void nvhost_nvdec_common::AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr,
|
||||
bool is_allocated) {
|
||||
buffer_mappings.insert_or_assign(gpu_addr, BufferMap{gpu_addr, size, cpu_addr, is_allocated});
|
||||
}
|
||||
|
||||
std::optional<std::size_t> nvhost_nvdec_common::RemoveBufferMap(GPUVAddr gpu_addr) {
|
||||
const auto iter{buffer_mappings.find(gpu_addr)};
|
||||
if (iter == buffer_mappings.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::size_t size = 0;
|
||||
if (iter->second.IsAllocated()) {
|
||||
size = iter->second.Size();
|
||||
}
|
||||
buffer_mappings.erase(iter);
|
||||
return size;
|
||||
}
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -23,6 +23,45 @@ public:
|
||||
~nvhost_nvdec_common() override;
|
||||
|
||||
protected:
|
||||
class BufferMap final {
|
||||
public:
|
||||
constexpr BufferMap() = default;
|
||||
|
||||
constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_)
|
||||
: start_addr{start_addr_}, end_addr{start_addr_ + size_} {}
|
||||
|
||||
constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_, VAddr cpu_addr_,
|
||||
bool is_allocated_)
|
||||
: start_addr{start_addr_}, end_addr{start_addr_ + size_}, cpu_addr{cpu_addr_},
|
||||
is_allocated{is_allocated_} {}
|
||||
|
||||
constexpr VAddr StartAddr() const {
|
||||
return start_addr;
|
||||
}
|
||||
|
||||
constexpr VAddr EndAddr() const {
|
||||
return end_addr;
|
||||
}
|
||||
|
||||
constexpr std::size_t Size() const {
|
||||
return end_addr - start_addr;
|
||||
}
|
||||
|
||||
constexpr VAddr CpuAddr() const {
|
||||
return cpu_addr;
|
||||
}
|
||||
|
||||
constexpr bool IsAllocated() const {
|
||||
return is_allocated;
|
||||
}
|
||||
|
||||
private:
|
||||
GPUVAddr start_addr{};
|
||||
GPUVAddr end_addr{};
|
||||
VAddr cpu_addr{};
|
||||
bool is_allocated{};
|
||||
};
|
||||
|
||||
struct IoctlSetNvmapFD {
|
||||
s32_le nvmap_fd{};
|
||||
};
|
||||
@@ -115,11 +154,17 @@ protected:
|
||||
NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
|
||||
std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
|
||||
void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
|
||||
std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr);
|
||||
|
||||
s32_le nvmap_fd{};
|
||||
u32_le submit_timeout{};
|
||||
std::shared_ptr<nvmap> nvmap_dev;
|
||||
SyncpointManager& syncpoint_manager;
|
||||
std::array<u32, MaxSyncPoints> device_syncpoints{};
|
||||
// This is expected to be ordered, therefore we must use a map, not unordered_map
|
||||
std::map<GPUVAddr, BufferMap> buffer_mappings;
|
||||
};
|
||||
}; // namespace Devices
|
||||
} // namespace Service::Nvidia
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
namespace Service::Set {
|
||||
namespace {
|
||||
constexpr std::array<LanguageCode, 18> available_language_codes = {{
|
||||
constexpr std::array<LanguageCode, 17> available_language_codes = {{
|
||||
LanguageCode::JA,
|
||||
LanguageCode::EN_US,
|
||||
LanguageCode::FR,
|
||||
@@ -30,7 +30,6 @@ constexpr std::array<LanguageCode, 18> available_language_codes = {{
|
||||
LanguageCode::ES_419,
|
||||
LanguageCode::ZH_HANS,
|
||||
LanguageCode::ZH_HANT,
|
||||
LanguageCode::PT_BR,
|
||||
}};
|
||||
|
||||
enum class KeyboardLayout : u64 {
|
||||
@@ -51,7 +50,7 @@ enum class KeyboardLayout : u64 {
|
||||
ChineseTraditional = 14,
|
||||
};
|
||||
|
||||
constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_layout{{
|
||||
constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 17> language_to_layout{{
|
||||
{LanguageCode::JA, KeyboardLayout::Japanese},
|
||||
{LanguageCode::EN_US, KeyboardLayout::EnglishUs},
|
||||
{LanguageCode::FR, KeyboardLayout::French},
|
||||
@@ -69,11 +68,10 @@ constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_la
|
||||
{LanguageCode::ES_419, KeyboardLayout::SpanishLatin},
|
||||
{LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified},
|
||||
{LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional},
|
||||
{LanguageCode::PT_BR, KeyboardLayout::Portuguese},
|
||||
}};
|
||||
|
||||
constexpr std::size_t PRE_4_0_0_MAX_ENTRIES = 0xF;
|
||||
constexpr std::size_t POST_4_0_0_MAX_ENTRIES = 0x40;
|
||||
constexpr std::size_t pre4_0_0_max_entries = 15;
|
||||
constexpr std::size_t post4_0_0_max_entries = 17;
|
||||
|
||||
constexpr ResultCode ERR_INVALID_LANGUAGE{ErrorModule::Settings, 625};
|
||||
|
||||
@@ -83,9 +81,9 @@ void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t num_la
|
||||
rb.Push(static_cast<u32>(num_language_codes));
|
||||
}
|
||||
|
||||
void GetAvailableLanguageCodesImpl(Kernel::HLERequestContext& ctx, std::size_t max_entries) {
|
||||
void GetAvailableLanguageCodesImpl(Kernel::HLERequestContext& ctx, std::size_t max_size) {
|
||||
const std::size_t requested_amount = ctx.GetWriteBufferSize() / sizeof(LanguageCode);
|
||||
const std::size_t copy_amount = std::min(requested_amount, max_entries);
|
||||
const std::size_t copy_amount = std::min(requested_amount, max_size);
|
||||
const std::size_t copy_size = copy_amount * sizeof(LanguageCode);
|
||||
|
||||
ctx.WriteBuffer(available_language_codes.data(), copy_size);
|
||||
@@ -120,7 +118,7 @@ LanguageCode GetLanguageCodeFromIndex(std::size_t index) {
|
||||
void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
GetAvailableLanguageCodesImpl(ctx, PRE_4_0_0_MAX_ENTRIES);
|
||||
GetAvailableLanguageCodesImpl(ctx, pre4_0_0_max_entries);
|
||||
}
|
||||
|
||||
void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) {
|
||||
@@ -142,19 +140,19 @@ void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) {
|
||||
void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
GetAvailableLanguageCodesImpl(ctx, POST_4_0_0_MAX_ENTRIES);
|
||||
GetAvailableLanguageCodesImpl(ctx, post4_0_0_max_entries);
|
||||
}
|
||||
|
||||
void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
PushResponseLanguageCode(ctx, PRE_4_0_0_MAX_ENTRIES);
|
||||
PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
|
||||
}
|
||||
|
||||
void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
PushResponseLanguageCode(ctx, POST_4_0_0_MAX_ENTRIES);
|
||||
PushResponseLanguageCode(ctx, post4_0_0_max_entries);
|
||||
}
|
||||
|
||||
void SET::GetQuestFlag(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
@@ -31,7 +31,6 @@ enum class LanguageCode : u64 {
|
||||
ES_419 = 0x00003931342D7365,
|
||||
ZH_HANS = 0x00736E61482D687A,
|
||||
ZH_HANT = 0x00746E61482D687A,
|
||||
PT_BR = 0x00000052422D7470,
|
||||
};
|
||||
LanguageCode GetLanguageCodeFromIndex(std::size_t idx);
|
||||
|
||||
|
||||
@@ -106,8 +106,6 @@ add_library(video_core STATIC
|
||||
renderer_vulkan/maxwell_to_vk.cpp
|
||||
renderer_vulkan/maxwell_to_vk.h
|
||||
renderer_vulkan/pipeline_helper.h
|
||||
renderer_vulkan/pipeline_statistics.cpp
|
||||
renderer_vulkan/pipeline_statistics.h
|
||||
renderer_vulkan/renderer_vulkan.h
|
||||
renderer_vulkan/renderer_vulkan.cpp
|
||||
renderer_vulkan/vk_blit_screen.cpp
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
|
||||
namespace Tegra::Decoder {
|
||||
namespace {
|
||||
constexpr u32 diff_update_probability = 252;
|
||||
constexpr u32 frame_sync_code = 0x498342;
|
||||
|
||||
// Default compressed header probabilities once frame context resets
|
||||
constexpr Vp9EntropyProbs default_probs{
|
||||
.y_mode_prob{
|
||||
@@ -364,7 +361,8 @@ Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state)
|
||||
InsertEntropy(state.vp9_entropy_probs_offset, vp9_info.entropy);
|
||||
|
||||
// surface_luma_offset[0:3] contains the address of the reference frame offsets in the following
|
||||
// order: last, golden, altref, current.
|
||||
// order: last, golden, altref, current. It may be worthwhile to track the updates done here
|
||||
// to avoid buffering frame data needed for reference frame updating in the header composition.
|
||||
std::copy(state.surface_luma_offset.begin(), state.surface_luma_offset.begin() + 4,
|
||||
vp9_info.frame_offsets.begin());
|
||||
|
||||
@@ -386,18 +384,33 @@ Vp9FrameContainer VP9::GetCurrentFrame(const NvdecCommon::NvdecRegisters& state)
|
||||
gpu.MemoryManager().ReadBlock(state.frame_bitstream_offset, current_frame.bit_stream.data(),
|
||||
current_frame.info.bitstream_size);
|
||||
}
|
||||
if (!next_frame.bit_stream.empty()) {
|
||||
// Buffer two frames, saving the last show frame info
|
||||
if (!next_next_frame.bit_stream.empty()) {
|
||||
Vp9FrameContainer temp{
|
||||
.info = current_frame.info,
|
||||
.bit_stream = std::move(current_frame.bit_stream),
|
||||
};
|
||||
next_frame.info.show_frame = current_frame.info.last_frame_shown;
|
||||
current_frame.info = next_frame.info;
|
||||
current_frame.bit_stream = std::move(next_frame.bit_stream);
|
||||
next_frame = std::move(temp);
|
||||
next_next_frame.info.show_frame = current_frame.info.last_frame_shown;
|
||||
current_frame.info = next_next_frame.info;
|
||||
current_frame.bit_stream = std::move(next_next_frame.bit_stream);
|
||||
next_next_frame = std::move(temp);
|
||||
|
||||
if (!next_frame.bit_stream.empty()) {
|
||||
Vp9FrameContainer temp2{
|
||||
.info = current_frame.info,
|
||||
.bit_stream = std::move(current_frame.bit_stream),
|
||||
};
|
||||
next_frame.info.show_frame = current_frame.info.last_frame_shown;
|
||||
current_frame.info = next_frame.info;
|
||||
current_frame.bit_stream = std::move(next_frame.bit_stream);
|
||||
next_frame = std::move(temp2);
|
||||
} else {
|
||||
next_frame.info = current_frame.info;
|
||||
next_frame.bit_stream = std::move(current_frame.bit_stream);
|
||||
}
|
||||
} else {
|
||||
next_frame.info = current_frame.info;
|
||||
next_frame.bit_stream = std::move(current_frame.bit_stream);
|
||||
next_next_frame.info = current_frame.info;
|
||||
next_next_frame.bit_stream = std::move(current_frame.bit_stream);
|
||||
}
|
||||
return current_frame;
|
||||
}
|
||||
@@ -600,64 +613,86 @@ VpxBitStreamWriter VP9::ComposeUncompressedHeader() {
|
||||
|
||||
// Reset context
|
||||
prev_frame_probs = default_probs;
|
||||
swap_ref_indices = false;
|
||||
swap_next_golden = false;
|
||||
loop_filter_ref_deltas.fill(0);
|
||||
loop_filter_mode_deltas.fill(0);
|
||||
frame_ctxs.fill(default_probs);
|
||||
|
||||
// allow frames offsets to stabilize before checking for golden frames
|
||||
grace_period = 4;
|
||||
|
||||
// On key frames, all frame slots are set to the current frame,
|
||||
// so the value of the selected slot doesn't really matter.
|
||||
frame_ctxs.fill({current_frame_number, false, default_probs});
|
||||
|
||||
// intra only, meaning the frame can be recreated with no other references
|
||||
current_frame_info.intra_only = true;
|
||||
|
||||
} else {
|
||||
|
||||
if (!current_frame_info.show_frame) {
|
||||
uncomp_writer.WriteBit(current_frame_info.intra_only);
|
||||
if (!current_frame_info.last_frame_was_key) {
|
||||
swap_next_golden = !swap_next_golden;
|
||||
}
|
||||
} else {
|
||||
current_frame_info.intra_only = false;
|
||||
}
|
||||
if (!current_frame_info.error_resilient_mode) {
|
||||
uncomp_writer.WriteU(0, 2); // Reset frame context.
|
||||
}
|
||||
const auto& curr_offsets = current_frame_info.frame_offsets;
|
||||
const auto& next_offsets = next_frame.info.frame_offsets;
|
||||
const bool ref_frames_different = curr_offsets[1] != curr_offsets[2];
|
||||
const bool next_references_swap =
|
||||
(next_offsets[1] == curr_offsets[2]) || (next_offsets[2] == curr_offsets[1]);
|
||||
const bool needs_ref_swap = ref_frames_different && next_references_swap;
|
||||
if (needs_ref_swap) {
|
||||
swap_ref_indices = !swap_ref_indices;
|
||||
}
|
||||
union {
|
||||
u32 raw;
|
||||
BitField<0, 1, u32> refresh_last;
|
||||
BitField<1, 2, u32> refresh_golden;
|
||||
BitField<2, 1, u32> refresh_alt;
|
||||
} refresh_frame_flags;
|
||||
|
||||
refresh_frame_flags.raw = 0;
|
||||
for (u32 index = 0; index < 3; ++index) {
|
||||
// Refresh indices that use the current frame as an index
|
||||
if (curr_offsets[3] == next_offsets[index]) {
|
||||
refresh_frame_flags.raw |= 1u << index;
|
||||
// Last, Golden, Altref frames
|
||||
std::array<s32, 3> ref_frame_index{0, 1, 2};
|
||||
|
||||
// Set when next frame is hidden
|
||||
// altref and golden references are swapped
|
||||
if (swap_next_golden) {
|
||||
ref_frame_index = std::array<s32, 3>{0, 2, 1};
|
||||
}
|
||||
|
||||
// update Last Frame
|
||||
u64 refresh_frame_flags = 1;
|
||||
|
||||
// golden frame may refresh, determined if the next golden frame offset is changed
|
||||
bool golden_refresh = false;
|
||||
if (grace_period <= 0) {
|
||||
for (s32 index = 1; index < 3; ++index) {
|
||||
if (current_frame_info.frame_offsets[index] !=
|
||||
next_frame.info.frame_offsets[index]) {
|
||||
current_frame_info.refresh_frame[index] = true;
|
||||
golden_refresh = true;
|
||||
grace_period = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (swap_ref_indices) {
|
||||
const u32 temp = refresh_frame_flags.refresh_golden;
|
||||
refresh_frame_flags.refresh_golden.Assign(refresh_frame_flags.refresh_alt.Value());
|
||||
refresh_frame_flags.refresh_alt.Assign(temp);
|
||||
|
||||
if (current_frame_info.show_frame &&
|
||||
(!next_frame.info.show_frame || next_frame.info.is_key_frame)) {
|
||||
// Update golden frame
|
||||
refresh_frame_flags = swap_next_golden ? 2 : 4;
|
||||
}
|
||||
|
||||
if (!current_frame_info.show_frame) {
|
||||
// Update altref
|
||||
refresh_frame_flags = swap_next_golden ? 2 : 4;
|
||||
} else if (golden_refresh) {
|
||||
refresh_frame_flags = 3;
|
||||
}
|
||||
|
||||
if (current_frame_info.intra_only) {
|
||||
uncomp_writer.WriteU(frame_sync_code, 24);
|
||||
uncomp_writer.WriteU(refresh_frame_flags.raw, 8);
|
||||
uncomp_writer.WriteU(static_cast<s32>(refresh_frame_flags), 8);
|
||||
uncomp_writer.WriteU(current_frame_info.frame_size.width - 1, 16);
|
||||
uncomp_writer.WriteU(current_frame_info.frame_size.height - 1, 16);
|
||||
uncomp_writer.WriteBit(false); // Render and frame size different.
|
||||
} else {
|
||||
const bool swap_indices = needs_ref_swap ^ swap_ref_indices;
|
||||
const auto ref_frame_index = swap_indices ? std::array{0, 2, 1} : std::array{0, 1, 2};
|
||||
uncomp_writer.WriteU(refresh_frame_flags.raw, 8);
|
||||
for (size_t index = 1; index < 4; index++) {
|
||||
uncomp_writer.WriteU(static_cast<s32>(refresh_frame_flags), 8);
|
||||
|
||||
for (s32 index = 1; index < 4; index++) {
|
||||
uncomp_writer.WriteU(ref_frame_index[index - 1], 3);
|
||||
uncomp_writer.WriteU(current_frame_info.ref_frame_sign_bias[index], 1);
|
||||
}
|
||||
|
||||
uncomp_writer.WriteBit(true); // Frame size with refs.
|
||||
uncomp_writer.WriteBit(false); // Render and frame size different.
|
||||
uncomp_writer.WriteBit(current_frame_info.allow_high_precision_mv);
|
||||
@@ -679,9 +714,10 @@ VpxBitStreamWriter VP9::ComposeUncompressedHeader() {
|
||||
frame_ctx_idx = 1;
|
||||
}
|
||||
|
||||
uncomp_writer.WriteU(frame_ctx_idx, 2); // Frame context index.
|
||||
prev_frame_probs = frame_ctxs[frame_ctx_idx]; // reference probabilities for compressed header
|
||||
frame_ctxs[frame_ctx_idx] = current_frame_info.entropy;
|
||||
uncomp_writer.WriteU(frame_ctx_idx, 2); // Frame context index.
|
||||
prev_frame_probs =
|
||||
frame_ctxs[frame_ctx_idx].probs; // reference probabilities for compressed header
|
||||
frame_ctxs[frame_ctx_idx] = {current_frame_number, false, current_frame_info.entropy};
|
||||
|
||||
uncomp_writer.WriteU(current_frame_info.first_level, 6);
|
||||
uncomp_writer.WriteU(current_frame_info.sharpness_level, 3);
|
||||
@@ -776,6 +812,7 @@ const std::vector<u8>& VP9::ComposeFrameHeader(const NvdecCommon::NvdecRegisters
|
||||
current_frame_info = curr_frame.info;
|
||||
bitstream = std::move(curr_frame.bit_stream);
|
||||
}
|
||||
|
||||
// The uncompressed header routine sets PrevProb parameters needed for the compressed header
|
||||
auto uncomp_writer = ComposeUncompressedHeader();
|
||||
std::vector<u8> compressed_header = ComposeCompressedHeader();
|
||||
@@ -791,6 +828,13 @@ const std::vector<u8>& VP9::ComposeFrameHeader(const NvdecCommon::NvdecRegisters
|
||||
frame.begin() + uncompressed_header.size());
|
||||
std::copy(bitstream.begin(), bitstream.end(),
|
||||
frame.begin() + uncompressed_header.size() + compressed_header.size());
|
||||
|
||||
// keep track of frame number
|
||||
current_frame_number++;
|
||||
grace_period--;
|
||||
|
||||
// don't display hidden frames
|
||||
hidden = !current_frame_info.show_frame;
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
namespace Tegra {
|
||||
class GPU;
|
||||
enum class FrameType { KeyFrame = 0, InterFrame = 1 };
|
||||
namespace Decoder {
|
||||
|
||||
/// The VpxRangeEncoder, and VpxBitStreamWriter classes are used to compose the
|
||||
@@ -123,7 +124,7 @@ public:
|
||||
|
||||
/// Returns true if the most recent frame was a hidden frame.
|
||||
[[nodiscard]] bool WasFrameHidden() const {
|
||||
return !current_frame_info.show_frame;
|
||||
return hidden;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -177,12 +178,19 @@ private:
|
||||
std::array<s8, 4> loop_filter_ref_deltas{};
|
||||
std::array<s8, 2> loop_filter_mode_deltas{};
|
||||
|
||||
bool hidden = false;
|
||||
s64 current_frame_number = -2; // since we buffer 2 frames
|
||||
s32 grace_period = 6; // frame offsets need to stabilize
|
||||
std::array<FrameContexts, 4> frame_ctxs{};
|
||||
Vp9FrameContainer next_frame{};
|
||||
std::array<Vp9EntropyProbs, 4> frame_ctxs{};
|
||||
bool swap_ref_indices{};
|
||||
Vp9FrameContainer next_next_frame{};
|
||||
bool swap_next_golden{};
|
||||
|
||||
Vp9PictureInfo current_frame_info{};
|
||||
Vp9EntropyProbs prev_frame_probs{};
|
||||
|
||||
s32 diff_update_probability = 252;
|
||||
s32 frame_sync_code = 0x498342;
|
||||
};
|
||||
|
||||
} // namespace Decoder
|
||||
|
||||
@@ -296,6 +296,12 @@ struct RefPoolElement {
|
||||
bool refresh{};
|
||||
};
|
||||
|
||||
struct FrameContexts {
|
||||
s64 from;
|
||||
bool adapted;
|
||||
Vp9EntropyProbs probs;
|
||||
};
|
||||
|
||||
#define ASSERT_POSITION(field_name, position) \
|
||||
static_assert(offsetof(Vp9EntropyProbs, field_name) == position, \
|
||||
"Field " #field_name " has invalid position")
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "video_core/renderer_vulkan/pipeline_statistics.h"
|
||||
#include "video_core/vulkan_common/vulkan_device.h"
|
||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
static u64 GetUint64(const VkPipelineExecutableStatisticKHR& statistic) {
|
||||
switch (statistic.format) {
|
||||
case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR:
|
||||
return static_cast<u64>(statistic.value.i64);
|
||||
case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR:
|
||||
return statistic.value.u64;
|
||||
case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR:
|
||||
return static_cast<u64>(statistic.value.f64);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
PipelineStatistics::PipelineStatistics(const Device& device_) : device{device_} {}
|
||||
|
||||
void PipelineStatistics::Collect(VkPipeline pipeline) {
|
||||
const auto& dev{device.GetLogical()};
|
||||
const std::vector properties{dev.GetPipelineExecutablePropertiesKHR(pipeline)};
|
||||
const u32 num_executables{static_cast<u32>(properties.size())};
|
||||
for (u32 executable = 0; executable < num_executables; ++executable) {
|
||||
const auto statistics{dev.GetPipelineExecutableStatisticsKHR(pipeline, executable)};
|
||||
if (statistics.empty()) {
|
||||
continue;
|
||||
}
|
||||
Stats stage_stats;
|
||||
for (const auto& statistic : statistics) {
|
||||
const char* const name{statistic.name};
|
||||
if (name == "Binary Size"sv || name == "Code size"sv || name == "Instruction Count"sv) {
|
||||
stage_stats.code_size = GetUint64(statistic);
|
||||
} else if (name == "Register Count"sv) {
|
||||
stage_stats.register_count = GetUint64(statistic);
|
||||
} else if (name == "SGPRs"sv || name == "numUsedSgprs"sv) {
|
||||
stage_stats.sgpr_count = GetUint64(statistic);
|
||||
} else if (name == "VGPRs"sv || name == "numUsedVgprs"sv) {
|
||||
stage_stats.vgpr_count = GetUint64(statistic);
|
||||
} else if (name == "Branches"sv) {
|
||||
stage_stats.branches_count = GetUint64(statistic);
|
||||
} else if (name == "Basic Block Count"sv) {
|
||||
stage_stats.basic_block_count = GetUint64(statistic);
|
||||
}
|
||||
}
|
||||
std::lock_guard lock{mutex};
|
||||
collected_stats.push_back(stage_stats);
|
||||
}
|
||||
}
|
||||
|
||||
void PipelineStatistics::Report() const {
|
||||
double num{};
|
||||
Stats total;
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
for (const Stats& stats : collected_stats) {
|
||||
total.code_size += stats.code_size;
|
||||
total.register_count += stats.register_count;
|
||||
total.sgpr_count += stats.sgpr_count;
|
||||
total.vgpr_count += stats.vgpr_count;
|
||||
total.branches_count += stats.branches_count;
|
||||
total.basic_block_count += stats.basic_block_count;
|
||||
}
|
||||
num = static_cast<double>(collected_stats.size());
|
||||
}
|
||||
std::string report;
|
||||
const auto add = [&](const char* fmt, u64 value) {
|
||||
if (value > 0) {
|
||||
report += fmt::format(fmt::runtime(fmt), static_cast<double>(value) / num);
|
||||
}
|
||||
};
|
||||
add("Code size: {:9.03f}\n", total.code_size);
|
||||
add("Register count: {:9.03f}\n", total.register_count);
|
||||
add("SGPRs: {:9.03f}\n", total.sgpr_count);
|
||||
add("VGPRs: {:9.03f}\n", total.vgpr_count);
|
||||
add("Branches count: {:9.03f}\n", total.branches_count);
|
||||
add("Basic blocks: {:9.03f}\n", total.basic_block_count);
|
||||
|
||||
LOG_INFO(Render_Vulkan,
|
||||
"\nAverage pipeline statistics\n"
|
||||
"==========================================\n"
|
||||
"{}\n",
|
||||
report);
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
class Device;
|
||||
|
||||
class PipelineStatistics {
|
||||
public:
|
||||
explicit PipelineStatistics(const Device& device_);
|
||||
|
||||
void Collect(VkPipeline pipeline);
|
||||
|
||||
void Report() const;
|
||||
|
||||
private:
|
||||
struct Stats {
|
||||
u64 code_size{};
|
||||
u64 register_count{};
|
||||
u64 sgpr_count{};
|
||||
u64 vgpr_count{};
|
||||
u64 branches_count{};
|
||||
u64 basic_block_count{};
|
||||
};
|
||||
|
||||
const Device& device;
|
||||
mutable std::mutex mutex;
|
||||
std::vector<Stats> collected_stats;
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#include "video_core/renderer_vulkan/pipeline_helper.h"
|
||||
#include "video_core/renderer_vulkan/pipeline_statistics.h"
|
||||
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
||||
#include "video_core/renderer_vulkan/vk_compute_pipeline.h"
|
||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
||||
@@ -27,7 +26,6 @@ using Tegra::Texture::TexturePair;
|
||||
ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descriptor_pool,
|
||||
VKUpdateDescriptorQueue& update_descriptor_queue_,
|
||||
Common::ThreadWorker* thread_worker,
|
||||
PipelineStatistics* pipeline_statistics,
|
||||
VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_,
|
||||
vk::ShaderModule spv_module_)
|
||||
: device{device_}, update_descriptor_queue{update_descriptor_queue_}, info{info_},
|
||||
@@ -38,7 +36,7 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript
|
||||
std::copy_n(info.constant_buffer_used_sizes.begin(), uniform_buffer_sizes.size(),
|
||||
uniform_buffer_sizes.begin());
|
||||
|
||||
auto func{[this, &descriptor_pool, shader_notify, pipeline_statistics] {
|
||||
auto func{[this, &descriptor_pool, shader_notify] {
|
||||
DescriptorLayoutBuilder builder{device};
|
||||
builder.Add(info, VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
|
||||
@@ -52,14 +50,10 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript
|
||||
.pNext = nullptr,
|
||||
.requiredSubgroupSize = GuestWarpSize,
|
||||
};
|
||||
VkPipelineCreateFlags flags{};
|
||||
if (device.IsKhrPipelineEexecutablePropertiesEnabled()) {
|
||||
flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
|
||||
}
|
||||
pipeline = device.GetLogical().CreateComputePipeline({
|
||||
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = flags,
|
||||
.flags = 0,
|
||||
.stage{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.pNext = device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr,
|
||||
@@ -73,9 +67,6 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript
|
||||
.basePipelineHandle = 0,
|
||||
.basePipelineIndex = 0,
|
||||
});
|
||||
if (pipeline_statistics) {
|
||||
pipeline_statistics->Collect(*pipeline);
|
||||
}
|
||||
std::lock_guard lock{build_mutex};
|
||||
is_built = true;
|
||||
build_condvar.notify_one();
|
||||
|
||||
@@ -25,7 +25,6 @@ class ShaderNotify;
|
||||
namespace Vulkan {
|
||||
|
||||
class Device;
|
||||
class PipelineStatistics;
|
||||
class VKScheduler;
|
||||
|
||||
class ComputePipeline {
|
||||
@@ -33,7 +32,6 @@ public:
|
||||
explicit ComputePipeline(const Device& device, DescriptorPool& descriptor_pool,
|
||||
VKUpdateDescriptorQueue& update_descriptor_queue,
|
||||
Common::ThreadWorker* thread_worker,
|
||||
PipelineStatistics* pipeline_statistics,
|
||||
VideoCore::ShaderNotify* shader_notify, const Shader::Info& info,
|
||||
vk::ShaderModule spv_module);
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "common/bit_field.h"
|
||||
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
|
||||
#include "video_core/renderer_vulkan/pipeline_helper.h"
|
||||
#include "video_core/renderer_vulkan/pipeline_statistics.h"
|
||||
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
||||
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
|
||||
#include "video_core/renderer_vulkan/vk_render_pass_cache.h"
|
||||
@@ -218,8 +217,8 @@ GraphicsPipeline::GraphicsPipeline(
|
||||
VKScheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_,
|
||||
VideoCore::ShaderNotify* shader_notify, const Device& device_, DescriptorPool& descriptor_pool,
|
||||
VKUpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread,
|
||||
PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache,
|
||||
const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages,
|
||||
RenderPassCache& render_pass_cache, const GraphicsPipelineCacheKey& key_,
|
||||
std::array<vk::ShaderModule, NUM_STAGES> stages,
|
||||
const std::array<const Shader::Info*, NUM_STAGES>& infos)
|
||||
: key{key_}, maxwell3d{maxwell3d_}, gpu_memory{gpu_memory_}, device{device_},
|
||||
texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, scheduler{scheduler_},
|
||||
@@ -236,7 +235,7 @@ GraphicsPipeline::GraphicsPipeline(
|
||||
enabled_uniform_buffer_masks[stage] = info->constant_buffer_mask;
|
||||
std::ranges::copy(info->constant_buffer_used_sizes, uniform_buffer_sizes[stage].begin());
|
||||
}
|
||||
auto func{[this, shader_notify, &render_pass_cache, &descriptor_pool, pipeline_statistics] {
|
||||
auto func{[this, shader_notify, &render_pass_cache, &descriptor_pool] {
|
||||
DescriptorLayoutBuilder builder{MakeBuilder(device, stage_infos)};
|
||||
uses_push_descriptor = builder.CanUsePushDescriptor();
|
||||
descriptor_set_layout = builder.CreateDescriptorSetLayout(uses_push_descriptor);
|
||||
@@ -251,9 +250,6 @@ GraphicsPipeline::GraphicsPipeline(
|
||||
const VkRenderPass render_pass{render_pass_cache.Get(MakeRenderPassKey(key.state))};
|
||||
Validate();
|
||||
MakePipeline(render_pass);
|
||||
if (pipeline_statistics) {
|
||||
pipeline_statistics->Collect(*pipeline);
|
||||
}
|
||||
|
||||
std::lock_guard lock{build_mutex};
|
||||
is_built = true;
|
||||
@@ -786,14 +782,10 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||
}
|
||||
*/
|
||||
}
|
||||
VkPipelineCreateFlags flags{};
|
||||
if (device.IsKhrPipelineEexecutablePropertiesEnabled()) {
|
||||
flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
|
||||
}
|
||||
pipeline = device.GetLogical().CreateGraphicsPipeline({
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = flags,
|
||||
.flags = 0,
|
||||
.stageCount = static_cast<u32>(shader_stages.size()),
|
||||
.pStages = shader_stages.data(),
|
||||
.pVertexInputState = &vertex_input_ci,
|
||||
|
||||
@@ -60,7 +60,6 @@ struct hash<Vulkan::GraphicsPipelineCacheKey> {
|
||||
namespace Vulkan {
|
||||
|
||||
class Device;
|
||||
class PipelineStatistics;
|
||||
class RenderPassCache;
|
||||
class VKScheduler;
|
||||
class VKUpdateDescriptorQueue;
|
||||
@@ -74,9 +73,8 @@ public:
|
||||
VKScheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache,
|
||||
VideoCore::ShaderNotify* shader_notify, const Device& device,
|
||||
DescriptorPool& descriptor_pool, VKUpdateDescriptorQueue& update_descriptor_queue,
|
||||
Common::ThreadWorker* worker_thread, PipelineStatistics* pipeline_statistics,
|
||||
RenderPassCache& render_pass_cache, const GraphicsPipelineCacheKey& key,
|
||||
std::array<vk::ShaderModule, NUM_STAGES> stages,
|
||||
Common::ThreadWorker* worker_thread, RenderPassCache& render_pass_cache,
|
||||
const GraphicsPipelineCacheKey& key, std::array<vk::ShaderModule, NUM_STAGES> stages,
|
||||
const std::array<const Shader::Info*, NUM_STAGES>& infos);
|
||||
|
||||
GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete;
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
|
||||
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
|
||||
#include "video_core/renderer_vulkan/pipeline_helper.h"
|
||||
#include "video_core/renderer_vulkan/pipeline_statistics.h"
|
||||
#include "video_core/renderer_vulkan/vk_compute_pipeline.h"
|
||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
||||
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
|
||||
@@ -390,19 +389,15 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
|
||||
size_t total{};
|
||||
size_t built{};
|
||||
bool has_loaded{};
|
||||
std::unique_ptr<PipelineStatistics> statistics;
|
||||
} state;
|
||||
|
||||
if (device.IsKhrPipelineEexecutablePropertiesEnabled()) {
|
||||
state.statistics = std::make_unique<PipelineStatistics>(device);
|
||||
}
|
||||
const auto load_compute{[&](std::ifstream& file, FileEnvironment env) {
|
||||
ComputePipelineCacheKey key;
|
||||
file.read(reinterpret_cast<char*>(&key), sizeof(key));
|
||||
|
||||
workers.QueueWork([this, key, env = std::move(env), &state, &callback]() mutable {
|
||||
ShaderPools pools;
|
||||
auto pipeline{CreateComputePipeline(pools, key, env, state.statistics.get(), false)};
|
||||
auto pipeline{CreateComputePipeline(pools, key, env, false)};
|
||||
std::lock_guard lock{state.mutex};
|
||||
if (pipeline) {
|
||||
compute_cache.emplace(key, std::move(pipeline));
|
||||
@@ -430,8 +425,7 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
|
||||
for (auto& env : envs) {
|
||||
env_ptrs.push_back(&env);
|
||||
}
|
||||
auto pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs),
|
||||
state.statistics.get(), false)};
|
||||
auto pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs), false)};
|
||||
|
||||
std::lock_guard lock{state.mutex};
|
||||
graphics_cache.emplace(key, std::move(pipeline));
|
||||
@@ -451,10 +445,6 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
|
||||
lock.unlock();
|
||||
|
||||
workers.WaitForRequests();
|
||||
|
||||
if (state.statistics) {
|
||||
state.statistics->Report();
|
||||
}
|
||||
}
|
||||
|
||||
GraphicsPipeline* PipelineCache::CurrentGraphicsPipelineSlowPath() {
|
||||
@@ -496,8 +486,7 @@ GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const
|
||||
|
||||
std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||
ShaderPools& pools, const GraphicsPipelineCacheKey& key,
|
||||
std::span<Shader::Environment* const> envs, PipelineStatistics* statistics,
|
||||
bool build_in_parallel) try {
|
||||
std::span<Shader::Environment* const> envs, bool build_in_parallel) try {
|
||||
LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash());
|
||||
size_t env_index{0};
|
||||
std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs;
|
||||
@@ -551,7 +540,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||
Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr};
|
||||
return std::make_unique<GraphicsPipeline>(
|
||||
maxwell3d, gpu_memory, scheduler, buffer_cache, texture_cache, &shader_notify, device,
|
||||
descriptor_pool, update_descriptor_queue, thread_worker, statistics, render_pass_cache, key,
|
||||
descriptor_pool, update_descriptor_queue, thread_worker, render_pass_cache, key,
|
||||
std::move(modules), infos);
|
||||
|
||||
} catch (const Shader::Exception& exception) {
|
||||
@@ -564,8 +553,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline() {
|
||||
GetGraphicsEnvironments(environments, graphics_key.unique_hashes);
|
||||
|
||||
main_pools.ReleaseContents();
|
||||
auto pipeline{
|
||||
CreateGraphicsPipeline(main_pools, graphics_key, environments.Span(), nullptr, true)};
|
||||
auto pipeline{CreateGraphicsPipeline(main_pools, graphics_key, environments.Span(), true)};
|
||||
if (!pipeline || pipeline_cache_filename.empty()) {
|
||||
return pipeline;
|
||||
}
|
||||
@@ -590,7 +578,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
env.SetCachedSize(shader->size_bytes);
|
||||
|
||||
main_pools.ReleaseContents();
|
||||
auto pipeline{CreateComputePipeline(main_pools, key, env, nullptr, true)};
|
||||
auto pipeline{CreateComputePipeline(main_pools, key, env, true)};
|
||||
if (!pipeline || pipeline_cache_filename.empty()) {
|
||||
return pipeline;
|
||||
}
|
||||
@@ -603,7 +591,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
|
||||
std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
ShaderPools& pools, const ComputePipelineCacheKey& key, Shader::Environment& env,
|
||||
PipelineStatistics* statistics, bool build_in_parallel) try {
|
||||
bool build_in_parallel) try {
|
||||
LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash());
|
||||
|
||||
Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()};
|
||||
@@ -617,8 +605,8 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
}
|
||||
Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr};
|
||||
return std::make_unique<ComputePipeline>(device, descriptor_pool, update_descriptor_queue,
|
||||
thread_worker, statistics, &shader_notify,
|
||||
program.info, std::move(spv_module));
|
||||
thread_worker, &shader_notify, program.info,
|
||||
std::move(spv_module));
|
||||
|
||||
} catch (const Shader::Exception& exception) {
|
||||
LOG_ERROR(Render_Vulkan, "{}", exception.what());
|
||||
|
||||
@@ -80,9 +80,8 @@ struct hash<Vulkan::ComputePipelineCacheKey> {
|
||||
namespace Vulkan {
|
||||
|
||||
class ComputePipeline;
|
||||
class DescriptorPool;
|
||||
class Device;
|
||||
class PipelineStatistics;
|
||||
class DescriptorPool;
|
||||
class RasterizerVulkan;
|
||||
class RenderPassCache;
|
||||
class VKScheduler;
|
||||
@@ -129,8 +128,7 @@ private:
|
||||
|
||||
std::unique_ptr<GraphicsPipeline> CreateGraphicsPipeline(
|
||||
ShaderPools& pools, const GraphicsPipelineCacheKey& key,
|
||||
std::span<Shader::Environment* const> envs, PipelineStatistics* statistics,
|
||||
bool build_in_parallel);
|
||||
std::span<Shader::Environment* const> envs, bool build_in_parallel);
|
||||
|
||||
std::unique_ptr<ComputePipeline> CreateComputePipeline(const ComputePipelineCacheKey& key,
|
||||
const ShaderInfo* shader);
|
||||
@@ -138,7 +136,6 @@ private:
|
||||
std::unique_ptr<ComputePipeline> CreateComputePipeline(ShaderPools& pools,
|
||||
const ComputePipelineCacheKey& key,
|
||||
Shader::Environment& env,
|
||||
PipelineStatistics* statistics,
|
||||
bool build_in_parallel);
|
||||
|
||||
const Device& device;
|
||||
|
||||
@@ -526,17 +526,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
SetNext(next, workgroup_layout);
|
||||
}
|
||||
|
||||
VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR executable_properties;
|
||||
if (khr_pipeline_executable_properties) {
|
||||
LOG_INFO(Render_Vulkan, "Enabling shader feedback, expect slower shader build times");
|
||||
executable_properties = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR,
|
||||
.pNext = nullptr,
|
||||
.pipelineExecutableInfo = VK_TRUE,
|
||||
};
|
||||
SetNext(next, executable_properties);
|
||||
}
|
||||
|
||||
if (!ext_depth_range_unrestricted) {
|
||||
LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted");
|
||||
}
|
||||
@@ -835,7 +824,6 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
|
||||
|
||||
bool has_khr_shader_float16_int8{};
|
||||
bool has_khr_workgroup_memory_explicit_layout{};
|
||||
bool has_khr_pipeline_executable_properties{};
|
||||
bool has_ext_subgroup_size_control{};
|
||||
bool has_ext_transform_feedback{};
|
||||
bool has_ext_custom_border_color{};
|
||||
@@ -890,10 +878,6 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
|
||||
test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME,
|
||||
true);
|
||||
}
|
||||
if (Settings::values.renderer_shader_feedback) {
|
||||
test(has_khr_pipeline_executable_properties,
|
||||
VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME, false);
|
||||
}
|
||||
}
|
||||
VkPhysicalDeviceFeatures2KHR features{};
|
||||
features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
|
||||
@@ -1049,19 +1033,6 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
|
||||
khr_workgroup_memory_explicit_layout = true;
|
||||
}
|
||||
}
|
||||
if (has_khr_pipeline_executable_properties) {
|
||||
VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR executable_properties;
|
||||
executable_properties.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR;
|
||||
executable_properties.pNext = nullptr;
|
||||
features.pNext = &executable_properties;
|
||||
physical.GetFeatures2KHR(features);
|
||||
|
||||
if (executable_properties.pipelineExecutableInfo) {
|
||||
extensions.push_back(VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME);
|
||||
khr_pipeline_executable_properties = true;
|
||||
}
|
||||
}
|
||||
if (khr_push_descriptor) {
|
||||
VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor;
|
||||
push_descriptor.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR;
|
||||
|
||||
@@ -214,11 +214,6 @@ public:
|
||||
return khr_push_descriptor;
|
||||
}
|
||||
|
||||
/// Returns true if VK_KHR_pipeline_executable_properties is enabled.
|
||||
bool IsKhrPipelineEexecutablePropertiesEnabled() const {
|
||||
return khr_pipeline_executable_properties;
|
||||
}
|
||||
|
||||
/// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout.
|
||||
bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const {
|
||||
return khr_workgroup_memory_explicit_layout;
|
||||
@@ -383,7 +378,6 @@ private:
|
||||
bool khr_spirv_1_4{}; ///< Support for VK_KHR_spirv_1_4.
|
||||
bool khr_workgroup_memory_explicit_layout{}; ///< Support for explicit workgroup layouts.
|
||||
bool khr_push_descriptor{}; ///< Support for VK_KHR_push_descritor.
|
||||
bool khr_pipeline_executable_properties{}; ///< Support for executable properties.
|
||||
bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8.
|
||||
bool ext_sampler_filter_minmax{}; ///< Support for VK_EXT_sampler_filter_minmax.
|
||||
bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted.
|
||||
|
||||
@@ -181,8 +181,6 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
|
||||
X(vkGetMemoryWin32HandleKHR);
|
||||
#endif
|
||||
X(vkGetQueryPoolResults);
|
||||
X(vkGetPipelineExecutablePropertiesKHR);
|
||||
X(vkGetPipelineExecutableStatisticsKHR);
|
||||
X(vkGetSemaphoreCounterValueKHR);
|
||||
X(vkMapMemory);
|
||||
X(vkQueueSubmit);
|
||||
@@ -811,42 +809,6 @@ VkMemoryRequirements Device::GetImageMemoryRequirements(VkImage image) const noe
|
||||
return requirements;
|
||||
}
|
||||
|
||||
std::vector<VkPipelineExecutablePropertiesKHR> Device::GetPipelineExecutablePropertiesKHR(
|
||||
VkPipeline pipeline) const {
|
||||
const VkPipelineInfoKHR info{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR,
|
||||
.pNext = nullptr,
|
||||
.pipeline = pipeline,
|
||||
};
|
||||
u32 num{};
|
||||
dld->vkGetPipelineExecutablePropertiesKHR(handle, &info, &num, nullptr);
|
||||
std::vector<VkPipelineExecutablePropertiesKHR> properties(num);
|
||||
for (auto& property : properties) {
|
||||
property.sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR;
|
||||
}
|
||||
Check(dld->vkGetPipelineExecutablePropertiesKHR(handle, &info, &num, properties.data()));
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::vector<VkPipelineExecutableStatisticKHR> Device::GetPipelineExecutableStatisticsKHR(
|
||||
VkPipeline pipeline, u32 executable_index) const {
|
||||
const VkPipelineExecutableInfoKHR executable_info{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR,
|
||||
.pNext = nullptr,
|
||||
.pipeline = pipeline,
|
||||
.executableIndex = executable_index,
|
||||
};
|
||||
u32 num{};
|
||||
dld->vkGetPipelineExecutableStatisticsKHR(handle, &executable_info, &num, nullptr);
|
||||
std::vector<VkPipelineExecutableStatisticKHR> statistics(num);
|
||||
for (auto& statistic : statistics) {
|
||||
statistic.sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR;
|
||||
}
|
||||
Check(dld->vkGetPipelineExecutableStatisticsKHR(handle, &executable_info, &num,
|
||||
statistics.data()));
|
||||
return statistics;
|
||||
}
|
||||
|
||||
void Device::UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes,
|
||||
Span<VkCopyDescriptorSet> copies) const noexcept {
|
||||
dld->vkUpdateDescriptorSets(handle, writes.size(), writes.data(), copies.size(), copies.data());
|
||||
|
||||
@@ -295,8 +295,6 @@ struct DeviceDispatch : InstanceDispatch {
|
||||
#ifdef _WIN32
|
||||
PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR{};
|
||||
#endif
|
||||
PFN_vkGetPipelineExecutablePropertiesKHR vkGetPipelineExecutablePropertiesKHR{};
|
||||
PFN_vkGetPipelineExecutableStatisticsKHR vkGetPipelineExecutableStatisticsKHR{};
|
||||
PFN_vkGetQueryPoolResults vkGetQueryPoolResults{};
|
||||
PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR{};
|
||||
PFN_vkMapMemory vkMapMemory{};
|
||||
@@ -881,12 +879,6 @@ public:
|
||||
|
||||
VkMemoryRequirements GetImageMemoryRequirements(VkImage image) const noexcept;
|
||||
|
||||
std::vector<VkPipelineExecutablePropertiesKHR> GetPipelineExecutablePropertiesKHR(
|
||||
VkPipeline pipeline) const;
|
||||
|
||||
std::vector<VkPipelineExecutableStatisticKHR> GetPipelineExecutableStatisticsKHR(
|
||||
VkPipeline pipeline, u32 executable_index) const;
|
||||
|
||||
void UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes,
|
||||
Span<VkCopyDescriptorSet> copies) const noexcept;
|
||||
|
||||
|
||||
@@ -825,7 +825,6 @@ void Config::ReadRendererValues() {
|
||||
if (global) {
|
||||
ReadBasicSetting(Settings::values.fps_cap);
|
||||
ReadBasicSetting(Settings::values.renderer_debug);
|
||||
ReadBasicSetting(Settings::values.renderer_shader_feedback);
|
||||
ReadBasicSetting(Settings::values.enable_nsight_aftermath);
|
||||
ReadBasicSetting(Settings::values.disable_shader_loop_safety_checks);
|
||||
}
|
||||
@@ -1364,7 +1363,6 @@ void Config::SaveRendererValues() {
|
||||
if (global) {
|
||||
WriteBasicSetting(Settings::values.fps_cap);
|
||||
WriteBasicSetting(Settings::values.renderer_debug);
|
||||
WriteBasicSetting(Settings::values.renderer_shader_feedback);
|
||||
WriteBasicSetting(Settings::values.enable_nsight_aftermath);
|
||||
WriteBasicSetting(Settings::values.disable_shader_loop_safety_checks);
|
||||
}
|
||||
|
||||
@@ -43,8 +43,6 @@ void ConfigureDebug::SetConfiguration() {
|
||||
ui->use_auto_stub->setChecked(Settings::values.use_auto_stub.GetValue());
|
||||
ui->enable_graphics_debugging->setEnabled(runtime_lock);
|
||||
ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue());
|
||||
ui->enable_shader_feedback->setEnabled(runtime_lock);
|
||||
ui->enable_shader_feedback->setChecked(Settings::values.renderer_shader_feedback.GetValue());
|
||||
ui->enable_cpu_debugging->setEnabled(runtime_lock);
|
||||
ui->enable_cpu_debugging->setChecked(Settings::values.cpu_debug_mode.GetValue());
|
||||
ui->enable_nsight_aftermath->setEnabled(runtime_lock);
|
||||
@@ -67,7 +65,6 @@ void ConfigureDebug::ApplyConfiguration() {
|
||||
Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked();
|
||||
Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
|
||||
Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
|
||||
Settings::values.renderer_shader_feedback = ui->enable_shader_feedback->isChecked();
|
||||
Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked();
|
||||
Settings::values.enable_nsight_aftermath = ui->enable_nsight_aftermath->isChecked();
|
||||
Settings::values.disable_shader_loop_safety_checks =
|
||||
|
||||
@@ -111,8 +111,8 @@
|
||||
<property name="title">
|
||||
<string>Graphics</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enable_graphics_debugging">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
@@ -125,7 +125,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enable_nsight_aftermath">
|
||||
<property name="toolTip">
|
||||
<string>When checked, it enables Nsight Aftermath crash dumps</string>
|
||||
@@ -135,7 +135,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="disable_macro_jit">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
@@ -148,17 +148,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="enable_shader_feedback">
|
||||
<property name="toolTip">
|
||||
<string>When checked, yuzu will log statistics about the compiled pipeline cache</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable Shader Feedback</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="disable_loop_safety_checks">
|
||||
<property name="toolTip">
|
||||
<string>When checked, it executes shaders without loop logic changes</string>
|
||||
@@ -286,14 +276,11 @@
|
||||
<tabstop>open_log_button</tabstop>
|
||||
<tabstop>homebrew_args_edit</tabstop>
|
||||
<tabstop>enable_graphics_debugging</tabstop>
|
||||
<tabstop>enable_shader_feedback</tabstop>
|
||||
<tabstop>enable_nsight_aftermath</tabstop>
|
||||
<tabstop>disable_macro_jit</tabstop>
|
||||
<tabstop>disable_loop_safety_checks</tabstop>
|
||||
<tabstop>fs_access_log</tabstop>
|
||||
<tabstop>reporting_services</tabstop>
|
||||
<tabstop>quest_flag</tabstop>
|
||||
<tabstop>enable_cpu_debugging</tabstop>
|
||||
<tabstop>use_debug_asserts</tabstop>
|
||||
<tabstop>use_auto_stub</tabstop>
|
||||
</tabstops>
|
||||
|
||||
@@ -401,11 +401,6 @@
|
||||
<string>Traditional Chinese (正體中文)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Brazilian Portuguese (português do Brasil)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
|
||||
@@ -444,7 +444,6 @@ void Config::ReadValues() {
|
||||
// Renderer
|
||||
ReadSetting("Renderer", Settings::values.renderer_backend);
|
||||
ReadSetting("Renderer", Settings::values.renderer_debug);
|
||||
ReadSetting("Renderer", Settings::values.renderer_shader_feedback);
|
||||
ReadSetting("Renderer", Settings::values.enable_nsight_aftermath);
|
||||
ReadSetting("Renderer", Settings::values.disable_shader_loop_safety_checks);
|
||||
ReadSetting("Renderer", Settings::values.vulkan_device);
|
||||
|
||||
@@ -221,10 +221,6 @@ backend =
|
||||
# 0 (default): Disabled, 1: Enabled
|
||||
debug =
|
||||
|
||||
# Enable shader feedback.
|
||||
# 0 (default): Disabled, 1: Enabled
|
||||
renderer_shader_feedback =
|
||||
|
||||
# Enable Nsight Aftermath crash dumps
|
||||
# 0 (default): Disabled, 1: Enabled
|
||||
nsight_aftermath =
|
||||
@@ -367,7 +363,7 @@ custom_rtc =
|
||||
# Sets the systems language index
|
||||
# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese,
|
||||
# 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French,
|
||||
# 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese, 17: Brazilian Portuguese
|
||||
# 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese
|
||||
language_index =
|
||||
|
||||
# The system region that yuzu will use during emulation
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
|
||||
#include "yuzu_cmd/yuzu_icon.h"
|
||||
|
||||
EmuWindow_SDL2::EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_)
|
||||
: input_subsystem{input_subsystem_}, system{system_} {
|
||||
EmuWindow_SDL2::EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_)
|
||||
: input_subsystem{input_subsystem_} {
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
|
||||
LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting...");
|
||||
exit(1);
|
||||
@@ -218,7 +218,7 @@ void EmuWindow_SDL2::WaitEvent() {
|
||||
|
||||
const u32 current_time = SDL_GetTicks();
|
||||
if (current_time > last_time + 2000) {
|
||||
const auto results = system.GetAndResetPerfStats();
|
||||
const auto results = Core::System::GetInstance().GetAndResetPerfStats();
|
||||
const auto title =
|
||||
fmt::format("yuzu {} | {}-{} | FPS: {:.0f} ({:.0f}%)", Common::g_build_fullname,
|
||||
Common::g_scm_branch, Common::g_scm_desc, results.average_game_fps,
|
||||
|
||||
@@ -24,7 +24,7 @@ enum class MouseButton;
|
||||
|
||||
class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
|
||||
public:
|
||||
explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem, Core::System& system_);
|
||||
explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem);
|
||||
~EmuWindow_SDL2();
|
||||
|
||||
/// Whether the window is still open, and a close request hasn't yet been sent
|
||||
@@ -87,7 +87,4 @@ protected:
|
||||
|
||||
/// Input subsystem to use with this window.
|
||||
InputCommon::InputSubsystem* input_subsystem;
|
||||
|
||||
/// yuzu core instance
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
@@ -76,9 +76,8 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() {
|
||||
return unsupported_ext.empty();
|
||||
}
|
||||
|
||||
EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem,
|
||||
Core::System& system_, bool fullscreen)
|
||||
: EmuWindow_SDL2{input_subsystem, system_} {
|
||||
EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen)
|
||||
: EmuWindow_SDL2{input_subsystem} {
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
|
||||
|
||||
@@ -8,18 +8,13 @@
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace InputCommon {
|
||||
class InputSubsystem;
|
||||
}
|
||||
|
||||
class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 {
|
||||
public:
|
||||
explicit EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, Core::System& system_,
|
||||
bool fullscreen);
|
||||
explicit EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen);
|
||||
~EmuWindow_SDL2_GL();
|
||||
|
||||
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
|
||||
|
||||
@@ -24,9 +24,8 @@
|
||||
#include <SDL.h>
|
||||
#include <SDL_syswm.h>
|
||||
|
||||
EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem,
|
||||
Core::System& system_, bool fullscreen)
|
||||
: EmuWindow_SDL2{input_subsystem, system_} {
|
||||
EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem, bool fullscreen)
|
||||
: EmuWindow_SDL2{input_subsystem} {
|
||||
const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name,
|
||||
Common::g_scm_branch, Common::g_scm_desc);
|
||||
render_window =
|
||||
|
||||
@@ -19,8 +19,7 @@ class InputSubsystem;
|
||||
|
||||
class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 {
|
||||
public:
|
||||
explicit EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem, Core::System& system,
|
||||
bool fullscreen);
|
||||
explicit EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem, bool fullscreen);
|
||||
~EmuWindow_SDL2_VK() override;
|
||||
|
||||
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
|
||||
|
||||
@@ -172,10 +172,10 @@ int main(int argc, char** argv) {
|
||||
std::unique_ptr<EmuWindow_SDL2> emu_window;
|
||||
switch (Settings::values.renderer_backend.GetValue()) {
|
||||
case Settings::RendererBackend::OpenGL:
|
||||
emu_window = std::make_unique<EmuWindow_SDL2_GL>(&input_subsystem, system, fullscreen);
|
||||
emu_window = std::make_unique<EmuWindow_SDL2_GL>(&input_subsystem, fullscreen);
|
||||
break;
|
||||
case Settings::RendererBackend::Vulkan:
|
||||
emu_window = std::make_unique<EmuWindow_SDL2_VK>(&input_subsystem, system, fullscreen);
|
||||
emu_window = std::make_unique<EmuWindow_SDL2_VK>(&input_subsystem, fullscreen);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user