(stages.size()),
+ .pStages = stages.data(),
+ .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+ .pTessellationState = nullptr,
+ .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+ .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+ .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+ .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
+ .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO,
+ .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+ .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout,
+ .renderPass = renderpass,
+ .subpass = 0,
+ .basePipelineHandle = VK_NULL_HANDLE,
+ .basePipelineIndex = 0,
+ });
+}
+
} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h
index d77f76678..f754a7294 100644
--- a/src/video_core/renderer_vulkan/blit_image.h
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -56,10 +56,19 @@ public:
void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
u32 up_scale, u32 down_shift);
+ void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
+ u32 up_scale, u32 down_shift);
+
+ void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
+ u32 up_scale, u32 down_shift);
+
private:
void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
const ImageView& src_image_view, u32 up_scale, u32 down_shift);
+ void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
+ ImageView& src_image_view, u32 up_scale, u32 down_shift);
+
[[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key);
[[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key);
@@ -68,6 +77,9 @@ private:
void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
+ void ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
+ vk::ShaderModule& module, bool single_texture);
+
const Device& device;
VKScheduler& scheduler;
StateTracker& state_tracker;
@@ -83,6 +95,8 @@ private:
vk::ShaderModule blit_depth_stencil_frag;
vk::ShaderModule convert_depth_to_float_frag;
vk::ShaderModule convert_float_to_depth_frag;
+ vk::ShaderModule convert_abgr8_to_d24s8_frag;
+ vk::ShaderModule convert_d24s8_to_abgr8_frag;
vk::Sampler linear_sampler;
vk::Sampler nearest_sampler;
@@ -94,6 +108,8 @@ private:
vk::Pipeline convert_r32_to_d32_pipeline;
vk::Pipeline convert_d16_to_r16_pipeline;
vk::Pipeline convert_r16_to_d16_pipeline;
+ vk::Pipeline convert_abgr8_to_d24s8_pipeline;
+ vk::Pipeline convert_d24s8_to_abgr8_pipeline;
};
} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 407fd2a15..6dfd45f31 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -881,6 +881,12 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
return blit_image_helper.ConvertD16ToR16(dst, src_view, up_scale, down_shift);
}
break;
+ case PixelFormat::A8B8G8R8_UNORM:
+ case PixelFormat::B8G8R8A8_UNORM:
+ if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) {
+ return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view, up_scale, down_shift);
+ }
+ break;
case PixelFormat::R32_FLOAT:
if (src_view.format == PixelFormat::D32_FLOAT) {
return blit_image_helper.ConvertD32ToR32(dst, src_view, up_scale, down_shift);
@@ -891,6 +897,12 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
return blit_image_helper.ConvertR16ToD16(dst, src_view, up_scale, down_shift);
}
break;
+ case PixelFormat::S8_UINT_D24_UNORM:
+ if (src_view.format == PixelFormat::A8B8G8R8_UNORM ||
+ src_view.format == PixelFormat::B8G8R8A8_UNORM) {
+ return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view, up_scale, down_shift);
+ }
+ break;
case PixelFormat::D32_FLOAT:
if (src_view.format == PixelFormat::R32_FLOAT) {
return blit_image_helper.ConvertR32ToD32(dst, src_view, up_scale, down_shift);
--
cgit v1.2.3
From b130f648d7c629411c487722f864c6bafcd2562c Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow
Date: Fri, 19 Nov 2021 03:17:54 +0100
Subject: TextureCache: Fix regression caused by ART and improve blit detection
algorithm to be smarter.
---
src/video_core/texture_cache/texture_cache.h | 9 +++------
src/video_core/texture_cache/util.cpp | 28 ++++++++++++++++++++++++----
2 files changed, 27 insertions(+), 10 deletions(-)
(limited to 'src')
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 241f71a91..5ade3ce55 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -475,6 +475,7 @@ void TextureCache::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
const BlitImages images = GetBlitImages(dst, src);
const ImageId dst_id = images.dst_id;
const ImageId src_id = images.src_id;
+
PrepareImage(src_id, false, false);
PrepareImage(dst_id, true, false);
@@ -1094,12 +1095,8 @@ typename TextureCache
::BlitImages TextureCache
::GetBlitImages(
if (GetFormatType(dst_info.format) != GetFormatType(src_info.format)) {
continue;
}
- if (!dst_id) {
- dst_id = InsertImage(dst_info, dst_addr, RelaxedOptions{});
- }
- if (!src_id) {
- src_id = InsertImage(src_info, src_addr, RelaxedOptions{});
- }
+ src_id = FindOrInsertImage(src_info, src_addr);
+ dst_id = FindOrInsertImage(dst_info, dst_addr);
} while (has_deleted_images);
return BlitImages{
.dst_id = dst_id,
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index ddc9fb13a..8f9eb387c 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -1151,17 +1151,37 @@ bool IsSubresource(const ImageInfo& candidate, const ImageBase& image, GPUVAddr
void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst,
const ImageBase* src) {
- if (src && GetFormatType(src->info.format) != SurfaceType::ColorTexture) {
+ if (src) {
src_info.format = src->info.format;
+ src_info.num_samples = src->info.num_samples;
+ src_info.size = src->info.size;
}
- if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) {
+ if (dst) {
dst_info.format = dst->info.format;
+ dst_info.num_samples = dst->info.num_samples;
+ dst_info.size = dst->info.size;
}
if (src && GetFormatType(src->info.format) != SurfaceType::ColorTexture) {
- dst_info.format = src->info.format;
+ if (dst) {
+ src_info.format = dst_info.format;
+ } else {
+ dst_info.format = src->info.format;
+ }
}
if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) {
- src_info.format = dst->info.format;
+ if (src) {
+ if (GetFormatType(src->info.format) == SurfaceType::ColorTexture) {
+ dst_info.format = src->info.format;
+ }
+ } else {
+ src_info.format = dst->info.format;
+ }
+ }
+ if (src_info.num_samples > 1) {
+ dst_info.format = src_info.format;
+ }
+ if (dst_info.num_samples > 1) {
+ src_info.format = dst_info.format;
}
}
--
cgit v1.2.3
From c76163b611350e2261a6a64f1853626af6f57ada Mon Sep 17 00:00:00 2001
From: Morph
Date: Thu, 18 Nov 2021 23:04:06 -0500
Subject: main: Shorten AMD FSR status bar text
AMD'S FIDELITYFX SR -> FSR
---
src/yuzu/main.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 6071a222f..689746028 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -3106,7 +3106,7 @@ void GMainWindow::UpdateFilterText() {
filter_status_button->setText(tr("SCALEFORCE"));
break;
case Settings::ScalingFilter::Fsr:
- filter_status_button->setText(tr("AMD'S FIDELITYFX SR"));
+ filter_status_button->setText(tr("FSR"));
break;
default:
filter_status_button->setText(tr("BILINEAR"));
--
cgit v1.2.3
From a237fb5f759f15e1e1a8f920118e2189ad6d82e0 Mon Sep 17 00:00:00 2001
From: Morph
Date: Thu, 18 Nov 2021 23:09:28 -0500
Subject: configure_graphics_ui: AMD's -> AMD
AMD officially markets FSR as AMD FidelityFX™️ Super Resolution
---
src/yuzu/configuration/configure_graphics.ui | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 660b68c1c..9241678e4 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -429,7 +429,7 @@
-
- AMD's FidelityFX™️ Super Resolution [Vulkan Only]
+ AMD FidelityFX™️ Super Resolution [Vulkan Only]
--
cgit v1.2.3
From bc5ed1aa1b41b9960657dddee658c3ce344cb501 Mon Sep 17 00:00:00 2001
From: Morph
Date: Thu, 18 Nov 2021 23:22:32 -0500
Subject: main: Fix default AA name
By default, no AA is applied, not FXAA
---
src/yuzu/main.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
(limited to 'src')
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 689746028..44800e165 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -3117,15 +3117,15 @@ void GMainWindow::UpdateFilterText() {
void GMainWindow::UpdateAAText() {
const auto aa_mode = Settings::values.anti_aliasing.GetValue();
switch (aa_mode) {
- case Settings::AntiAliasing::Fxaa:
- aa_status_button->setText(tr("FXAA"));
- break;
case Settings::AntiAliasing::None:
aa_status_button->setText(tr("NO AA"));
break;
- default:
+ case Settings::AntiAliasing::Fxaa:
aa_status_button->setText(tr("FXAA"));
break;
+ default:
+ aa_status_button->setText(tr("NO AA"));
+ break;
}
}
--
cgit v1.2.3
From 0ff228405faae92a39167b9aec072e14744eae35 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow
Date: Fri, 19 Nov 2021 05:46:57 +0100
Subject: TextureCache: force same image format when resolving an image.
---
src/video_core/texture_cache/texture_cache.h | 10 ++++++++--
src/video_core/texture_cache/types.h | 1 +
2 files changed, 9 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 5ade3ce55..06257f064 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -759,7 +759,8 @@ ImageId TextureCache
::FindImage(const ImageInfo& info, GPUVAddr gpu_addr,
return ImageId{};
}
}
- const bool broken_views = runtime.HasBrokenTextureViewFormats();
+ const bool broken_views =
+ runtime.HasBrokenTextureViewFormats() || True(options & RelaxedOptions::ForceBrokenViews);
const bool native_bgr = runtime.HasNativeBgr();
ImageId image_id;
const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) {
@@ -1096,7 +1097,12 @@ typename TextureCache
::BlitImages TextureCache
::GetBlitImages(
continue;
}
src_id = FindOrInsertImage(src_info, src_addr);
- dst_id = FindOrInsertImage(dst_info, dst_addr);
+ RelaxedOptions dst_options{};
+ if (src_info.num_samples > 1) {
+ // it's a resolve, we must enforce the same format.
+ dst_options = RelaxedOptions::ForceBrokenViews;
+ }
+ dst_id = FindOrInsertImage(dst_info, dst_addr, dst_options);
} while (has_deleted_images);
return BlitImages{
.dst_id = dst_id,
diff --git a/src/video_core/texture_cache/types.h b/src/video_core/texture_cache/types.h
index 5c274abdf..5ac27b3a7 100644
--- a/src/video_core/texture_cache/types.h
+++ b/src/video_core/texture_cache/types.h
@@ -54,6 +54,7 @@ enum class RelaxedOptions : u32 {
Size = 1 << 0,
Format = 1 << 1,
Samples = 1 << 2,
+ ForceBrokenViews = 1 << 3,
};
DECLARE_ENUM_FLAG_OPERATORS(RelaxedOptions)
--
cgit v1.2.3
From b805c7bf058c6da04620cf75880509bdf6d5986c Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow
Date: Fri, 19 Nov 2021 06:27:44 +0100
Subject: TextureCache: Implement additional D24S8 convertions.
---
src/video_core/host_shaders/CMakeLists.txt | 2 ++
.../host_shaders/convert_d24s8_to_b10g11r11.frag | 21 +++++++++++++++++++++
.../host_shaders/convert_d24s8_to_r16g16.frag | 21 +++++++++++++++++++++
src/video_core/renderer_vulkan/blit_image.cpp | 22 ++++++++++++++++++++++
src/video_core/renderer_vulkan/blit_image.h | 10 ++++++++++
.../renderer_vulkan/vk_texture_cache.cpp | 10 ++++++++++
6 files changed, 86 insertions(+)
create mode 100644 src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag
create mode 100644 src/video_core/host_shaders/convert_d24s8_to_r16g16.frag
(limited to 'src')
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
index fd3e41434..87042195a 100644
--- a/src/video_core/host_shaders/CMakeLists.txt
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -12,6 +12,8 @@ set(SHADER_FILES
block_linear_unswizzle_3d.comp
convert_abgr8_to_d24s8.frag
convert_d24s8_to_abgr8.frag
+ convert_d24s8_to_b10g11r11.frag
+ convert_d24s8_to_r16g16.frag
convert_depth_to_float.frag
convert_float_to_depth.frag
full_screen_triangle.vert
diff --git a/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag b/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag
new file mode 100644
index 000000000..c743d3a13
--- /dev/null
+++ b/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag
@@ -0,0 +1,21 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#version 450
+
+layout(binding = 0) uniform sampler2D depth_tex;
+layout(binding = 1) uniform isampler2D stencil_tex;
+
+layout(location = 0) out vec4 color;
+
+void main() {
+ ivec2 coord = ivec2(gl_FragCoord.xy);
+ uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f));
+ uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
+
+ color.b = float(depth >> 22) / (exp2(10) - 1.0);
+ color.g = float((depth >> 11) & 0x00FF) / (exp2(11) - 1.0);
+ color.r = float(depth & 0x00FF) / (exp2(11) - 1.0);
+ color.a = 1.0f;
+}
diff --git a/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag b/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag
new file mode 100644
index 000000000..2a9443d3d
--- /dev/null
+++ b/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag
@@ -0,0 +1,21 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#version 450
+
+layout(binding = 0) uniform sampler2D depth_tex;
+layout(binding = 1) uniform isampler2D stencil_tex;
+
+layout(location = 0) out vec4 color;
+
+void main() {
+ ivec2 coord = ivec2(gl_FragCoord.xy);
+ uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f));
+ uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
+
+ color.r = float(depth >> 16) / (exp2(16) - 1.0);
+ color.g = float((depth >> 16) & 0x00FF) / (exp2(16) - 1.0);
+ color.b = 0.0f;
+ color.a = 1.0f;
+}
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index 01535d0c0..12b28aadd 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -6,6 +6,8 @@
#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_b10g11r11_frag_spv.h"
+#include "video_core/host_shaders/convert_d24s8_to_r16g16_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/full_screen_triangle_vert_spv.h"
@@ -358,6 +360,8 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_,
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_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
+ convert_d24s8_to_b10g11r11_frag(BuildShader(device, CONVERT_D24S8_TO_B10G11R11_FRAG_SPV)),
+ convert_d24s8_to_r16g16_frag(BuildShader(device, CONVERT_D24S8_TO_R16G16_FRAG_SPV)),
linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)),
nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)) {
if (device.IsExtShaderStencilExportSupported()) {
@@ -469,6 +473,24 @@ void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
down_shift);
}
+void BlitImageHelper::ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer,
+ ImageView& src_image_view, u32 up_scale,
+ u32 down_shift) {
+ ConvertPipelineEx(convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer->RenderPass(),
+ convert_d24s8_to_b10g11r11_frag, false);
+ ConvertDepthStencil(*convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer, src_image_view,
+ up_scale, down_shift);
+}
+
+void BlitImageHelper::ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer,
+ ImageView& src_image_view, u32 up_scale,
+ u32 down_shift) {
+ ConvertPipelineEx(convert_d24s8_to_r16g16_pipeline, dst_framebuffer->RenderPass(),
+ convert_d24s8_to_r16g16_frag, false);
+ ConvertDepthStencil(*convert_d24s8_to_r16g16_pipeline, dst_framebuffer, src_image_view,
+ up_scale, down_shift);
+}
+
void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
const ImageView& src_image_view, u32 up_scale, u32 down_shift) {
const VkPipelineLayout layout = *one_texture_pipeline_layout;
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h
index f754a7294..10d24c4b7 100644
--- a/src/video_core/renderer_vulkan/blit_image.h
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -62,6 +62,12 @@ public:
void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
u32 up_scale, u32 down_shift);
+ void ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
+ u32 up_scale, u32 down_shift);
+
+ void ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
+ u32 up_scale, u32 down_shift);
+
private:
void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
const ImageView& src_image_view, u32 up_scale, u32 down_shift);
@@ -97,6 +103,8 @@ private:
vk::ShaderModule convert_float_to_depth_frag;
vk::ShaderModule convert_abgr8_to_d24s8_frag;
vk::ShaderModule convert_d24s8_to_abgr8_frag;
+ vk::ShaderModule convert_d24s8_to_b10g11r11_frag;
+ vk::ShaderModule convert_d24s8_to_r16g16_frag;
vk::Sampler linear_sampler;
vk::Sampler nearest_sampler;
@@ -110,6 +118,8 @@ private:
vk::Pipeline convert_r16_to_d16_pipeline;
vk::Pipeline convert_abgr8_to_d24s8_pipeline;
vk::Pipeline convert_d24s8_to_abgr8_pipeline;
+ vk::Pipeline convert_d24s8_to_b10g11r11_pipeline;
+ vk::Pipeline convert_d24s8_to_r16g16_pipeline;
};
} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 6dfd45f31..fd6064271 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -887,6 +887,16 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view, up_scale, down_shift);
}
break;
+ case PixelFormat::B10G11R11_FLOAT:
+ if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) {
+ return blit_image_helper.ConvertD24S8ToB10G11R11(dst, src_view, up_scale, down_shift);
+ }
+ break;
+ case PixelFormat::R16G16_UNORM:
+ if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) {
+ return blit_image_helper.ConvertD24S8ToR16G16(dst, src_view, up_scale, down_shift);
+ }
+ break;
case PixelFormat::R32_FLOAT:
if (src_view.format == PixelFormat::D32_FLOAT) {
return blit_image_helper.ConvertD32ToR32(dst, src_view, up_scale, down_shift);
--
cgit v1.2.3
From 6f896d1fae3d244f83450a485d15e7cebe79abaa Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow
Date: Fri, 19 Nov 2021 22:23:48 +0100
Subject: TextureCache: Further fixes on resolve algorithm.
---
src/video_core/texture_cache/texture_cache.h | 8 ++++----
src/video_core/texture_cache/util.cpp | 25 +++++++++++++------------
2 files changed, 17 insertions(+), 16 deletions(-)
(limited to 'src')
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 06257f064..4188f93c5 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -1096,13 +1096,13 @@ typename TextureCache::BlitImages TextureCache
::GetBlitImages(
if (GetFormatType(dst_info.format) != GetFormatType(src_info.format)) {
continue;
}
- src_id = FindOrInsertImage(src_info, src_addr);
- RelaxedOptions dst_options{};
+ RelaxedOptions find_options{};
if (src_info.num_samples > 1) {
// it's a resolve, we must enforce the same format.
- dst_options = RelaxedOptions::ForceBrokenViews;
+ find_options = RelaxedOptions::ForceBrokenViews;
}
- dst_id = FindOrInsertImage(dst_info, dst_addr, dst_options);
+ src_id = FindOrInsertImage(src_info, src_addr, find_options);
+ dst_id = FindOrInsertImage(dst_info, dst_addr, find_options);
} while (has_deleted_images);
return BlitImages{
.dst_id = dst_id,
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index 8f9eb387c..e4d82631e 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -1151,19 +1151,25 @@ bool IsSubresource(const ImageInfo& candidate, const ImageBase& image, GPUVAddr
void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst,
const ImageBase* src) {
+ bool is_resolve = false;
+ const auto original_src_format = src_info.format;
+ const auto original_dst_format = dst_info.format;
if (src) {
- src_info.format = src->info.format;
+ if (GetFormatType(src->info.format) != SurfaceType::ColorTexture) {
+ src_info.format = src->info.format;
+ }
+ is_resolve = src->info.num_samples > 1;
src_info.num_samples = src->info.num_samples;
src_info.size = src->info.size;
}
- if (dst) {
+ if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) {
dst_info.format = dst->info.format;
- dst_info.num_samples = dst->info.num_samples;
- dst_info.size = dst->info.size;
}
if (src && GetFormatType(src->info.format) != SurfaceType::ColorTexture) {
if (dst) {
- src_info.format = dst_info.format;
+ if (GetFormatType(dst->info.format) == SurfaceType::ColorTexture) {
+ src_info.format = original_src_format;
+ }
} else {
dst_info.format = src->info.format;
}
@@ -1171,18 +1177,13 @@ void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase*
if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) {
if (src) {
if (GetFormatType(src->info.format) == SurfaceType::ColorTexture) {
- dst_info.format = src->info.format;
+ dst_info.format = original_dst_format;
}
} else {
src_info.format = dst->info.format;
}
}
- if (src_info.num_samples > 1) {
- dst_info.format = src_info.format;
- }
- if (dst_info.num_samples > 1) {
- src_info.format = dst_info.format;
- }
+ ASSERT(!is_resolve || dst_info.format == src_info.format);
}
u32 MapSizeBytes(const ImageBase& image) {
--
cgit v1.2.3
From 1d5e6a51d7f66cf089d541a009c84c373fd5c6ab Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow
Date: Fri, 19 Nov 2021 23:22:44 +0100
Subject: TextureCache: Add B10G11R11 to D24S8 converter.
---
src/video_core/host_shaders/CMakeLists.txt | 1 +
.../host_shaders/convert_b10g11r11_to_d24s8.frag | 19 +++++++
src/video_core/renderer_vulkan/blit_image.cpp | 62 ++++++++++++++++++----
src/video_core/renderer_vulkan/blit_image.h | 12 ++++-
.../renderer_vulkan/vk_texture_cache.cpp | 3 ++
5 files changed, 84 insertions(+), 13 deletions(-)
create mode 100644 src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag
(limited to 'src')
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
index 87042195a..a2e046f12 100644
--- a/src/video_core/host_shaders/CMakeLists.txt
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -11,6 +11,7 @@ set(SHADER_FILES
block_linear_unswizzle_2d.comp
block_linear_unswizzle_3d.comp
convert_abgr8_to_d24s8.frag
+ convert_b10g11r11_to_d24s8.frag
convert_d24s8_to_abgr8.frag
convert_d24s8_to_b10g11r11.frag
convert_d24s8_to_r16g16.frag
diff --git a/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag b/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag
new file mode 100644
index 000000000..b7358c15c
--- /dev/null
+++ b/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag
@@ -0,0 +1,19 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#version 450
+// #extension GL_ARB_shader_stencil_export : require
+
+layout(binding = 0) uniform sampler2D color_texture;
+
+void main() {
+ ivec2 coord = ivec2(gl_FragCoord.xy);
+ vec4 color = texelFetch(color_texture, coord, 0).rgba;
+ uint depth_stencil_unorm = (uint(color.b * (exp2(10) - 1.0f)) << 22)
+ | (uint(color.g * (exp2(11) - 1.0f)) << 11)
+ | (uint(color.r * (exp2(11) - 1.0f)));
+
+ gl_FragDepth = float(depth_stencil_unorm >> 8) / (exp2(24.0) - 1.0f);
+ // gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF);
+}
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index 12b28aadd..e70459de5 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -5,6 +5,7 @@
#include
#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
+#include "video_core/host_shaders/convert_b10g11r11_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_b10g11r11_frag_spv.h"
#include "video_core/host_shaders/convert_d24s8_to_r16g16_frag_spv.h"
@@ -359,6 +360,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_,
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_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
+ convert_b10g11r11_to_d24s8_frag(BuildShader(device, CONVERT_B10G11R11_TO_D24S8_FRAG_SPV)),
convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
convert_d24s8_to_b10g11r11_frag(BuildShader(device, CONVERT_D24S8_TO_B10G11R11_FRAG_SPV)),
convert_d24s8_to_r16g16_frag(BuildShader(device, CONVERT_D24S8_TO_R16G16_FRAG_SPV)),
@@ -459,16 +461,25 @@ void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
const ImageView& src_image_view, u32 up_scale,
u32 down_shift) {
- ConvertPipelineEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
- convert_abgr8_to_d24s8_frag, true);
+ ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
+ convert_abgr8_to_d24s8_frag, true);
Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale,
down_shift);
}
+void BlitImageHelper::ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer,
+ const ImageView& src_image_view, u32 up_scale,
+ u32 down_shift) {
+ ConvertPipelineDepthTargetEx(convert_b10g11r11_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
+ convert_b10g11r11_to_d24s8_frag, true);
+ Convert(*convert_b10g11r11_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale,
+ down_shift);
+}
+
void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
ImageView& src_image_view, u32 up_scale, u32 down_shift) {
- ConvertPipelineEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
- convert_d24s8_to_abgr8_frag, false);
+ ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
+ convert_d24s8_to_abgr8_frag, false);
ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view, up_scale,
down_shift);
}
@@ -476,8 +487,8 @@ void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
void BlitImageHelper::ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer,
ImageView& src_image_view, u32 up_scale,
u32 down_shift) {
- ConvertPipelineEx(convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer->RenderPass(),
- convert_d24s8_to_b10g11r11_frag, false);
+ ConvertPipelineColorTargetEx(convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer->RenderPass(),
+ convert_d24s8_to_b10g11r11_frag, false);
ConvertDepthStencil(*convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer, src_image_view,
up_scale, down_shift);
}
@@ -485,8 +496,8 @@ void BlitImageHelper::ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer
void BlitImageHelper::ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer,
ImageView& src_image_view, u32 up_scale,
u32 down_shift) {
- ConvertPipelineEx(convert_d24s8_to_r16g16_pipeline, dst_framebuffer->RenderPass(),
- convert_d24s8_to_r16g16_frag, false);
+ ConvertPipelineColorTargetEx(convert_d24s8_to_r16g16_pipeline, dst_framebuffer->RenderPass(),
+ convert_d24s8_to_r16g16_frag, false);
ConvertDepthStencil(*convert_d24s8_to_r16g16_pipeline, dst_framebuffer, src_image_view,
up_scale, down_shift);
}
@@ -540,7 +551,7 @@ void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_frameb
void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
ImageView& src_image_view, u32 up_scale, u32 down_shift) {
- const VkPipelineLayout layout = *one_texture_pipeline_layout;
+ const VkPipelineLayout layout = *two_textures_pipeline_layout;
const VkImageView src_depth_view = src_image_view.DepthView();
const VkImageView src_stencil_view = src_image_view.StencilView();
const VkSampler sampler = *nearest_sampler;
@@ -727,8 +738,37 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend
});
}
-void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
- vk::ShaderModule& module, bool single_texture) {
+void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
+ vk::ShaderModule& module, bool single_texture) {
+ if (pipeline) {
+ return;
+ }
+ const std::array stages = MakeStages(*full_screen_vert, *module);
+ pipeline = device.GetLogical().CreateGraphicsPipeline({
+ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .stageCount = static_cast(stages.size()),
+ .pStages = stages.data(),
+ .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+ .pTessellationState = nullptr,
+ .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+ .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+ .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+ .pDepthStencilState = nullptr,
+ .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
+ .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+ .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout,
+ .renderPass = renderpass,
+ .subpass = 0,
+ .basePipelineHandle = VK_NULL_HANDLE,
+ .basePipelineIndex = 0,
+ });
+}
+
+void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
+ vk::ShaderModule& module, bool single_texture) {
if (pipeline) {
return;
}
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h
index 10d24c4b7..607964b5e 100644
--- a/src/video_core/renderer_vulkan/blit_image.h
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -59,6 +59,9 @@ public:
void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
u32 up_scale, u32 down_shift);
+ void ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer,
+ const ImageView& src_image_view, u32 up_scale, u32 down_shift);
+
void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
u32 up_scale, u32 down_shift);
@@ -83,8 +86,11 @@ private:
void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
- void ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
- vk::ShaderModule& module, bool single_texture);
+ void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
+ vk::ShaderModule& module, bool single_texture);
+
+ void ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
+ vk::ShaderModule& module, bool single_texture);
const Device& device;
VKScheduler& scheduler;
@@ -102,6 +108,7 @@ private:
vk::ShaderModule convert_depth_to_float_frag;
vk::ShaderModule convert_float_to_depth_frag;
vk::ShaderModule convert_abgr8_to_d24s8_frag;
+ vk::ShaderModule convert_b10g11r11_to_d24s8_frag;
vk::ShaderModule convert_d24s8_to_abgr8_frag;
vk::ShaderModule convert_d24s8_to_b10g11r11_frag;
vk::ShaderModule convert_d24s8_to_r16g16_frag;
@@ -117,6 +124,7 @@ private:
vk::Pipeline convert_d16_to_r16_pipeline;
vk::Pipeline convert_r16_to_d16_pipeline;
vk::Pipeline convert_abgr8_to_d24s8_pipeline;
+ vk::Pipeline convert_b10g11r11_to_d24s8_pipeline;
vk::Pipeline convert_d24s8_to_abgr8_pipeline;
vk::Pipeline convert_d24s8_to_b10g11r11_pipeline;
vk::Pipeline convert_d24s8_to_r16g16_pipeline;
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index fd6064271..28a659c0e 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -912,6 +912,9 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
src_view.format == PixelFormat::B8G8R8A8_UNORM) {
return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view, up_scale, down_shift);
}
+ if (src_view.format == PixelFormat::B10G11R11_FLOAT) {
+ return blit_image_helper.ConvertB10G11R11ToD24S8(dst, src_view, up_scale, down_shift);
+ }
break;
case PixelFormat::D32_FLOAT:
if (src_view.format == PixelFormat::R32_FLOAT) {
--
cgit v1.2.3
From e02cff2f69f9a90777f87f85f290f83fc04c16ec Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow
Date: Sat, 20 Nov 2021 00:02:12 +0100
Subject: TextureCache: Add R16G16 to D24S8 converter.
---
src/video_core/host_shaders/CMakeLists.txt | 1 +
.../host_shaders/convert_r16g16_to_d24s8.frag | 18 ++++++++++++++++++
src/video_core/renderer_vulkan/blit_image.cpp | 11 +++++++++++
src/video_core/renderer_vulkan/blit_image.h | 5 +++++
src/video_core/renderer_vulkan/vk_texture_cache.cpp | 3 +++
5 files changed, 38 insertions(+)
create mode 100644 src/video_core/host_shaders/convert_r16g16_to_d24s8.frag
(limited to 'src')
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
index a2e046f12..1c91999d7 100644
--- a/src/video_core/host_shaders/CMakeLists.txt
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -17,6 +17,7 @@ set(SHADER_FILES
convert_d24s8_to_r16g16.frag
convert_depth_to_float.frag
convert_float_to_depth.frag
+ convert_r16g16_to_d24s8.frag
full_screen_triangle.vert
fxaa.frag
fxaa.vert
diff --git a/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag
new file mode 100644
index 000000000..7b1b914f6
--- /dev/null
+++ b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag
@@ -0,0 +1,18 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#version 450
+// #extension GL_ARB_shader_stencil_export : require
+
+layout(binding = 0) uniform sampler2D color_texture;
+
+void main() {
+ ivec2 coord = ivec2(gl_FragCoord.xy);
+ vec4 color = texelFetch(color_texture, coord, 0).rgba;
+ uint depth_stencil_unorm = (uint(color.r * (exp2(16) - 1.0f)) << 16)
+ | (uint(color.g * (exp2(16) - 1.0f)) << 16);
+
+ gl_FragDepth = float(depth_stencil_unorm >> 8) / (exp2(24.0) - 1.0f);
+ // gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF);
+}
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index e70459de5..28b631f73 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -11,6 +11,7 @@
#include "video_core/host_shaders/convert_d24s8_to_r16g16_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_r16g16_to_d24s8_frag_spv.h"
#include "video_core/host_shaders/full_screen_triangle_vert_spv.h"
#include "video_core/host_shaders/vulkan_blit_color_float_frag_spv.h"
#include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h"
@@ -361,6 +362,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_,
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_b10g11r11_to_d24s8_frag(BuildShader(device, CONVERT_B10G11R11_TO_D24S8_FRAG_SPV)),
+ convert_r16g16_to_d24s8_frag(BuildShader(device, CONVERT_R16G16_TO_D24S8_FRAG_SPV)),
convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
convert_d24s8_to_b10g11r11_frag(BuildShader(device, CONVERT_D24S8_TO_B10G11R11_FRAG_SPV)),
convert_d24s8_to_r16g16_frag(BuildShader(device, CONVERT_D24S8_TO_R16G16_FRAG_SPV)),
@@ -476,6 +478,15 @@ void BlitImageHelper::ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer
down_shift);
}
+void BlitImageHelper::ConvertR16G16ToD24S8(const Framebuffer* dst_framebuffer,
+ const ImageView& src_image_view, u32 up_scale,
+ u32 down_shift) {
+ ConvertPipelineDepthTargetEx(convert_r16g16_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
+ convert_r16g16_to_d24s8_frag, true);
+ Convert(*convert_r16g16_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale,
+ down_shift);
+}
+
void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
ImageView& src_image_view, u32 up_scale, u32 down_shift) {
ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h
index 607964b5e..cec095341 100644
--- a/src/video_core/renderer_vulkan/blit_image.h
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -62,6 +62,9 @@ public:
void ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer,
const ImageView& src_image_view, u32 up_scale, u32 down_shift);
+ void ConvertR16G16ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
+ u32 up_scale, u32 down_shift);
+
void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
u32 up_scale, u32 down_shift);
@@ -109,6 +112,7 @@ private:
vk::ShaderModule convert_float_to_depth_frag;
vk::ShaderModule convert_abgr8_to_d24s8_frag;
vk::ShaderModule convert_b10g11r11_to_d24s8_frag;
+ vk::ShaderModule convert_r16g16_to_d24s8_frag;
vk::ShaderModule convert_d24s8_to_abgr8_frag;
vk::ShaderModule convert_d24s8_to_b10g11r11_frag;
vk::ShaderModule convert_d24s8_to_r16g16_frag;
@@ -125,6 +129,7 @@ private:
vk::Pipeline convert_r16_to_d16_pipeline;
vk::Pipeline convert_abgr8_to_d24s8_pipeline;
vk::Pipeline convert_b10g11r11_to_d24s8_pipeline;
+ vk::Pipeline convert_r16g16_to_d24s8_pipeline;
vk::Pipeline convert_d24s8_to_abgr8_pipeline;
vk::Pipeline convert_d24s8_to_b10g11r11_pipeline;
vk::Pipeline convert_d24s8_to_r16g16_pipeline;
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 28a659c0e..af1a11059 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -915,6 +915,9 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
if (src_view.format == PixelFormat::B10G11R11_FLOAT) {
return blit_image_helper.ConvertB10G11R11ToD24S8(dst, src_view, up_scale, down_shift);
}
+ if (src_view.format == PixelFormat::R16G16_UNORM) {
+ return blit_image_helper.ConvertR16G16ToD24S8(dst, src_view, up_scale, down_shift);
+ }
break;
case PixelFormat::D32_FLOAT:
if (src_view.format == PixelFormat::R32_FLOAT) {
--
cgit v1.2.3
From 0857f82913d0bcf2de4721233f74cd40ecddcdae Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow
Date: Sat, 20 Nov 2021 06:15:29 +0100
Subject: TextureCache: Implement buffer copies on Vulkan.
---
.../renderer_opengl/gl_texture_cache.cpp | 4 +-
src/video_core/renderer_opengl/gl_texture_cache.h | 7 +-
.../renderer_vulkan/vk_texture_cache.cpp | 174 +++++++++++++++++++++
src/video_core/renderer_vulkan/vk_texture_cache.h | 11 +-
src/video_core/texture_cache/texture_cache.h | 4 +-
src/video_core/texture_cache/texture_cache_base.h | 2 -
6 files changed, 193 insertions(+), 9 deletions(-)
(limited to 'src')
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 6956535e5..e70bbec81 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -526,8 +526,8 @@ void TextureCacheRuntime::CopyImage(Image& dst_image, Image& src_image,
}
}
-void TextureCacheRuntime::ConvertImage(Image& dst, Image& src,
- std::span copies) {
+void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
+ std::span copies) {
LOG_DEBUG(Render_OpenGL, "Converting {} to {}", src.info.format, dst.info.format);
format_conversion_pass.ConvertImage(dst, src, copies);
}
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 578f8d523..ad5157d66 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -84,9 +84,13 @@ public:
u64 GetDeviceLocalMemory() const;
+ bool ShouldReinterpret([[maybe_unused]] Image& dst, [[maybe_unused]] Image& src) {
+ return true;
+ }
+
void CopyImage(Image& dst, Image& src, std::span copies);
- void ConvertImage(Image& dst, Image& src, std::span copies);
+ void ReinterpretImage(Image& dst, Image& src, std::span copies);
void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled) {
UNIMPLEMENTED();
@@ -338,7 +342,6 @@ struct TextureCacheParams {
static constexpr bool FRAMEBUFFER_BLITS = true;
static constexpr bool HAS_EMULATED_COPIES = true;
static constexpr bool HAS_DEVICE_MEMORY_INFO = true;
- static constexpr bool HAS_PIXEL_FORMAT_CONVERSIONS = true;
using Runtime = OpenGL::TextureCacheRuntime;
using Image = OpenGL::Image;
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index af1a11059..02215cfc2 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -308,6 +308,19 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) {
};
}
+[[nodiscard]] VkBufferImageCopy MakeBufferImageCopy(const VideoCommon::ImageCopy& copy, bool is_src,
+ VkImageAspectFlags aspect_mask) noexcept {
+ return VkBufferImageCopy{
+ .bufferOffset = 0,
+ .bufferRowLength = 0,
+ .bufferImageHeight = 0,
+ .imageSubresource = MakeImageSubresourceLayers(
+ is_src ? copy.src_subresource : copy.dst_subresource, aspect_mask),
+ .imageOffset = MakeOffset3D(is_src ? copy.src_offset : copy.dst_offset),
+ .imageExtent = MakeExtent3D(copy.extent),
+ };
+}
+
[[maybe_unused]] [[nodiscard]] std::vector TransformBufferCopies(
std::span copies, size_t buffer_offset) {
std::vector result(copies.size());
@@ -754,6 +767,167 @@ StagingBufferRef TextureCacheRuntime::DownloadStagingBuffer(size_t size) {
return staging_buffer_pool.Request(size, MemoryUsage::Download);
}
+bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) {
+ if (VideoCore::Surface::GetFormatType(dst.info.format) ==
+ VideoCore::Surface::SurfaceType::DepthStencil) {
+ return !device.IsExtShaderStencilExportSupported();
+ }
+ return false;
+}
+
+[[nodiscard]] size_t NextPow2(size_t value) {
+ return static_cast(1ULL << ((8U * sizeof(size_t)) - std::countl_zero(value - 1U)));
+}
+
+VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
+ const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL);
+ if (buffer_commits[level]) {
+ return *buffers[level];
+ }
+ const auto new_size = NextPow2(needed_size);
+ VkBufferUsageFlags flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
+ VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT |
+ VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
+ buffers[level] = device.GetLogical().CreateBuffer({
+ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .size = new_size,
+ .usage = flags,
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
+ .queueFamilyIndexCount = 0,
+ .pQueueFamilyIndices = nullptr,
+ });
+ buffer_commits[level] = std::make_unique(
+ memory_allocator.Commit(buffers[level], MemoryUsage::DeviceLocal));
+ return *buffers[level];
+}
+
+void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
+ std::span copies) {
+ std::vector vk_in_copies(copies.size());
+ std::vector vk_out_copies(copies.size());
+ const VkImageAspectFlags src_aspect_mask = src.AspectMask();
+ const VkImageAspectFlags dst_aspect_mask = dst.AspectMask();
+
+ std::ranges::transform(copies, vk_in_copies.begin(), [src_aspect_mask](const auto& copy) {
+ return MakeBufferImageCopy(copy, true, src_aspect_mask);
+ });
+ std::ranges::transform(copies, vk_out_copies.begin(), [dst_aspect_mask](const auto& copy) {
+ return MakeBufferImageCopy(copy, false, dst_aspect_mask);
+ });
+ const u32 img_bpp = BytesPerBlock(src.info.format);
+ size_t total_size = 0;
+ for (const auto& copy : copies) {
+ total_size += copy.extent.width * copy.extent.height * copy.extent.depth * img_bpp;
+ }
+ const VkBuffer copy_buffer = GetTemporaryBuffer(total_size);
+ const VkImage dst_image = dst.Handle();
+ const VkImage src_image = src.Handle();
+ scheduler.RequestOutsideRenderPassOperationContext();
+ scheduler.Record([dst_image, src_image, copy_buffer, src_aspect_mask, dst_aspect_mask,
+ vk_in_copies, vk_out_copies](vk::CommandBuffer cmdbuf) {
+ RangedBarrierRange dst_range;
+ RangedBarrierRange src_range;
+ for (const VkBufferImageCopy& copy : vk_in_copies) {
+ src_range.AddLayers(copy.imageSubresource);
+ }
+ for (const VkBufferImageCopy& copy : vk_out_copies) {
+ dst_range.AddLayers(copy.imageSubresource);
+ }
+ static constexpr VkMemoryBarrier READ_BARRIER{
+ .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
+ .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
+ };
+ static constexpr VkMemoryBarrier WRITE_BARRIER{
+ .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+ .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
+ };
+ const std::array pre_barriers{
+ VkImageMemoryBarrier{
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
+ .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = src_image,
+ .subresourceRange = src_range.SubresourceRange(src_aspect_mask),
+ },
+ };
+ const std::array middle_in_barrier{
+ VkImageMemoryBarrier{
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = 0,
+ .dstAccessMask = 0,
+ .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ .newLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = src_image,
+ .subresourceRange = src_range.SubresourceRange(src_aspect_mask),
+ },
+ };
+ const std::array middle_out_barrier{
+ VkImageMemoryBarrier{
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+ .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = dst_image,
+ .subresourceRange = dst_range.SubresourceRange(dst_aspect_mask),
+ },
+ };
+ const std::array post_barriers{
+ VkImageMemoryBarrier{
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+ .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
+ VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
+ .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ .newLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = dst_image,
+ .subresourceRange = dst_range.SubresourceRange(dst_aspect_mask),
+ },
+ };
+ cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
+ 0, {}, {}, pre_barriers);
+
+ cmdbuf.CopyImageToBuffer(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, copy_buffer,
+ vk_in_copies);
+ cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ 0, WRITE_BARRIER, nullptr, middle_in_barrier);
+
+ cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
+ 0, READ_BARRIER, {}, middle_out_barrier);
+ cmdbuf.CopyBufferToImage(copy_buffer, dst_image, VK_IMAGE_LAYOUT_GENERAL, vk_out_copies);
+ cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ 0, {}, {}, post_barriers);
+ });
+}
+
void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
const Region2D& dst_region, const Region2D& src_region,
Tegra::Engines::Fermi2D::Filter filter,
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index f5f8f9a74..44e9dcee4 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -61,6 +61,10 @@ public:
void CopyImage(Image& dst, Image& src, std::span copies);
+ bool ShouldReinterpret(Image& dst, Image& src);
+
+ void ReinterpretImage(Image& dst, Image& src, std::span copies);
+
void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled);
bool CanAccelerateImageUpload(Image&) const noexcept {
@@ -82,6 +86,8 @@ public:
return true;
}
+ [[nodiscard]] VkBuffer GetTemporaryBuffer(size_t needed_size);
+
const Device& device;
VKScheduler& scheduler;
MemoryAllocator& memory_allocator;
@@ -90,6 +96,10 @@ public:
ASTCDecoderPass& astc_decoder_pass;
RenderPassCache& render_pass_cache;
const Settings::ResolutionScalingInfo& resolution;
+
+ constexpr static size_t indexing_slots = 8 * sizeof(size_t);
+ std::array buffers{};
+ std::array, indexing_slots> buffer_commits{};
};
class Image : public VideoCommon::ImageBase {
@@ -316,7 +326,6 @@ struct TextureCacheParams {
static constexpr bool FRAMEBUFFER_BLITS = false;
static constexpr bool HAS_EMULATED_COPIES = false;
static constexpr bool HAS_DEVICE_MEMORY_INFO = true;
- static constexpr bool HAS_PIXEL_FORMAT_CONVERSIONS = false;
using Runtime = Vulkan::TextureCacheRuntime;
using Image = Vulkan::Image;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 4188f93c5..44a0d42ba 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -1762,8 +1762,8 @@ void TextureCache::CopyImage(ImageId dst_id, ImageId src_id, std::vector> 8) / (exp2(24.0) - 1.0f);
- // gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF);
+ gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF);
}
diff --git a/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag
index 7b1b914f6..3df70575e 100644
--- a/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag
+++ b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag
@@ -3,7 +3,7 @@
// Refer to the license.txt file included.
#version 450
-// #extension GL_ARB_shader_stencil_export : require
+#extension GL_ARB_shader_stencil_export : require
layout(binding = 0) uniform sampler2D color_texture;
@@ -14,5 +14,5 @@ void main() {
| (uint(color.g * (exp2(16) - 1.0f)) << 16);
gl_FragDepth = float(depth_stencil_unorm >> 8) / (exp2(24.0) - 1.0f);
- // gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF);
+ gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF);
}
--
cgit v1.2.3
From da2fe8190518d3266df7f4a48f9b651eaea84d4b Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow
Date: Sat, 20 Nov 2021 14:46:19 +0100
Subject: TextureCache: Refactor and fix linux compiling.
---
src/common/bit_util.h | 7 +++++++
src/video_core/renderer_opengl/gl_texture_cache.cpp | 6 ++----
src/video_core/renderer_vulkan/vk_texture_cache.cpp | 7 ++-----
3 files changed, 11 insertions(+), 9 deletions(-)
(limited to 'src')
diff --git a/src/common/bit_util.h b/src/common/bit_util.h
index 64520ca4e..eef8c1c5a 100644
--- a/src/common/bit_util.h
+++ b/src/common/bit_util.h
@@ -7,6 +7,7 @@
#include
#include
#include
+#include
#include "common/common_types.h"
@@ -44,4 +45,10 @@ template
return static_cast(log2_f + static_cast((value ^ (1ULL << log2_f)) != 0ULL));
}
+template
+requires std::is_integral_v
+[[nodiscard]] T NextPow2(T value) {
+ return static_cast(1ULL << ((8U * sizeof(T)) - std::countl_zero(value - 1U)));
+}
+
} // namespace Common
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index e70bbec81..ecb215a7d 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -9,6 +9,7 @@
#include
+#include "common/bit_util.h"
#include "common/literals.h"
#include "common/settings.h"
#include "video_core/renderer_opengl/gl_device.h"
@@ -397,9 +398,6 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form
return GL_R32UI;
}
-[[nodiscard]] u32 NextPow2(u32 value) {
- return 1U << (32U - std::countl_zero(value - 1U));
-}
} // Anonymous namespace
ImageBufferMap::~ImageBufferMap() {
@@ -1308,7 +1306,7 @@ void FormatConversionPass::ConvertImage(Image& dst_image, Image& src_image,
const u32 copy_size = region.width * region.height * region.depth * img_bpp;
if (pbo_size < copy_size) {
intermediate_pbo.Create();
- pbo_size = NextPow2(copy_size);
+ pbo_size = Common::NextPow2(copy_size);
glNamedBufferData(intermediate_pbo.handle, pbo_size, nullptr, GL_STREAM_COPY);
}
// Copy from source to PBO
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 02215cfc2..f194110e5 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -8,6 +8,7 @@
#include
#include "common/bit_cast.h"
+#include "common/bit_util.h"
#include "common/settings.h"
#include "video_core/engines/fermi_2d.h"
@@ -775,16 +776,12 @@ bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) {
return false;
}
-[[nodiscard]] size_t NextPow2(size_t value) {
- return static_cast(1ULL << ((8U * sizeof(size_t)) - std::countl_zero(value - 1U)));
-}
-
VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL);
if (buffer_commits[level]) {
return *buffers[level];
}
- const auto new_size = NextPow2(needed_size);
+ const auto new_size = Common::NextPow2(needed_size);
VkBufferUsageFlags flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT |
VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
--
cgit v1.2.3
From fe1f06c856b768e9afcc9ba9ab8ef09b7152678c Mon Sep 17 00:00:00 2001
From: ameerj
Date: Sat, 20 Nov 2021 17:48:22 -0500
Subject: Fix screenshot dimensions when at 1x scale
This was regressed by ART.
Prior to ART, the screenshots were saved at the title's framebuffer resolution. A misunderstanding of the existing logic led to screenshot dimensions becoming dependent on the host render window size.
This changes the behavior to match how it was prior to ART at 1x, with screenshots now always being the title's framebuffer dimensions scaled by the resolution scaling factor.
---
src/core/frontend/framebuffer_layout.cpp | 7 ++++++-
src/core/frontend/framebuffer_layout.h | 11 +----------
src/video_core/video_core.cpp | 6 ------
src/video_core/video_core.h | 2 --
src/yuzu/bootmanager.cpp | 2 +-
5 files changed, 8 insertions(+), 20 deletions(-)
(limited to 'src')
diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp
index 4b58b672a..26a5b12aa 100644
--- a/src/core/frontend/framebuffer_layout.cpp
+++ b/src/core/frontend/framebuffer_layout.cpp
@@ -25,7 +25,12 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
ASSERT(height > 0);
// The drawing code needs at least somewhat valid values for both screens
// so just calculate them both even if the other isn't showing.
- FramebufferLayout res{width, height, false, {}};
+ FramebufferLayout res{
+ .width = width,
+ .height = height,
+ .screen = {},
+ .is_srgb = false,
+ };
const float window_aspect_ratio = static_cast(height) / static_cast(width);
const float emulation_aspect_ratio = EmulationAspectRatio(
diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h
index 2e36c0163..8e341e4e2 100644
--- a/src/core/frontend/framebuffer_layout.h
+++ b/src/core/frontend/framebuffer_layout.h
@@ -35,17 +35,8 @@ enum class AspectRatio {
struct FramebufferLayout {
u32 width{ScreenUndocked::Width};
u32 height{ScreenUndocked::Height};
- bool is_srgb{};
-
Common::Rectangle screen;
-
- /**
- * Returns the ration of pixel size of the screen, compared to the native size of the undocked
- * Switch screen.
- */
- float GetScalingRatio() const {
- return static_cast(screen.GetWidth()) / ScreenUndocked::Width;
- }
+ bool is_srgb{};
};
/**
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index e852c817e..329bf4def 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -55,10 +55,4 @@ std::unique_ptr CreateGPU(Core::Frontend::EmuWindow& emu_window, Cor
}
}
-float GetResolutionScaleFactor(const RendererBase& renderer) {
- return Settings::values.resolution_info.active
- ? Settings::values.resolution_info.up_factor
- : renderer.GetRenderWindow().GetFramebufferLayout().GetScalingRatio();
-}
-
} // namespace VideoCore
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index f86877e86..084df641f 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -25,6 +25,4 @@ class RendererBase;
/// Creates an emulated GPU instance using the given system context.
std::unique_ptr CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system);
-float GetResolutionScaleFactor(const RendererBase& renderer);
-
} // namespace VideoCore
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 976acd176..822ba1a34 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -630,7 +630,7 @@ void GRenderWindow::ReleaseRenderTarget() {
void GRenderWindow::CaptureScreenshot(const QString& screenshot_path) {
auto& renderer = system.Renderer();
- const f32 res_scale = VideoCore::GetResolutionScaleFactor(renderer);
+ const f32 res_scale = Settings::values.resolution_info.up_factor;
const Layout::FramebufferLayout layout{Layout::FrameLayoutFromResolutionScale(res_scale)};
screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32);
--
cgit v1.2.3
From 40cd0bb97b3d6db6eba0e18fae6560c8e1b69794 Mon Sep 17 00:00:00 2001
From: Morph
Date: Sat, 20 Nov 2021 19:39:26 -0500
Subject: service: pm: Rename title id to program id
---
src/core/hle/service/pm/pm.cpp | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index 88fc5b5cc..969300795 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -95,13 +95,13 @@ public:
private:
void GetProcessId(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- const auto title_id = rp.PopRaw();
+ const auto program_id = rp.PopRaw();
- LOG_DEBUG(Service_PM, "called, title_id={:016X}", title_id);
+ LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id);
const auto process =
- SearchProcessList(kernel.GetProcessList(), [title_id](const auto& proc) {
- return proc->GetProgramID() == title_id;
+ SearchProcessList(kernel.GetProcessList(), [program_id](const auto& proc) {
+ return proc->GetProgramID() == program_id;
});
if (!process.has_value()) {
@@ -128,13 +128,13 @@ public:
explicit Info(Core::System& system_, const std::vector& process_list_)
: ServiceFramework{system_, "pm:info"}, process_list{process_list_} {
static const FunctionInfo functions[] = {
- {0, &Info::GetTitleId, "GetTitleId"},
+ {0, &Info::GetProgramId, "GetProgramId"},
};
RegisterHandlers(functions);
}
private:
- void GetTitleId(Kernel::HLERequestContext& ctx) {
+ void GetProgramId(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw();
--
cgit v1.2.3
From 3dc38d185b595ef2cf1d539f7bc68554999cd1db Mon Sep 17 00:00:00 2001
From: Morph
Date: Sat, 20 Nov 2021 19:42:30 -0500
Subject: service: pm: Add all relevant result codes
---
src/core/hle/service/pm/pm.cpp | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index 969300795..b2e97a218 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -13,7 +13,12 @@ namespace Service::PM {
namespace {
-constexpr ResultCode ERROR_PROCESS_NOT_FOUND{ErrorModule::PM, 1};
+constexpr ResultCode ResultProcessNotFound{ErrorModule::PM, 1};
+[[maybe_unused]] constexpr ResultCode ResultAlreadyStarted{ErrorModule::PM, 2};
+[[maybe_unused]] constexpr ResultCode ResultNotTerminated{ErrorModule::PM, 3};
+[[maybe_unused]] constexpr ResultCode ResultDebugHookInUse{ErrorModule::PM, 4};
+[[maybe_unused]] constexpr ResultCode ResultApplicationRunning{ErrorModule::PM, 5};
+[[maybe_unused]] constexpr ResultCode ResultInvalidSize{ErrorModule::PM, 6};
constexpr u64 NO_PROCESS_FOUND_PID{0};
@@ -106,7 +111,7 @@ private:
if (!process.has_value()) {
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_PROCESS_NOT_FOUND);
+ rb.Push(ResultProcessNotFound);
return;
}
@@ -146,7 +151,7 @@ private:
if (!process.has_value()) {
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_PROCESS_NOT_FOUND);
+ rb.Push(ResultProcessNotFound);
return;
}
--
cgit v1.2.3
From 9173f07a51ee355d79c60fed21e7731868db5e6d Mon Sep 17 00:00:00 2001
From: Morph
Date: Sat, 20 Nov 2021 19:52:25 -0500
Subject: service: pm: Implement AtmosphereGetProcessId
- Used by Skyline modding framework
---
src/core/hle/service/pm/pm.cpp | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
(limited to 'src')
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index b2e97a218..277abc17a 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -134,6 +134,9 @@ public:
: ServiceFramework{system_, "pm:info"}, process_list{process_list_} {
static const FunctionInfo functions[] = {
{0, &Info::GetProgramId, "GetProgramId"},
+ {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"},
+ {65001, nullptr, "AtmosphereHasLaunchedProgram"},
+ {65002, nullptr, "AtmosphereGetProcessInfo"},
};
RegisterHandlers(functions);
}
@@ -160,6 +163,27 @@ private:
rb.Push((*process)->GetProgramID());
}
+ void AtmosphereGetProcessId(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto program_id = rp.PopRaw();
+
+ LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id);
+
+ const auto process = SearchProcessList(process_list, [program_id](const auto& proc) {
+ return proc->GetProgramID() == program_id;
+ });
+
+ if (!process.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultProcessNotFound);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push((*process)->GetProcessID());
+ }
+
const std::vector& process_list;
};
--
cgit v1.2.3
From 095bc88428a0c744136969441e4763ddb5c697a6 Mon Sep 17 00:00:00 2001
From: Morph
Date: Sat, 20 Nov 2021 21:18:37 -0500
Subject: vk_blit_image: Consolidate CreatePipelineTargetEx functions
---
src/video_core/renderer_vulkan/blit_image.cpp | 38 +++++++--------------------
src/video_core/renderer_vulkan/blit_image.h | 3 +++
2 files changed, 13 insertions(+), 28 deletions(-)
(limited to 'src')
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index 28b631f73..a63d4d222 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -749,8 +749,9 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend
});
}
-void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
- vk::ShaderModule& module, bool single_texture) {
+void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
+ vk::ShaderModule& module, bool is_target_depth,
+ bool single_texture) {
if (pipeline) {
return;
}
@@ -767,7 +768,7 @@ void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRen
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
- .pDepthStencilState = nullptr,
+ .pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr,
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout,
@@ -778,33 +779,14 @@ void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRen
});
}
+void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
+ vk::ShaderModule& module, bool single_texture) {
+ ConvertPipelineEx(pipeline, renderpass, module, false, single_texture);
+}
+
void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
vk::ShaderModule& module, bool single_texture) {
- if (pipeline) {
- return;
- }
- const std::array stages = MakeStages(*full_screen_vert, *module);
- pipeline = device.GetLogical().CreateGraphicsPipeline({
- .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
- .pNext = nullptr,
- .flags = 0,
- .stageCount = static_cast(stages.size()),
- .pStages = stages.data(),
- .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
- .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
- .pTessellationState = nullptr,
- .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
- .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
- .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
- .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
- .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO,
- .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
- .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout,
- .renderPass = renderpass,
- .subpass = 0,
- .basePipelineHandle = VK_NULL_HANDLE,
- .basePipelineIndex = 0,
- });
+ ConvertPipelineEx(pipeline, renderpass, module, true, single_texture);
}
} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h
index cec095341..3455c75f4 100644
--- a/src/video_core/renderer_vulkan/blit_image.h
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -89,6 +89,9 @@ private:
void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
+ void ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
+ vk::ShaderModule& module, bool is_target_depth, bool single_texture);
+
void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
vk::ShaderModule& module, bool single_texture);
--
cgit v1.2.3
From a41c6dafea6e00d674cfcf3e1b6576fa208acf81 Mon Sep 17 00:00:00 2001
From: Morph
Date: Sat, 20 Nov 2021 21:49:37 -0500
Subject: vk_texture_cache: Mark VkBufferUsageFlags as static constexpr
---
src/video_core/renderer_vulkan/vk_texture_cache.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
(limited to 'src')
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 3964424af..c72f0c897 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -787,9 +787,9 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
return *buffers[level];
}
const auto new_size = Common::NextPow2(needed_size);
- VkBufferUsageFlags flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
- VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT |
- VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
+ static constexpr VkBufferUsageFlags flags =
+ VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
+ VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
buffers[level] = device.GetLogical().CreateBuffer({
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
--
cgit v1.2.3
From 281437c811847adbc38b69ef3638996c666f65c3 Mon Sep 17 00:00:00 2001
From: Morph
Date: Sat, 20 Nov 2021 20:05:02 -0500
Subject: kernel: KPageTable: Rename SetCodeMemoryPermission to
SetProcessMemoryPermission
---
src/core/hle/kernel/k_page_table.cpp | 4 ++--
src/core/hle/kernel/k_page_table.h | 2 +-
src/core/hle/kernel/k_process.cpp | 2 +-
src/core/hle/service/ldr/ldr.cpp | 8 ++++----
4 files changed, 8 insertions(+), 8 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index 526b87241..9bda5c5b2 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -685,8 +685,8 @@ ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list,
return ResultSuccess;
}
-ResultCode KPageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size,
- KMemoryPermission perm) {
+ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
+ KMemoryPermission perm) {
std::lock_guard lock{page_table_lock};
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h
index 770c4841c..b7ec38f06 100644
--- a/src/core/hle/kernel/k_page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -41,7 +41,7 @@ public:
ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state,
KMemoryPermission perm);
ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state);
- ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm);
+ ResultCode SetProcessMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm);
KMemoryInfo QueryInfo(VAddr addr);
ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm);
ResultCode ResetTransferMemory(VAddr addr, std::size_t size);
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 76fd8c285..1aad061e1 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -528,7 +528,7 @@ void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) {
std::lock_guard lock{HLE::g_hle_lock};
const auto ReprotectSegment = [&](const CodeSet::Segment& segment,
KMemoryPermission permission) {
- page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission);
+ page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission);
};
kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(),
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index 32eff3b2a..3782703d2 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -396,12 +396,12 @@ public:
CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start,
nro_header.segment_headers[DATA_INDEX].memory_size);
- CASCADE_CODE(process->PageTable().SetCodeMemoryPermission(
+ CASCADE_CODE(process->PageTable().SetProcessMemoryPermission(
text_start, ro_start - text_start, Kernel::KMemoryPermission::ReadAndExecute));
- CASCADE_CODE(process->PageTable().SetCodeMemoryPermission(ro_start, data_start - ro_start,
- Kernel::KMemoryPermission::Read));
+ CASCADE_CODE(process->PageTable().SetProcessMemoryPermission(
+ ro_start, data_start - ro_start, Kernel::KMemoryPermission::Read));
- return process->PageTable().SetCodeMemoryPermission(
+ return process->PageTable().SetProcessMemoryPermission(
data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::ReadAndWrite);
}
--
cgit v1.2.3
From 2726d705f8dde6d8fcbcfcd55e065a0598e10969 Mon Sep 17 00:00:00 2001
From: Morph
Date: Sat, 20 Nov 2021 20:23:59 -0500
Subject: kernel: svc: Implement SetProcessMemoryPermission
- Used by Skyline modding framework
---
src/core/hle/kernel/svc.cpp | 42 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index f9d99bc51..23dc44780 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1183,6 +1183,18 @@ constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) {
return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare;
}
+constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
+ switch (perm) {
+ case Svc::MemoryPermission::None:
+ case Svc::MemoryPermission::Read:
+ case Svc::MemoryPermission::ReadWrite:
+ case Svc::MemoryPermission::ReadExecute:
+ return true;
+ default:
+ return false;
+ }
+}
+
static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
u64 size, Svc::MemoryPermission map_perm) {
LOG_TRACE(Kernel_SVC,
@@ -1262,6 +1274,34 @@ static ResultCode UnmapSharedMemory32(Core::System& system, Handle shmem_handle,
return UnmapSharedMemory(system, shmem_handle, address, size);
}
+static ResultCode SetProcessMemoryPermission(Core::System& system, Handle process_handle,
+ VAddr address, u64 size, Svc::MemoryPermission perm) {
+ LOG_TRACE(Kernel_SVC,
+ "called, process_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
+ process_handle, address, size, perm);
+
+ // Validate the address/size.
+ R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
+ R_UNLESS(size > 0, ResultInvalidSize);
+ R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
+
+ // Validate the memory permission.
+ R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission);
+
+ // Get the process from its handle.
+ KScopedAutoObject process =
+ system.CurrentProcess()->GetHandleTable().GetObject(process_handle);
+ R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
+
+ // Validate that the address is in range.
+ auto& page_table = process->PageTable();
+ R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
+
+ // Set the memory permission.
+ return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm));
+}
+
static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
VAddr page_info_address, Handle process_handle,
VAddr address) {
@@ -2588,7 +2628,7 @@ static const FunctionDef SVC_Table_64[] = {
{0x70, nullptr, "CreatePort"},
{0x71, nullptr, "ManageNamedPort"},
{0x72, nullptr, "ConnectToPort"},
- {0x73, nullptr, "SetProcessMemoryPermission"},
+ {0x73, SvcWrap64, "SetProcessMemoryPermission"},
{0x74, nullptr, "MapProcessMemory"},
{0x75, nullptr, "UnmapProcessMemory"},
{0x76, SvcWrap64, "QueryProcessMemory"},
--
cgit v1.2.3
From 5cf93c134684f7548572ff27131901f5909725fa Mon Sep 17 00:00:00 2001
From: Morph
Date: Sat, 20 Nov 2021 21:54:46 -0500
Subject: kernel: svc: Move all IsValid functions to an anonymous namespace
---
src/core/hle/kernel/svc.cpp | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 23dc44780..f0cd8471e 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1169,6 +1169,8 @@ static u32 GetCurrentProcessorNumber32(Core::System& system) {
return GetCurrentProcessorNumber(system);
}
+namespace {
+
constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) {
switch (perm) {
case Svc::MemoryPermission::Read:
@@ -1179,7 +1181,7 @@ constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) {
}
}
-constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) {
+[[maybe_unused]] constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) {
return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare;
}
@@ -1195,6 +1197,8 @@ constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
}
}
+} // Anonymous namespace
+
static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
u64 size, Svc::MemoryPermission map_perm) {
LOG_TRACE(Kernel_SVC,
@@ -1499,10 +1503,14 @@ static void ExitProcess32(Core::System& system) {
ExitProcess(system);
}
-static constexpr bool IsValidVirtualCoreId(int32_t core_id) {
+namespace {
+
+constexpr bool IsValidVirtualCoreId(int32_t core_id) {
return (0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES));
}
+} // Anonymous namespace
+
/// Creates a new thread
static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg,
VAddr stack_bottom, u32 priority, s32 core_id) {
@@ -1886,7 +1894,9 @@ static ResultCode ResetSignal32(Core::System& system, Handle handle) {
return ResetSignal(system, handle);
}
-static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
+namespace {
+
+constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
switch (perm) {
case MemoryPermission::None:
case MemoryPermission::Read:
@@ -1897,6 +1907,8 @@ static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
}
}
+} // Anonymous namespace
+
/// Creates a TransferMemory object
static ResultCode CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size,
MemoryPermission map_perm) {
--
cgit v1.2.3
From 779f4ac72d2ea2788c2106c8d2d1ec0e01b77b81 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow
Date: Sun, 21 Nov 2021 05:32:34 +0100
Subject: TextureCache: Eliminate format deduction as full depth conversion has
been supported.
---
src/video_core/texture_cache/texture_cache.h | 6 ++----
src/video_core/texture_cache/util.cpp | 28 +++-------------------------
2 files changed, 5 insertions(+), 29 deletions(-)
(limited to 'src')
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 44a0d42ba..0e4907c53 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -1079,7 +1079,7 @@ ImageId TextureCache::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
template
typename TextureCache::BlitImages TextureCache
::GetBlitImages(
const Tegra::Engines::Fermi2D::Surface& dst, const Tegra::Engines::Fermi2D::Surface& src) {
- static constexpr auto FIND_OPTIONS = RelaxedOptions::Format | RelaxedOptions::Samples;
+ static constexpr auto FIND_OPTIONS = RelaxedOptions::Samples;
const GPUVAddr dst_addr = dst.Address();
const GPUVAddr src_addr = src.Address();
ImageInfo dst_info(dst);
@@ -1093,9 +1093,7 @@ typename TextureCache
::BlitImages TextureCache
::GetBlitImages(
const ImageBase* const dst_image = dst_id ? &slot_images[dst_id] : nullptr;
const ImageBase* const src_image = src_id ? &slot_images[src_id] : nullptr;
DeduceBlitImages(dst_info, src_info, dst_image, src_image);
- if (GetFormatType(dst_info.format) != GetFormatType(src_info.format)) {
- continue;
- }
+ ASSERT(GetFormatType(dst_info.format) == GetFormatType(src_info.format));
RelaxedOptions find_options{};
if (src_info.num_samples > 1) {
// it's a resolve, we must enforce the same format.
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index e4d82631e..777503488 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -1152,36 +1152,14 @@ bool IsSubresource(const ImageInfo& candidate, const ImageBase& image, GPUVAddr
void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst,
const ImageBase* src) {
bool is_resolve = false;
- const auto original_src_format = src_info.format;
- const auto original_dst_format = dst_info.format;
if (src) {
- if (GetFormatType(src->info.format) != SurfaceType::ColorTexture) {
- src_info.format = src->info.format;
- }
is_resolve = src->info.num_samples > 1;
src_info.num_samples = src->info.num_samples;
src_info.size = src->info.size;
}
- if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) {
- dst_info.format = dst->info.format;
- }
- if (src && GetFormatType(src->info.format) != SurfaceType::ColorTexture) {
- if (dst) {
- if (GetFormatType(dst->info.format) == SurfaceType::ColorTexture) {
- src_info.format = original_src_format;
- }
- } else {
- dst_info.format = src->info.format;
- }
- }
- if (dst && GetFormatType(dst->info.format) != SurfaceType::ColorTexture) {
- if (src) {
- if (GetFormatType(src->info.format) == SurfaceType::ColorTexture) {
- dst_info.format = original_dst_format;
- }
- } else {
- src_info.format = dst->info.format;
- }
+ if (dst) {
+ dst_info.num_samples = dst->info.num_samples;
+ dst_info.size = dst->info.size;
}
ASSERT(!is_resolve || dst_info.format == src_info.format);
}
--
cgit v1.2.3
From 8e3371a5c5aa26e1f3d0c1f944b65ee6b65c3f34 Mon Sep 17 00:00:00 2001
From: Kewlan
Date: Sun, 21 Nov 2021 16:57:00 +0100
Subject: configure_general: Allow framerate cap to be used in custom game
configs
---
src/common/settings.cpp | 1 +
src/common/settings.h | 2 +-
src/yuzu/configuration/config.cpp | 4 +-
src/yuzu/configuration/configure_general.cpp | 20 ++++++
src/yuzu/configuration/configure_general.ui | 99 +++++++++++++++++++++-------
5 files changed, 99 insertions(+), 27 deletions(-)
(limited to 'src')
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 3bcaa072f..6964a8273 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -183,6 +183,7 @@ void RestoreGlobalState(bool is_powered_on) {
values.max_anisotropy.SetGlobal(true);
values.use_speed_limit.SetGlobal(true);
values.speed_limit.SetGlobal(true);
+ values.fps_cap.SetGlobal(true);
values.use_disk_shader_cache.SetGlobal(true);
values.gpu_accuracy.SetGlobal(true);
values.use_asynchronous_gpu_emulation.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index 42f8b4a7d..fa4aa8747 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -525,7 +525,7 @@ struct Values {
Setting nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
Setting accelerate_astc{true, "accelerate_astc"};
Setting use_vsync{true, "use_vsync"};
- BasicRangedSetting fps_cap{1000, 1, 1000, "fps_cap"};
+ RangedSetting fps_cap{1000, 1, 1000, "fps_cap"};
BasicSetting disable_fps_limit{false, "disable_fps_limit"};
RangedSetting shader_backend{ShaderBackend::GLASM, ShaderBackend::GLSL,
ShaderBackend::SPIRV, "shader_backend"};
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 8227d06bc..2b670ddfd 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -830,6 +830,7 @@ void Config::ReadRendererValues() {
ReadGlobalSetting(Settings::values.max_anisotropy);
ReadGlobalSetting(Settings::values.use_speed_limit);
ReadGlobalSetting(Settings::values.speed_limit);
+ ReadGlobalSetting(Settings::values.fps_cap);
ReadGlobalSetting(Settings::values.use_disk_shader_cache);
ReadGlobalSetting(Settings::values.gpu_accuracy);
ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation);
@@ -844,7 +845,6 @@ void Config::ReadRendererValues() {
ReadGlobalSetting(Settings::values.bg_blue);
if (global) {
- ReadBasicSetting(Settings::values.fps_cap);
ReadBasicSetting(Settings::values.renderer_debug);
ReadBasicSetting(Settings::values.renderer_shader_feedback);
ReadBasicSetting(Settings::values.enable_nsight_aftermath);
@@ -1382,6 +1382,7 @@ void Config::SaveRendererValues() {
WriteGlobalSetting(Settings::values.max_anisotropy);
WriteGlobalSetting(Settings::values.use_speed_limit);
WriteGlobalSetting(Settings::values.speed_limit);
+ WriteGlobalSetting(Settings::values.fps_cap);
WriteGlobalSetting(Settings::values.use_disk_shader_cache);
WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()),
static_cast(Settings::values.gpu_accuracy.GetValue(global)),
@@ -1405,7 +1406,6 @@ void Config::SaveRendererValues() {
WriteGlobalSetting(Settings::values.bg_blue);
if (global) {
- WriteBasicSetting(Settings::values.fps_cap);
WriteBasicSetting(Settings::values.renderer_debug);
WriteBasicSetting(Settings::values.renderer_shader_feedback);
WriteBasicSetting(Settings::values.enable_nsight_aftermath);
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 7af3ea97e..566879317 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -30,6 +30,9 @@ ConfigureGeneral::ConfigureGeneral(const Core::System& system_, QWidget* parent)
connect(ui->button_reset_defaults, &QPushButton::clicked, this,
&ConfigureGeneral::ResetDefaults);
+
+ ui->fps_cap_label->setVisible(Settings::IsConfiguringGlobal());
+ ui->fps_cap_combobox->setVisible(!Settings::IsConfiguringGlobal());
}
ConfigureGeneral::~ConfigureGeneral() = default;
@@ -57,6 +60,11 @@ void ConfigureGeneral::SetConfiguration() {
} else {
ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue() &&
use_speed_limit != ConfigurationShared::CheckState::Global);
+
+ ui->fps_cap_combobox->setCurrentIndex(Settings::values.fps_cap.UsingGlobal() ? 0 : 1);
+ ui->fps_cap->setEnabled(!Settings::values.fps_cap.UsingGlobal());
+ ConfigurationShared::SetHighlight(ui->fps_cap_layout,
+ !Settings::values.fps_cap.UsingGlobal());
}
}
@@ -106,6 +114,13 @@ void ConfigureGeneral::ApplyConfiguration() {
Qt::Checked);
Settings::values.speed_limit.SetValue(ui->speed_limit->value());
}
+
+ if (ui->fps_cap_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ Settings::values.fps_cap.SetGlobal(true);
+ } else {
+ Settings::values.fps_cap.SetGlobal(false);
+ Settings::values.fps_cap.SetValue(ui->fps_cap->value());
+ }
}
}
@@ -148,4 +163,9 @@ void ConfigureGeneral::SetupPerGameUI() {
ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() &&
(use_speed_limit != ConfigurationShared::CheckState::Global));
});
+
+ connect(ui->fps_cap_combobox, qOverload(&QComboBox::activated), this, [this](int index) {
+ ui->fps_cap->setEnabled(index == 1);
+ ConfigurationShared::SetHighlight(ui->fps_cap_layout, index == 1);
+ });
}
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index f9f0e3ebf..112dc72b3 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -6,8 +6,8 @@
0
0
- 329
- 407
+ 744
+ 568
@@ -28,34 +28,85 @@
-
-
-
-
-
-
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
-
+
+
+ Use global framerate cap
+
+
+ 0
+
+
-
- Framerate Cap
+ Use global framerate cap
-
- Requires the use of the FPS Limiter Toggle hotkey to take effect.
+
+ -
+
+ Set framerate cap:
+
-
- -
-
-
- x
-
-
- 1
-
-
- 1000
-
-
- 500
-
+
+ -
+
+
+ Requires the use of the FPS Limiter Toggle hotkey to take effect.
+
+
+ Framerate Cap
+
-
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ x
+
+
+ 1
+
+
+ 1000
+
+
+ 500
+
+
+
+
-
--
cgit v1.2.3
From b96caf200d047b81554c3839c7a6a7c35b251944 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow
Date: Sun, 21 Nov 2021 20:52:39 +0100
Subject: HostShaders: Fix D24S8 convertion shaders.
---
.../host_shaders/convert_abgr8_to_d24s8.frag | 7 ++++---
.../host_shaders/convert_b10g11r11_to_d24s8.frag | 18 +++++++++++++-----
.../host_shaders/convert_d24s8_to_abgr8.frag | 10 ++++++----
.../host_shaders/convert_d24s8_to_b10g11r11.frag | 19 +++++++++++++++----
.../host_shaders/convert_d24s8_to_r16g16.frag | 7 ++++---
.../host_shaders/convert_r16g16_to_d24s8.frag | 9 +++++----
6 files changed, 47 insertions(+), 23 deletions(-)
(limited to 'src')
diff --git a/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag b/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag
index 4e4ab6a26..d51397a0c 100644
--- a/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag
+++ b/src/video_core/host_shaders/convert_abgr8_to_d24s8.frag
@@ -10,8 +10,9 @@ layout(binding = 0) uniform sampler2D color_texture;
void main() {
ivec2 coord = ivec2(gl_FragCoord.xy);
uvec4 color = uvec4(texelFetch(color_texture, coord, 0).rgba * (exp2(8) - 1.0f));
- uint depth_unorm = (color.r << 16) | (color.g << 8) | color.b;
+ uvec4 bytes = color << uvec4(24, 16, 8, 0);
+ uint depth_stencil_unorm = bytes.x | bytes.y | bytes.z | bytes.w;
- gl_FragDepth = float(depth_unorm) / (exp2(24.0) - 1.0f);
- gl_FragStencilRefARB = int(color.a);
+ gl_FragDepth = float(depth_stencil_unorm & 0x00FFFFFFu) / (exp2(24.0) - 1.0f);
+ gl_FragStencilRefARB = int(depth_stencil_unorm >> 24);
}
diff --git a/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag b/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag
index 2999a84cf..11bdd861d 100644
--- a/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag
+++ b/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag
@@ -7,13 +7,21 @@
layout(binding = 0) uniform sampler2D color_texture;
+uint conv_from_float(float value_f, uint mantissa_bits) {
+ uint value = floatBitsToInt(value_f);
+ uint exp = (value >> 23) & 0x1Fu;
+ uint mantissa_shift = 32u - mantissa_bits;
+ uint mantissa = (value << 9u) >> mantissa_shift;
+ return (exp << mantissa_bits) | mantissa;
+}
+
void main() {
ivec2 coord = ivec2(gl_FragCoord.xy);
vec4 color = texelFetch(color_texture, coord, 0).rgba;
- uint depth_stencil_unorm = (uint(color.b * (exp2(10) - 1.0f)) << 22)
- | (uint(color.g * (exp2(11) - 1.0f)) << 11)
- | (uint(color.r * (exp2(11) - 1.0f)));
+ uint depth_stencil_unorm = (conv_from_float(color.r, 6u) << 21)
+ | (conv_from_float(color.g, 6u) << 10)
+ | conv_from_float(color.b, 5u);
- gl_FragDepth = float(depth_stencil_unorm >> 8) / (exp2(24.0) - 1.0f);
- gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF);
+ gl_FragDepth = float(depth_stencil_unorm & 0x00FFFFFFu) / (exp2(24.0) - 1.0f);
+ gl_FragStencilRefARB = int(depth_stencil_unorm >> 24);
}
diff --git a/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag b/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag
index ff3bf8209..47f9c1abc 100644
--- a/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag
+++ b/src/video_core/host_shaders/convert_d24s8_to_abgr8.frag
@@ -14,8 +14,10 @@ void main() {
uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f));
uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
- color.r = float(depth >> 16) / (exp2(8) - 1.0);
- color.g = float((depth >> 8) & 0x00FF) / (exp2(8) - 1.0);
- color.b = float(depth & 0x00FF) / (exp2(8) - 1.0);
- color.a = float(stencil) / (exp2(8) - 1.0);
+ highp uint depth_val =
+ uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0));
+ lowp uint stencil_val = textureLod(stencil_tex, coord, 0).r;
+ highp uvec4 components =
+ uvec4(stencil_val, (uvec3(depth_val) >> uvec3(24u, 16u, 8u)) & 0x000000FFu);
+ color = vec4(components) / (exp2(8.0) - 1.0);
}
diff --git a/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag b/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag
index c743d3a13..c2d935fcd 100644
--- a/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag
+++ b/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag
@@ -9,13 +9,24 @@ layout(binding = 1) uniform isampler2D stencil_tex;
layout(location = 0) out vec4 color;
+float conv_to_float(uint value, uint mantissa_bits) {
+ uint exp = (value >> mantissa_bits) & 0x1Fu;
+ uint mantissa_shift = 32u - mantissa_bits;
+ uint mantissa = (value << mantissa_shift) >> mantissa_shift;
+ return uintBitsToFloat((exp << 23) | (mantissa << (23 - mantissa_bits)));
+}
+
void main() {
ivec2 coord = ivec2(gl_FragCoord.xy);
- uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f));
+ uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0f));
uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
+ uint depth_stencil = (stencil << 24) | (depth >> 8);
+ uint red_int = (depth_stencil >> 21) & 0x07FF;
+ uint green_int = (depth_stencil >> 10) & 0x07FF;
+ uint blue_int = depth_stencil & 0x03FF;
- color.b = float(depth >> 22) / (exp2(10) - 1.0);
- color.g = float((depth >> 11) & 0x00FF) / (exp2(11) - 1.0);
- color.r = float(depth & 0x00FF) / (exp2(11) - 1.0);
+ color.r = conv_to_float(red_int, 6u);
+ color.g = conv_to_float(green_int, 6u);
+ color.b = conv_to_float(blue_int, 5u);
color.a = 1.0f;
}
diff --git a/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag b/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag
index 2a9443d3d..c48a7ac66 100644
--- a/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag
+++ b/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag
@@ -11,11 +11,12 @@ layout(location = 0) out vec4 color;
void main() {
ivec2 coord = ivec2(gl_FragCoord.xy);
- uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f));
+ uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0f));
uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
+ uint depth_stencil = (stencil << 24) | (depth >> 8);
- color.r = float(depth >> 16) / (exp2(16) - 1.0);
- color.g = float((depth >> 16) & 0x00FF) / (exp2(16) - 1.0);
+ color.r = float(depth_stencil & 0x0000FFFFu) / (exp2(16) - 1.0);
+ color.g = float(depth_stencil >> 16) / (exp2(16) - 1.0);
color.b = 0.0f;
color.a = 1.0f;
}
diff --git a/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag
index 3df70575e..beb2d1284 100644
--- a/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag
+++ b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag
@@ -10,9 +10,10 @@ layout(binding = 0) uniform sampler2D color_texture;
void main() {
ivec2 coord = ivec2(gl_FragCoord.xy);
vec4 color = texelFetch(color_texture, coord, 0).rgba;
- uint depth_stencil_unorm = (uint(color.r * (exp2(16) - 1.0f)) << 16)
- | (uint(color.g * (exp2(16) - 1.0f)) << 16);
+ uvec2 bytes = uvec2(color.rg * (exp2(16) - 1.0f)) << uvec2(0, 16);
+ uint depth_stencil_unorm =
+ uint(color.r * (exp2(16) - 1.0f)) | (uint(color.g * (exp2(16) - 1.0f)) << 16);
- gl_FragDepth = float(depth_stencil_unorm >> 8) / (exp2(24.0) - 1.0f);
- gl_FragStencilRefARB = int(depth_stencil_unorm & 0x00FF);
+ gl_FragDepth = float(depth_stencil_unorm & 0x00FFFFFFu) / (exp2(24.0) - 1.0f);
+ gl_FragStencilRefARB = int(depth_stencil_unorm >> 24);
}
--
cgit v1.2.3
From d7f4434bd534d53e8aea293e39629bf8ca8ee123 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow
Date: Sun, 21 Nov 2021 21:09:49 +0100
Subject: VulkanTexturECache: Use reinterpret on D32_S8 formats.
---
src/video_core/renderer_vulkan/vk_texture_cache.cpp | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 3964424af..e1ba1bdaf 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -775,8 +775,13 @@ StagingBufferRef TextureCacheRuntime::DownloadStagingBuffer(size_t size) {
bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) {
if (VideoCore::Surface::GetFormatType(dst.info.format) ==
- VideoCore::Surface::SurfaceType::DepthStencil) {
- return !device.IsExtShaderStencilExportSupported();
+ VideoCore::Surface::SurfaceType::DepthStencil &&
+ !device.IsExtShaderStencilExportSupported()) {
+ return true;
+ }
+ if (dst.info.format == PixelFormat::D32_FLOAT_S8_UINT ||
+ src.info.format == PixelFormat::D32_FLOAT_S8_UINT) {
+ return true;
}
return false;
}
--
cgit v1.2.3
From 853284943901560081f6ff992b6c04b7c33f0d21 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow
Date: Mon, 22 Nov 2021 00:00:01 +0100
Subject: TextureCache: Simplify blitting of D24S8 formats and fix bugs.
---
src/video_core/host_shaders/CMakeLists.txt | 4 -
.../host_shaders/convert_b10g11r11_to_d24s8.frag | 27 ------
.../host_shaders/convert_d24s8_to_b10g11r11.frag | 32 -------
.../host_shaders/convert_d24s8_to_r16g16.frag | 22 -----
.../host_shaders/convert_r16g16_to_d24s8.frag | 19 -----
src/video_core/renderer_vulkan/blit_image.cpp | 98 +++++++++++-----------
src/video_core/renderer_vulkan/blit_image.h | 25 +-----
.../renderer_vulkan/vk_texture_cache.cpp | 30 ++-----
src/video_core/renderer_vulkan/vk_texture_cache.h | 3 +
src/video_core/texture_cache/texture_cache.h | 8 +-
10 files changed, 73 insertions(+), 195 deletions(-)
delete mode 100644 src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag
delete mode 100644 src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag
delete mode 100644 src/video_core/host_shaders/convert_d24s8_to_r16g16.frag
delete mode 100644 src/video_core/host_shaders/convert_r16g16_to_d24s8.frag
(limited to 'src')
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
index 1c91999d7..fd3e41434 100644
--- a/src/video_core/host_shaders/CMakeLists.txt
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -11,13 +11,9 @@ set(SHADER_FILES
block_linear_unswizzle_2d.comp
block_linear_unswizzle_3d.comp
convert_abgr8_to_d24s8.frag
- convert_b10g11r11_to_d24s8.frag
convert_d24s8_to_abgr8.frag
- convert_d24s8_to_b10g11r11.frag
- convert_d24s8_to_r16g16.frag
convert_depth_to_float.frag
convert_float_to_depth.frag
- convert_r16g16_to_d24s8.frag
full_screen_triangle.vert
fxaa.frag
fxaa.vert
diff --git a/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag b/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag
deleted file mode 100644
index 11bdd861d..000000000
--- a/src/video_core/host_shaders/convert_b10g11r11_to_d24s8.frag
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2021 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#version 450
-#extension GL_ARB_shader_stencil_export : require
-
-layout(binding = 0) uniform sampler2D color_texture;
-
-uint conv_from_float(float value_f, uint mantissa_bits) {
- uint value = floatBitsToInt(value_f);
- uint exp = (value >> 23) & 0x1Fu;
- uint mantissa_shift = 32u - mantissa_bits;
- uint mantissa = (value << 9u) >> mantissa_shift;
- return (exp << mantissa_bits) | mantissa;
-}
-
-void main() {
- ivec2 coord = ivec2(gl_FragCoord.xy);
- vec4 color = texelFetch(color_texture, coord, 0).rgba;
- uint depth_stencil_unorm = (conv_from_float(color.r, 6u) << 21)
- | (conv_from_float(color.g, 6u) << 10)
- | conv_from_float(color.b, 5u);
-
- gl_FragDepth = float(depth_stencil_unorm & 0x00FFFFFFu) / (exp2(24.0) - 1.0f);
- gl_FragStencilRefARB = int(depth_stencil_unorm >> 24);
-}
diff --git a/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag b/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag
deleted file mode 100644
index c2d935fcd..000000000
--- a/src/video_core/host_shaders/convert_d24s8_to_b10g11r11.frag
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2021 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#version 450
-
-layout(binding = 0) uniform sampler2D depth_tex;
-layout(binding = 1) uniform isampler2D stencil_tex;
-
-layout(location = 0) out vec4 color;
-
-float conv_to_float(uint value, uint mantissa_bits) {
- uint exp = (value >> mantissa_bits) & 0x1Fu;
- uint mantissa_shift = 32u - mantissa_bits;
- uint mantissa = (value << mantissa_shift) >> mantissa_shift;
- return uintBitsToFloat((exp << 23) | (mantissa << (23 - mantissa_bits)));
-}
-
-void main() {
- ivec2 coord = ivec2(gl_FragCoord.xy);
- uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0f));
- uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
- uint depth_stencil = (stencil << 24) | (depth >> 8);
- uint red_int = (depth_stencil >> 21) & 0x07FF;
- uint green_int = (depth_stencil >> 10) & 0x07FF;
- uint blue_int = depth_stencil & 0x03FF;
-
- color.r = conv_to_float(red_int, 6u);
- color.g = conv_to_float(green_int, 6u);
- color.b = conv_to_float(blue_int, 5u);
- color.a = 1.0f;
-}
diff --git a/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag b/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag
deleted file mode 100644
index c48a7ac66..000000000
--- a/src/video_core/host_shaders/convert_d24s8_to_r16g16.frag
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2021 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#version 450
-
-layout(binding = 0) uniform sampler2D depth_tex;
-layout(binding = 1) uniform isampler2D stencil_tex;
-
-layout(location = 0) out vec4 color;
-
-void main() {
- ivec2 coord = ivec2(gl_FragCoord.xy);
- uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0f));
- uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
- uint depth_stencil = (stencil << 24) | (depth >> 8);
-
- color.r = float(depth_stencil & 0x0000FFFFu) / (exp2(16) - 1.0);
- color.g = float(depth_stencil >> 16) / (exp2(16) - 1.0);
- color.b = 0.0f;
- color.a = 1.0f;
-}
diff --git a/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag b/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag
deleted file mode 100644
index beb2d1284..000000000
--- a/src/video_core/host_shaders/convert_r16g16_to_d24s8.frag
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2021 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#version 450
-#extension GL_ARB_shader_stencil_export : require
-
-layout(binding = 0) uniform sampler2D color_texture;
-
-void main() {
- ivec2 coord = ivec2(gl_FragCoord.xy);
- vec4 color = texelFetch(color_texture, coord, 0).rgba;
- uvec2 bytes = uvec2(color.rg * (exp2(16) - 1.0f)) << uvec2(0, 16);
- uint depth_stencil_unorm =
- uint(color.r * (exp2(16) - 1.0f)) | (uint(color.g * (exp2(16) - 1.0f)) << 16);
-
- gl_FragDepth = float(depth_stencil_unorm & 0x00FFFFFFu) / (exp2(24.0) - 1.0f);
- gl_FragStencilRefARB = int(depth_stencil_unorm >> 24);
-}
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index 28b631f73..2e69e270f 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -5,13 +5,9 @@
#include
#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
-#include "video_core/host_shaders/convert_b10g11r11_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_b10g11r11_frag_spv.h"
-#include "video_core/host_shaders/convert_d24s8_to_r16g16_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_r16g16_to_d24s8_frag_spv.h"
#include "video_core/host_shaders/full_screen_triangle_vert_spv.h"
#include "video_core/host_shaders/vulkan_blit_color_float_frag_spv.h"
#include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h"
@@ -361,11 +357,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_,
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_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
- convert_b10g11r11_to_d24s8_frag(BuildShader(device, CONVERT_B10G11R11_TO_D24S8_FRAG_SPV)),
- convert_r16g16_to_d24s8_frag(BuildShader(device, CONVERT_R16G16_TO_D24S8_FRAG_SPV)),
convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
- convert_d24s8_to_b10g11r11_frag(BuildShader(device, CONVERT_D24S8_TO_B10G11R11_FRAG_SPV)),
- convert_d24s8_to_r16g16_frag(BuildShader(device, CONVERT_D24S8_TO_R16G16_FRAG_SPV)),
linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)),
nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)) {
if (device.IsExtShaderStencilExportSupported()) {
@@ -461,30 +453,11 @@ void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
}
void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
- const ImageView& src_image_view, u32 up_scale,
- u32 down_shift) {
+ ImageView& src_image_view, u32 up_scale, u32 down_shift) {
ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
convert_abgr8_to_d24s8_frag, true);
- Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale,
- down_shift);
-}
-
-void BlitImageHelper::ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer,
- const ImageView& src_image_view, u32 up_scale,
- u32 down_shift) {
- ConvertPipelineDepthTargetEx(convert_b10g11r11_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
- convert_b10g11r11_to_d24s8_frag, true);
- Convert(*convert_b10g11r11_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale,
- down_shift);
-}
-
-void BlitImageHelper::ConvertR16G16ToD24S8(const Framebuffer* dst_framebuffer,
- const ImageView& src_image_view, u32 up_scale,
- u32 down_shift) {
- ConvertPipelineDepthTargetEx(convert_r16g16_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
- convert_r16g16_to_d24s8_frag, true);
- Convert(*convert_r16g16_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale,
- down_shift);
+ ConvertColor(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale,
+ down_shift);
}
void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
@@ -495,24 +468,6 @@ void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
down_shift);
}
-void BlitImageHelper::ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer,
- ImageView& src_image_view, u32 up_scale,
- u32 down_shift) {
- ConvertPipelineColorTargetEx(convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer->RenderPass(),
- convert_d24s8_to_b10g11r11_frag, false);
- ConvertDepthStencil(*convert_d24s8_to_b10g11r11_pipeline, dst_framebuffer, src_image_view,
- up_scale, down_shift);
-}
-
-void BlitImageHelper::ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer,
- ImageView& src_image_view, u32 up_scale,
- u32 down_shift) {
- ConvertPipelineColorTargetEx(convert_d24s8_to_r16g16_pipeline, dst_framebuffer->RenderPass(),
- convert_d24s8_to_r16g16_frag, false);
- ConvertDepthStencil(*convert_d24s8_to_r16g16_pipeline, dst_framebuffer, src_image_view,
- up_scale, down_shift);
-}
-
void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
const ImageView& src_image_view, u32 up_scale, u32 down_shift) {
const VkPipelineLayout layout = *one_texture_pipeline_layout;
@@ -560,6 +515,53 @@ void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_frameb
scheduler.InvalidateState();
}
+void BlitImageHelper::ConvertColor(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
+ ImageView& src_image_view, u32 up_scale, u32 down_shift) {
+ const VkPipelineLayout layout = *one_texture_pipeline_layout;
+ const VkImageView src_view = src_image_view.ColorView();
+ const VkSampler sampler = *nearest_sampler;
+ const VkExtent2D extent{
+ .width = std::max((src_image_view.size.width * up_scale) >> down_shift, 1U),
+ .height = std::max((src_image_view.size.height * up_scale) >> down_shift, 1U),
+ };
+ scheduler.RequestRenderpass(dst_framebuffer);
+ scheduler.Record([pipeline, layout, sampler, src_view, extent, up_scale, down_shift,
+ this](vk::CommandBuffer cmdbuf) {
+ const VkOffset2D offset{
+ .x = 0,
+ .y = 0,
+ };
+ const VkViewport viewport{
+ .x = 0.0f,
+ .y = 0.0f,
+ .width = static_cast(extent.width),
+ .height = static_cast(extent.height),
+ .minDepth = 0.0f,
+ .maxDepth = 0.0f,
+ };
+ const VkRect2D scissor{
+ .offset = offset,
+ .extent = extent,
+ };
+ const PushConstants push_constants{
+ .tex_scale = {viewport.width, viewport.height},
+ .tex_offset = {0.0f, 0.0f},
+ };
+ const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
+ UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view);
+
+ // TODO: Barriers
+ cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
+ cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
+ nullptr);
+ cmdbuf.SetViewport(0, viewport);
+ cmdbuf.SetScissor(0, scissor);
+ cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
+ cmdbuf.Draw(3, 1, 0, 0);
+ });
+ scheduler.InvalidateState();
+}
+
void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
ImageView& src_image_view, u32 up_scale, u32 down_shift) {
const VkPipelineLayout layout = *two_textures_pipeline_layout;
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h
index cec095341..0b73cf444 100644
--- a/src/video_core/renderer_vulkan/blit_image.h
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -56,28 +56,19 @@ public:
void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
u32 up_scale, u32 down_shift);
- void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
+ void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
u32 up_scale, u32 down_shift);
- void ConvertB10G11R11ToD24S8(const Framebuffer* dst_framebuffer,
- const ImageView& src_image_view, u32 up_scale, u32 down_shift);
-
- void ConvertR16G16ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
- u32 up_scale, u32 down_shift);
-
void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
u32 up_scale, u32 down_shift);
- void ConvertD24S8ToB10G11R11(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
- u32 up_scale, u32 down_shift);
-
- void ConvertD24S8ToR16G16(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
- u32 up_scale, u32 down_shift);
-
private:
void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
const ImageView& src_image_view, u32 up_scale, u32 down_shift);
+ void ConvertColor(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
+ ImageView& src_image_view, u32 up_scale, u32 down_shift);
+
void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
ImageView& src_image_view, u32 up_scale, u32 down_shift);
@@ -111,11 +102,7 @@ private:
vk::ShaderModule convert_depth_to_float_frag;
vk::ShaderModule convert_float_to_depth_frag;
vk::ShaderModule convert_abgr8_to_d24s8_frag;
- vk::ShaderModule convert_b10g11r11_to_d24s8_frag;
- vk::ShaderModule convert_r16g16_to_d24s8_frag;
vk::ShaderModule convert_d24s8_to_abgr8_frag;
- vk::ShaderModule convert_d24s8_to_b10g11r11_frag;
- vk::ShaderModule convert_d24s8_to_r16g16_frag;
vk::Sampler linear_sampler;
vk::Sampler nearest_sampler;
@@ -128,11 +115,7 @@ private:
vk::Pipeline convert_d16_to_r16_pipeline;
vk::Pipeline convert_r16_to_d16_pipeline;
vk::Pipeline convert_abgr8_to_d24s8_pipeline;
- vk::Pipeline convert_b10g11r11_to_d24s8_pipeline;
- vk::Pipeline convert_r16g16_to_d24s8_pipeline;
vk::Pipeline convert_d24s8_to_abgr8_pipeline;
- vk::Pipeline convert_d24s8_to_b10g11r11_pipeline;
- vk::Pipeline convert_d24s8_to_r16g16_pipeline;
};
} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index e1ba1bdaf..ef8ae6cb6 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -1063,21 +1063,10 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
}
break;
case PixelFormat::A8B8G8R8_UNORM:
- case PixelFormat::B8G8R8A8_UNORM:
if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) {
return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view, up_scale, down_shift);
}
break;
- case PixelFormat::B10G11R11_FLOAT:
- if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) {
- return blit_image_helper.ConvertD24S8ToB10G11R11(dst, src_view, up_scale, down_shift);
- }
- break;
- case PixelFormat::R16G16_UNORM:
- if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) {
- return blit_image_helper.ConvertD24S8ToR16G16(dst, src_view, up_scale, down_shift);
- }
- break;
case PixelFormat::R32_FLOAT:
if (src_view.format == PixelFormat::D32_FLOAT) {
return blit_image_helper.ConvertD32ToR32(dst, src_view, up_scale, down_shift);
@@ -1089,16 +1078,7 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
}
break;
case PixelFormat::S8_UINT_D24_UNORM:
- if (src_view.format == PixelFormat::A8B8G8R8_UNORM ||
- src_view.format == PixelFormat::B8G8R8A8_UNORM) {
- return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view, up_scale, down_shift);
- }
- if (src_view.format == PixelFormat::B10G11R11_FLOAT) {
- return blit_image_helper.ConvertB10G11R11ToD24S8(dst, src_view, up_scale, down_shift);
- }
- if (src_view.format == PixelFormat::R16G16_UNORM) {
- return blit_image_helper.ConvertR16G16ToD24S8(dst, src_view, up_scale, down_shift);
- }
+ return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view, up_scale, down_shift);
break;
case PixelFormat::D32_FLOAT:
if (src_view.format == PixelFormat::R32_FLOAT) {
@@ -1595,6 +1575,14 @@ VkImageView ImageView::StencilView() {
return *stencil_view;
}
+VkImageView ImageView::ColorView() {
+ if (color_view) {
+ return *color_view;
+ }
+ color_view = MakeView(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT);
+ return *color_view;
+}
+
VkImageView ImageView::StorageView(Shader::TextureType texture_type,
Shader::ImageFormat image_format) {
if (image_format == Shader::ImageFormat::Typeless) {
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 44e9dcee4..753e3e8a1 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -184,6 +184,8 @@ public:
[[nodiscard]] VkImageView StencilView();
+ [[nodiscard]] VkImageView ColorView();
+
[[nodiscard]] VkImageView StorageView(Shader::TextureType texture_type,
Shader::ImageFormat image_format);
@@ -224,6 +226,7 @@ private:
std::unique_ptr storage_views;
vk::ImageView depth_view;
vk::ImageView stencil_view;
+ vk::ImageView color_view;
VkImage image_handle = VK_NULL_HANDLE;
VkImageView render_target = VK_NULL_HANDLE;
VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 0e4907c53..9548abec8 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -1781,7 +1781,13 @@ void TextureCache
::CopyImage(ImageId dst_id, ImageId src_id, std::vector> uvec3(24u, 16u, 8u)) & 0x000000FFu);
- color = vec4(components) / (exp2(8.0) - 1.0);
+ color.abgr = vec4(components) / (exp2(8.0) - 1.0);
}
--
cgit v1.2.3
From f90d9808378092e208b431f467c54feb6952e91d Mon Sep 17 00:00:00 2001
From: Adam Heinermann
Date: Sun, 21 Nov 2021 17:28:47 -0800
Subject: Added TAS controls to the menu under Tools
---
src/yuzu/bootmanager.cpp | 9 +++++
src/yuzu/bootmanager.h | 6 +++
src/yuzu/main.cpp | 100 +++++++++++++++++++++++++++++++++--------------
src/yuzu/main.h | 5 +++
src/yuzu/main.ui | 90 +++++++++++++++++++++++++++++-------------
5 files changed, 153 insertions(+), 57 deletions(-)
(limited to 'src')
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 822ba1a34..105f36d33 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -303,6 +303,7 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram,
Qt::QueuedConnection);
connect(this, &GRenderWindow::ExitSignal, parent, &GMainWindow::OnExit, Qt::QueuedConnection);
+ connect(this, &GRenderWindow::TasPlaybackStateChanged, parent, &GMainWindow::OnTasStateChanged);
}
void GRenderWindow::ExecuteProgram(std::size_t program_index) {
@@ -319,10 +320,18 @@ GRenderWindow::~GRenderWindow() {
void GRenderWindow::OnFrameDisplayed() {
input_subsystem->GetTas()->UpdateThread();
+ TasInput::TasState new_tas_state = std::get<0>(input_subsystem->GetTas()->GetStatus());
+
if (!first_frame) {
+ last_tas_state = new_tas_state;
first_frame = true;
emit FirstFrameDisplayed();
}
+
+ if (new_tas_state != last_tas_state) {
+ last_tas_state = new_tas_state;
+ emit TasPlaybackStateChanged();
+ }
}
bool GRenderWindow::IsShown() const {
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index 40fd4a9d6..061e3605f 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -41,6 +41,10 @@ enum class LoadCallbackStage;
class RendererBase;
} // namespace VideoCore
+namespace TasInput {
+enum class TasState;
+}
+
class EmuThread final : public QThread {
Q_OBJECT
@@ -203,6 +207,7 @@ signals:
void ExecuteProgramSignal(std::size_t program_index);
void ExitSignal();
void MouseActivity();
+ void TasPlaybackStateChanged();
private:
void TouchBeginEvent(const QTouchEvent* event);
@@ -236,6 +241,7 @@ private:
QWidget* child_widget = nullptr;
bool first_frame = false;
+ TasInput::TasState last_tas_state;
std::array touch_ids{};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index c4c76b094..73278f29f 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -965,6 +965,9 @@ void GMainWindow::InitializeHotkeys() {
const QString toggle_status_bar = QStringLiteral("Toggle Status Bar");
const QString fullscreen = QStringLiteral("Fullscreen");
const QString capture_screenshot = QStringLiteral("Capture Screenshot");
+ const QString tas_start_stop = QStringLiteral("TAS Start/Stop");
+ const QString tas_record = QStringLiteral("TAS Record");
+ const QString tas_reset = QStringLiteral("TAS Reset");
ui->action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file));
ui->action_Load_File->setShortcutContext(
@@ -1005,6 +1008,18 @@ void GMainWindow::InitializeHotkeys() {
ui->action_Fullscreen->setShortcutContext(
hotkey_registry.GetShortcutContext(main_window, fullscreen));
+ ui->action_TAS_Start->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_start_stop));
+ ui->action_TAS_Start->setShortcutContext(
+ hotkey_registry.GetShortcutContext(main_window, tas_start_stop));
+
+ ui->action_TAS_Record->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_record));
+ ui->action_TAS_Record->setShortcutContext(
+ hotkey_registry.GetShortcutContext(main_window, tas_record));
+
+ ui->action_TAS_Reset->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_reset));
+ ui->action_TAS_Reset->setShortcutContext(
+ hotkey_registry.GetShortcutContext(main_window, tas_reset));
+
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this),
&QShortcut::activated, this, &GMainWindow::OnMenuLoadFile);
connect(
@@ -1095,28 +1110,6 @@ void GMainWindow::InitializeHotkeys() {
render_window->setAttribute(Qt::WA_Hover, true);
}
});
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Start/Stop"), this),
- &QShortcut::activated, this, [&] {
- if (!emulation_running) {
- return;
- }
- input_subsystem->GetTas()->StartStop();
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Reset"), this),
- &QShortcut::activated, this, [&] { input_subsystem->GetTas()->Reset(); });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Record"), this),
- &QShortcut::activated, this, [&] {
- if (!emulation_running) {
- return;
- }
- bool is_recording = input_subsystem->GetTas()->Record();
- if (!is_recording) {
- const auto res = QMessageBox::question(this, tr("TAS Recording"),
- tr("Overwrite file of player 1?"),
- QMessageBox::Yes | QMessageBox::No);
- input_subsystem->GetTas()->SaveRecording(res == QMessageBox::Yes);
- }
- });
}
void GMainWindow::SetDefaultUIGeometry() {
@@ -1236,11 +1229,11 @@ void GMainWindow::ConnectMenuEvents() {
connect(ui->action_Restart, &QAction::triggered, this,
[this] { BootGame(QString(game_path)); });
connect(ui->action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure);
- connect(ui->action_Configure_Tas, &QAction::triggered, this, &GMainWindow::OnConfigureTas);
connect(ui->action_Configure_Current_Game, &QAction::triggered, this,
&GMainWindow::OnConfigurePerGame);
// View
+ connect(ui->action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen);
connect(ui->action_Single_Window_Mode, &QAction::triggered, this,
&GMainWindow::ToggleWindowMode);
connect(ui->action_Display_Dock_Widget_Headers, &QAction::triggered, this,
@@ -1258,17 +1251,20 @@ void GMainWindow::ConnectMenuEvents() {
ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_900);
ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_1080);
- // Fullscreen
- connect(ui->action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen);
-
- // Movie
+ // Tools
+ connect(ui->action_Rederive, &QAction::triggered, this,
+ std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning));
connect(ui->action_Capture_Screenshot, &QAction::triggered, this,
&GMainWindow::OnCaptureScreenshot);
+ // TAS
+ connect(ui->action_TAS_Start, &QAction::triggered, this, &GMainWindow::OnTasStartStop);
+ connect(ui->action_TAS_Record, &QAction::triggered, this, &GMainWindow::OnTasRecord);
+ connect(ui->action_TAS_Reset, &QAction::triggered, this, &GMainWindow::OnTasReset);
+ connect(ui->action_Configure_Tas, &QAction::triggered, this, &GMainWindow::OnConfigureTas);
+
// Help
connect(ui->action_Open_yuzu_Folder, &QAction::triggered, this, &GMainWindow::OnOpenYuzuFolder);
- connect(ui->action_Rederive, &QAction::triggered, this,
- std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning));
connect(ui->action_About, &QAction::triggered, this, &GMainWindow::OnAbout);
}
@@ -1582,6 +1578,7 @@ void GMainWindow::ShutdownGame() {
game_list->SetFilterFocus();
tas_label->clear();
input_subsystem->GetTas()->Stop();
+ OnTasStateChanged();
render_window->removeEventFilter(render_window);
render_window->setAttribute(Qt::WA_Hover, false);
@@ -2509,6 +2506,7 @@ void GMainWindow::OnStartGame() {
ui->action_Restart->setEnabled(true);
ui->action_Configure_Current_Game->setEnabled(true);
ui->action_Report_Compatibility->setEnabled(true);
+ OnTasStateChanged();
discord_rpc->Update();
ui->action_Load_Amiibo->setEnabled(true);
@@ -2821,6 +2819,33 @@ void GMainWindow::OnConfigureTas() {
}
}
+void GMainWindow::OnTasStartStop() {
+ if (!emulation_running) {
+ return;
+ }
+ input_subsystem->GetTas()->StartStop();
+ OnTasStateChanged();
+}
+
+void GMainWindow::OnTasRecord() {
+ if (!emulation_running) {
+ return;
+ }
+ bool is_recording = input_subsystem->GetTas()->Record();
+ if (!is_recording) {
+ const auto res =
+ QMessageBox::question(this, tr("TAS Recording"), tr("Overwrite file of player 1?"),
+ QMessageBox::Yes | QMessageBox::No);
+ input_subsystem->GetTas()->SaveRecording(res == QMessageBox::Yes);
+ }
+ OnTasStateChanged();
+}
+
+void GMainWindow::OnTasReset() {
+ input_subsystem->GetTas()->Reset();
+}
+
+
void GMainWindow::OnConfigurePerGame() {
const u64 title_id = system->GetCurrentProcessProgramID();
OpenPerGameConfiguration(title_id, game_path.toStdString());
@@ -3014,6 +3039,23 @@ QString GMainWindow::GetTasStateDescription() const {
}
}
+void GMainWindow::OnTasStateChanged() {
+ bool is_running = false;
+ bool is_recording = false;
+ if (emulation_running) {
+ TasInput::TasState tas_status = std::get<0>(input_subsystem->GetTas()->GetStatus());
+ is_running = tas_status == TasInput::TasState::Running;
+ is_recording = tas_status == TasInput::TasState::Recording;
+ }
+
+ ui->action_TAS_Start->setText(is_running ? tr("&Stop Running") : tr("&Start"));
+ ui->action_TAS_Record->setText(is_recording ? tr("Stop R&ecording") : tr("R&ecord"));
+
+ ui->action_TAS_Start->setEnabled(emulation_running);
+ ui->action_TAS_Record->setEnabled(emulation_running);
+ ui->action_TAS_Reset->setEnabled(emulation_running);
+}
+
void GMainWindow::UpdateStatusBar() {
if (emu_thread == nullptr) {
status_bar_update_timer.stop();
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 24633ff2d..556cbbaf7 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -177,6 +177,7 @@ public slots:
void WebBrowserOpenWebPage(const std::string& main_url, const std::string& additional_args,
bool is_local);
void OnAppFocusStateChanged(Qt::ApplicationState state);
+ void OnTasStateChanged();
private:
void RegisterMetaTypes();
@@ -268,6 +269,9 @@ private slots:
void OnMenuRecentFile();
void OnConfigure();
void OnConfigureTas();
+ void OnTasStartStop();
+ void OnTasRecord();
+ void OnTasReset();
void OnConfigurePerGame();
void OnLoadAmiibo();
void OnOpenYuzuFolder();
@@ -313,6 +317,7 @@ private:
void OpenURL(const QUrl& url);
void LoadTranslation();
void OpenPerGameConfiguration(u64 title_id, const std::string& file_name);
+
QString GetTasStateDescription() const;
std::unique_ptr ui;
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index a62e39a06..c58aa2866 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -79,39 +79,39 @@
&View
+
-
- Reset Window Size to &720p
-
-
- Reset Window Size to 720p
-
+
+ Reset Window Size to &720p
+
+
+ Reset Window Size to 720p
+
-
- Reset Window Size to &900p
-
-
- Reset Window Size to 900p
-
+
+ Reset Window Size to &900p
+
+
+ Reset Window Size to 900p
+
-
- Reset Window Size to &1080p
-
-
- Reset Window Size to 1080p
-
-
-
+
+ Reset Window Size to 1080p
+
+
@@ -125,10 +125,20 @@
&Tools
+
-
+
--
cgit v1.2.3
From b7a938e817be3801f2c2c9f1b693ea7d008373b1 Mon Sep 17 00:00:00 2001
From: Adam Heinermann
Date: Sun, 21 Nov 2021 18:02:08 -0800
Subject: Apply clang format
---
src/yuzu/main.cpp | 1 -
1 file changed, 1 deletion(-)
(limited to 'src')
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 73278f29f..42ee310cc 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -2845,7 +2845,6 @@ void GMainWindow::OnTasReset() {
input_subsystem->GetTas()->Reset();
}
-
void GMainWindow::OnConfigurePerGame() {
const u64 title_id = system->GetCurrentProcessProgramID();
OpenPerGameConfiguration(title_id, game_path.toStdString());
--
cgit v1.2.3
From 097de2febcf97da38c55235073eff834c529acac Mon Sep 17 00:00:00 2001
From: Adam Heinermann
Date: Sun, 21 Nov 2021 18:07:37 -0800
Subject: const fixes
---
src/yuzu/bootmanager.cpp | 2 +-
src/yuzu/main.cpp | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
(limited to 'src')
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 105f36d33..fd0a130a3 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -320,7 +320,7 @@ GRenderWindow::~GRenderWindow() {
void GRenderWindow::OnFrameDisplayed() {
input_subsystem->GetTas()->UpdateThread();
- TasInput::TasState new_tas_state = std::get<0>(input_subsystem->GetTas()->GetStatus());
+ const TasInput::TasState new_tas_state = std::get<0>(input_subsystem->GetTas()->GetStatus());
if (!first_frame) {
last_tas_state = new_tas_state;
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 42ee310cc..5058c3e4e 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -2831,7 +2831,7 @@ void GMainWindow::OnTasRecord() {
if (!emulation_running) {
return;
}
- bool is_recording = input_subsystem->GetTas()->Record();
+ const bool is_recording = input_subsystem->GetTas()->Record();
if (!is_recording) {
const auto res =
QMessageBox::question(this, tr("TAS Recording"), tr("Overwrite file of player 1?"),
@@ -3042,7 +3042,7 @@ void GMainWindow::OnTasStateChanged() {
bool is_running = false;
bool is_recording = false;
if (emulation_running) {
- TasInput::TasState tas_status = std::get<0>(input_subsystem->GetTas()->GetStatus());
+ const TasInput::TasState tas_status = std::get<0>(input_subsystem->GetTas()->GetStatus());
is_running = tas_status == TasInput::TasState::Running;
is_recording = tas_status == TasInput::TasState::Recording;
}
--
cgit v1.2.3
From 84eb3e7d02d386bc90eb4a6c6b6e33eea33a42e2 Mon Sep 17 00:00:00 2001
From: jam1garner
Date: Sun, 21 Nov 2021 21:10:14 -0500
Subject: arm: dynarmic: Implement icache op handling for 'ic ivau' instruction
---
src/core/arm/dynarmic/arm_dynarmic_64.cpp | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
(limited to 'src')
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 4e73cc03a..587fffb34 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -86,6 +86,24 @@ public:
num_instructions, MemoryReadCode(pc));
}
+ void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op,
+ VAddr value) override {
+ constexpr u64 ICACHE_LINE_SIZE = 64;
+ u64 cache_line_start;
+
+ switch (op) {
+ case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU:
+ cache_line_start = value & ~(ICACHE_LINE_SIZE - 1);
+ parent.InvalidateCacheRange(cache_line_start, ICACHE_LINE_SIZE);
+ return;
+
+ case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU:
+ case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable:
+ default:
+ LOG_DEBUG(Core_ARM, "Unprocesseed instruction cache operation");
+ }
+ }
+
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
switch (exception) {
case Dynarmic::A64::Exception::WaitForInterrupt:
--
cgit v1.2.3
From c8a67a725de6481c891d5bfe1b83fcb6340c88a3 Mon Sep 17 00:00:00 2001
From: jam1garner
Date: Sun, 21 Nov 2021 21:18:56 -0500
Subject: arm: dynarmic: Implement icache op handling for 'ic iallu'
instruction
---
src/core/arm/dynarmic/arm_dynarmic_64.cpp | 3 +++
1 file changed, 3 insertions(+)
(limited to 'src')
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 587fffb34..8fe83413c 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -98,6 +98,9 @@ public:
return;
case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU:
+ parent.ClearInstructionCache();
+ return;
+
case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable:
default:
LOG_DEBUG(Core_ARM, "Unprocesseed instruction cache operation");
--
cgit v1.2.3
From 4d9c9e567ef6c44967b639471613a0328dcbf833 Mon Sep 17 00:00:00 2001
From: jam1garner
Date: Sun, 21 Nov 2021 21:24:07 -0500
Subject: arm: dynarmic: Cleanup icache op handling
---
src/core/arm/dynarmic/arm_dynarmic_64.cpp | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
(limited to 'src')
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 8fe83413c..56836bd05 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -88,22 +88,21 @@ public:
void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op,
VAddr value) override {
- constexpr u64 ICACHE_LINE_SIZE = 64;
- u64 cache_line_start;
-
switch (op) {
- case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU:
- cache_line_start = value & ~(ICACHE_LINE_SIZE - 1);
- parent.InvalidateCacheRange(cache_line_start, ICACHE_LINE_SIZE);
- return;
+ case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: {
+ static constexpr u64 ICACHE_LINE_SIZE = 64;
+ const u64 cache_line_start = value & ~(ICACHE_LINE_SIZE - 1);
+ parent.InvalidateCacheRange(cache_line_start, ICACHE_LINE_SIZE);
+ break;
+ }
case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU:
parent.ClearInstructionCache();
- return;
-
+ break;
case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable:
default:
- LOG_DEBUG(Core_ARM, "Unprocesseed instruction cache operation");
+ LOG_DEBUG(Core_ARM, "Unprocesseed instruction cache operation: {}", op);
+ break;
}
}
--
cgit v1.2.3
From 08674aee87e385e5f2a3b8e1b9aa85a61e23a490 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow
Date: Mon, 22 Nov 2021 06:07:21 +0100
Subject: Texture Cache: Fix issue with blitting 3D textures.
---
src/video_core/texture_cache/util.cpp | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index 777503488..9b1613008 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -1155,11 +1155,13 @@ void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase*
if (src) {
is_resolve = src->info.num_samples > 1;
src_info.num_samples = src->info.num_samples;
- src_info.size = src->info.size;
+ src_info.size.width = src->info.size.width;
+ src_info.size.height = src->info.size.height;
}
if (dst) {
dst_info.num_samples = dst->info.num_samples;
- dst_info.size = dst->info.size;
+ dst_info.size.width = dst->info.size.width;
+ dst_info.size.height = dst->info.size.height;
}
ASSERT(!is_resolve || dst_info.format == src_info.format);
}
--
cgit v1.2.3
From 72aa418b0b412855683633d2799da1eb190ab6d5 Mon Sep 17 00:00:00 2001
From: liushuyu
Date: Wed, 24 Nov 2021 17:23:57 -0700
Subject: video_core/codecs: fix multiple decoding issues on Linux ...
* when someone installed Intel video drivers on an AMD system, the
decoder will select the Intel VA-API decoding driver and yuzu will
crash due to incorrect driver selection; the fix will check if the
currently about-to-use driver is loaded in the kernel
* when using NVIDIA driver on Linux with a ffmpeg that does not have
CUDA capability enabled, the decoder will crash; the fix simply
making the decoder prefers the VDPAU driver over CUDA on Linux
---
src/video_core/command_classes/codecs/codec.cpp | 49 ++++++++++++++++++++++++-
1 file changed, 47 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp
index 916277811..403ce30fe 100644
--- a/src/video_core/command_classes/codecs/codec.cpp
+++ b/src/video_core/command_classes/codecs/codec.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include
#include
#include
#include "common/assert.h"
@@ -59,6 +60,36 @@ Codec::~Codec() {
av_buffer_unref(&av_gpu_decoder);
}
+#ifdef LIBVA_FOUND
+// List all the currently loaded Linux modules
+static std::vector ListLinuxKernelModules() {
+ std::vector modules{};
+ auto module_listing = fopen("/proc/modules", "rt");
+ char* buffer = nullptr;
+ size_t buf_len = 0;
+ if (!module_listing) {
+ LOG_WARNING(Service_NVDRV, "Could not open /proc/modules to collect available modules");
+ return modules;
+ }
+ while (getline(&buffer, &buf_len, module_listing) != -1) {
+ // format for the module listing file (sysfs)
+ //
+ auto line = std::string(buffer);
+ // we are only interested in module names
+ auto name_pos = line.find_first_of(" ");
+ if (name_pos == std::string::npos) {
+ continue;
+ }
+ modules.push_back(line.erase(name_pos + 1));
+ }
+ if (buffer) {
+ free(buffer);
+ }
+ fclose(module_listing);
+ return modules;
+}
+#endif
+
bool Codec::CreateGpuAvDevice() {
#if defined(LIBVA_FOUND)
static constexpr std::array VAAPI_DRIVERS = {
@@ -67,8 +98,21 @@ bool Codec::CreateGpuAvDevice() {
"amdgpu",
};
AVDictionary* hwdevice_options = nullptr;
+ auto loaded_modules = ListLinuxKernelModules();
av_dict_set(&hwdevice_options, "connection_type", "drm", 0);
for (const auto& driver : VAAPI_DRIVERS) {
+ bool found = false;
+ // first check if the target driver is loaded in the kernel
+ for (const auto& module : loaded_modules) {
+ if (module == driver) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ LOG_DEBUG(Service_NVDRV, "Kernel driver {} is not loaded, trying the next one", driver);
+ continue;
+ }
av_dict_set(&hwdevice_options, "kernel_driver", driver, 0);
const int hwdevice_error = av_hwdevice_ctx_create(&av_gpu_decoder, AV_HWDEVICE_TYPE_VAAPI,
nullptr, hwdevice_options, 0);
@@ -85,11 +129,12 @@ bool Codec::CreateGpuAvDevice() {
#endif
static constexpr auto HW_CONFIG_METHOD = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX;
static constexpr std::array GPU_DECODER_TYPES{
+#ifdef linux
+ AV_HWDEVICE_TYPE_VDPAU,
+#endif
AV_HWDEVICE_TYPE_CUDA,
#ifdef _WIN32
AV_HWDEVICE_TYPE_D3D11VA,
-#else
- AV_HWDEVICE_TYPE_VDPAU,
#endif
};
for (const auto& type : GPU_DECODER_TYPES) {
--
cgit v1.2.3
From 60928cf8cd0d6f46826d588926969913d7fc6740 Mon Sep 17 00:00:00 2001
From: liushuyu
Date: Wed, 24 Nov 2021 18:00:55 -0700
Subject: video_core/codec: address comments
---
src/video_core/command_classes/codecs/codec.cpp | 28 ++++++++++---------------
1 file changed, 11 insertions(+), 17 deletions(-)
(limited to 'src')
diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp
index 403ce30fe..02d309170 100644
--- a/src/video_core/command_classes/codecs/codec.cpp
+++ b/src/video_core/command_classes/codecs/codec.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include
#include
#include
#include
@@ -63,15 +64,16 @@ Codec::~Codec() {
#ifdef LIBVA_FOUND
// List all the currently loaded Linux modules
static std::vector ListLinuxKernelModules() {
+ using FILEPtr = std::unique_ptr;
+ auto module_listing = FILEPtr{fopen("/proc/modules", "rt"), std::fclose};
std::vector modules{};
- auto module_listing = fopen("/proc/modules", "rt");
- char* buffer = nullptr;
- size_t buf_len = 0;
if (!module_listing) {
LOG_WARNING(Service_NVDRV, "Could not open /proc/modules to collect available modules");
return modules;
}
- while (getline(&buffer, &buf_len, module_listing) != -1) {
+ char* buffer = nullptr;
+ size_t buf_len = 0;
+ while (getline(&buffer, &buf_len, module_listing.get()) != -1) {
// format for the module listing file (sysfs)
//
auto line = std::string(buffer);
@@ -80,12 +82,9 @@ static std::vector ListLinuxKernelModules() {
if (name_pos == std::string::npos) {
continue;
}
- modules.push_back(line.erase(name_pos + 1));
+ modules.push_back(line.erase(name_pos));
}
- if (buffer) {
- free(buffer);
- }
- fclose(module_listing);
+ free(buffer);
return modules;
}
#endif
@@ -98,17 +97,12 @@ bool Codec::CreateGpuAvDevice() {
"amdgpu",
};
AVDictionary* hwdevice_options = nullptr;
- auto loaded_modules = ListLinuxKernelModules();
+ const auto loaded_modules = ListLinuxKernelModules();
av_dict_set(&hwdevice_options, "connection_type", "drm", 0);
for (const auto& driver : VAAPI_DRIVERS) {
- bool found = false;
// first check if the target driver is loaded in the kernel
- for (const auto& module : loaded_modules) {
- if (module == driver) {
- found = true;
- break;
- }
- }
+ bool found = std::any_of(loaded_modules.begin(), loaded_modules.end(),
+ [&driver](const auto& module) { return module == driver; });
if (!found) {
LOG_DEBUG(Service_NVDRV, "Kernel driver {} is not loaded, trying the next one", driver);
continue;
--
cgit v1.2.3
From f078d3d212a4b272012695762f3ce62eaa0db2ab Mon Sep 17 00:00:00 2001
From: Adam Heinermann
Date: Wed, 24 Nov 2021 18:27:25 -0800
Subject: Refactor menu states and shortcuts in GMainWindow. (#7419)
Refactor menu states and shortcuts in GMainWindow.
- Removed "Start", since it was always disabled unless it was "Continue"
which has now been moved to "Pause".
- Allow hotkeys to be used while in fullscreen.
- Removed the load amiibo hotkey.---
src/yuzu/main.cpp | 397 +++++++++++++++++++++++-------------------------------
src/yuzu/main.h | 6 +
src/yuzu/main.ui | 9 --
3 files changed, 175 insertions(+), 237 deletions(-)
(limited to 'src')
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 5058c3e4e..88e84e8f7 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -952,164 +952,80 @@ void GMainWindow::InitializeRecentFileMenuActions() {
UpdateRecentFiles();
}
+void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name) {
+ static const QString main_window = QStringLiteral("Main Window");
+ action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name));
+ action->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, action_name));
+
+ this->addAction(action);
+}
+
void GMainWindow::InitializeHotkeys() {
hotkey_registry.LoadHotkeys();
- const QString main_window = QStringLiteral("Main Window");
- const QString load_file = QStringLiteral("Load File");
- const QString load_amiibo = QStringLiteral("Load Amiibo");
- const QString exit_yuzu = QStringLiteral("Exit yuzu");
- const QString restart_emulation = QStringLiteral("Restart Emulation");
- const QString stop_emulation = QStringLiteral("Stop Emulation");
- const QString toggle_filter_bar = QStringLiteral("Toggle Filter Bar");
- const QString toggle_status_bar = QStringLiteral("Toggle Status Bar");
- const QString fullscreen = QStringLiteral("Fullscreen");
- const QString capture_screenshot = QStringLiteral("Capture Screenshot");
- const QString tas_start_stop = QStringLiteral("TAS Start/Stop");
- const QString tas_record = QStringLiteral("TAS Record");
- const QString tas_reset = QStringLiteral("TAS Reset");
-
- ui->action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file));
- ui->action_Load_File->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, load_file));
-
- ui->action_Load_Amiibo->setShortcut(hotkey_registry.GetKeySequence(main_window, load_amiibo));
- ui->action_Load_Amiibo->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, load_amiibo));
-
- ui->action_Exit->setShortcut(hotkey_registry.GetKeySequence(main_window, exit_yuzu));
- ui->action_Exit->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, exit_yuzu));
-
- ui->action_Restart->setShortcut(hotkey_registry.GetKeySequence(main_window, restart_emulation));
- ui->action_Restart->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, restart_emulation));
-
- ui->action_Stop->setShortcut(hotkey_registry.GetKeySequence(main_window, stop_emulation));
- ui->action_Stop->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, stop_emulation));
-
- ui->action_Show_Filter_Bar->setShortcut(
- hotkey_registry.GetKeySequence(main_window, toggle_filter_bar));
- ui->action_Show_Filter_Bar->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, toggle_filter_bar));
-
- ui->action_Show_Status_Bar->setShortcut(
- hotkey_registry.GetKeySequence(main_window, toggle_status_bar));
- ui->action_Show_Status_Bar->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, toggle_status_bar));
-
- ui->action_Capture_Screenshot->setShortcut(
- hotkey_registry.GetKeySequence(main_window, capture_screenshot));
- ui->action_Capture_Screenshot->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, capture_screenshot));
-
- ui->action_Fullscreen->setShortcut(
- hotkey_registry.GetHotkey(main_window, fullscreen, this)->key());
- ui->action_Fullscreen->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, fullscreen));
-
- ui->action_TAS_Start->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_start_stop));
- ui->action_TAS_Start->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, tas_start_stop));
-
- ui->action_TAS_Record->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_record));
- ui->action_TAS_Record->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, tas_record));
-
- ui->action_TAS_Reset->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_reset));
- ui->action_TAS_Reset->setShortcutContext(
- hotkey_registry.GetShortcutContext(main_window, tas_reset));
-
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this),
- &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile);
- connect(
- hotkey_registry.GetHotkey(main_window, QStringLiteral("Continue/Pause Emulation"), this),
- &QShortcut::activated, this, [&] {
- if (emulation_running) {
- if (emu_thread->IsRunning()) {
- OnPauseGame();
- } else {
- OnStartGame();
- }
- }
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Restart Emulation"), this),
- &QShortcut::activated, this, [this] {
- if (!system->IsPoweredOn()) {
- return;
- }
- BootGame(game_path);
- });
- connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window),
- &QShortcut::activated, ui->action_Fullscreen, &QAction::trigger);
- connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window),
- &QShortcut::activatedAmbiguously, ui->action_Fullscreen, &QAction::trigger);
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Exit Fullscreen"), this),
- &QShortcut::activated, this, [&] {
- if (emulation_running && ui->action_Fullscreen->isChecked()) {
- ui->action_Fullscreen->setChecked(false);
- ToggleFullscreen();
- }
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Speed Limit"), this),
- &QShortcut::activated, this, [&] {
- Settings::values.use_speed_limit.SetValue(
- !Settings::values.use_speed_limit.GetValue());
- UpdateStatusBar();
- });
+ LinkActionShortcut(ui->action_Load_File, QStringLiteral("Load File"));
+ LinkActionShortcut(ui->action_Load_Amiibo, QStringLiteral("Load Amiibo"));
+ LinkActionShortcut(ui->action_Exit, QStringLiteral("Exit yuzu"));
+ LinkActionShortcut(ui->action_Restart, QStringLiteral("Restart Emulation"));
+ LinkActionShortcut(ui->action_Pause, QStringLiteral("Continue/Pause Emulation"));
+ LinkActionShortcut(ui->action_Stop, QStringLiteral("Stop Emulation"));
+ LinkActionShortcut(ui->action_Show_Filter_Bar, QStringLiteral("Toggle Filter Bar"));
+ LinkActionShortcut(ui->action_Show_Status_Bar, QStringLiteral("Toggle Status Bar"));
+ LinkActionShortcut(ui->action_Fullscreen, QStringLiteral("Fullscreen"));
+ LinkActionShortcut(ui->action_Capture_Screenshot, QStringLiteral("Capture Screenshot"));
+ LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop"));
+ LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record"));
+ LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset"));
+
+ static const QString main_window = QStringLiteral("Main Window");
+ const auto connect_shortcut = [&](const QString& action_name, const Fn& function) {
+ const QShortcut* hotkey = hotkey_registry.GetHotkey(main_window, action_name, this);
+ connect(hotkey, &QShortcut::activated, this, function);
+ };
+
+ connect_shortcut(QStringLiteral("Exit Fullscreen"), [&] {
+ if (emulation_running && ui->action_Fullscreen->isChecked()) {
+ ui->action_Fullscreen->setChecked(false);
+ ToggleFullscreen();
+ }
+ });
+ connect_shortcut(QStringLiteral("Toggle Speed Limit"), [&] {
+ Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue());
+ UpdateStatusBar();
+ });
constexpr u16 SPEED_LIMIT_STEP = 5;
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Increase Speed Limit"), this),
- &QShortcut::activated, this, [&] {
- if (Settings::values.speed_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) {
- Settings::values.speed_limit.SetValue(SPEED_LIMIT_STEP +
- Settings::values.speed_limit.GetValue());
- UpdateStatusBar();
- }
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Decrease Speed Limit"), this),
- &QShortcut::activated, this, [&] {
- if (Settings::values.speed_limit.GetValue() > SPEED_LIMIT_STEP) {
- Settings::values.speed_limit.SetValue(Settings::values.speed_limit.GetValue() -
- SPEED_LIMIT_STEP);
- UpdateStatusBar();
- }
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load Amiibo"), this),
- &QShortcut::activated, this, [&] {
- if (ui->action_Load_Amiibo->isEnabled()) {
- OnLoadAmiibo();
- }
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Capture Screenshot"), this),
- &QShortcut::activated, this, [&] {
- if (emu_thread != nullptr && emu_thread->IsRunning()) {
- OnCaptureScreenshot();
- }
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Change Docked Mode"), this),
- &QShortcut::activated, this, [&] {
- Settings::values.use_docked_mode.SetValue(
- !Settings::values.use_docked_mode.GetValue());
- OnDockedModeChanged(!Settings::values.use_docked_mode.GetValue(),
- Settings::values.use_docked_mode.GetValue(), *system);
- dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Mute Audio"), this),
- &QShortcut::activated, this,
- [] { Settings::values.audio_muted = !Settings::values.audio_muted; });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Framerate Limit"), this),
- &QShortcut::activated, this, [] {
- Settings::values.disable_fps_limit.SetValue(
- !Settings::values.disable_fps_limit.GetValue());
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this),
- &QShortcut::activated, this, [&] {
- Settings::values.mouse_panning = !Settings::values.mouse_panning;
- if (Settings::values.mouse_panning) {
- render_window->installEventFilter(render_window);
- render_window->setAttribute(Qt::WA_Hover, true);
- }
- });
+ connect_shortcut(QStringLiteral("Increase Speed Limit"), [&] {
+ if (Settings::values.speed_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) {
+ Settings::values.speed_limit.SetValue(SPEED_LIMIT_STEP +
+ Settings::values.speed_limit.GetValue());
+ UpdateStatusBar();
+ }
+ });
+ connect_shortcut(QStringLiteral("Decrease Speed Limit"), [&] {
+ if (Settings::values.speed_limit.GetValue() > SPEED_LIMIT_STEP) {
+ Settings::values.speed_limit.SetValue(Settings::values.speed_limit.GetValue() -
+ SPEED_LIMIT_STEP);
+ UpdateStatusBar();
+ }
+ });
+ connect_shortcut(QStringLiteral("Change Docked Mode"), [&] {
+ Settings::values.use_docked_mode.SetValue(!Settings::values.use_docked_mode.GetValue());
+ OnDockedModeChanged(!Settings::values.use_docked_mode.GetValue(),
+ Settings::values.use_docked_mode.GetValue(), *system);
+ dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
+ });
+ connect_shortcut(QStringLiteral("Mute Audio"),
+ [] { Settings::values.audio_muted = !Settings::values.audio_muted; });
+ connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] {
+ Settings::values.disable_fps_limit.SetValue(!Settings::values.disable_fps_limit.GetValue());
+ });
+ connect_shortcut(QStringLiteral("Toggle Mouse Panning"), [&] {
+ Settings::values.mouse_panning = !Settings::values.mouse_panning;
+ if (Settings::values.mouse_panning) {
+ render_window->installEventFilter(render_window);
+ render_window->setAttribute(Qt::WA_Hover, true);
+ }
+ });
}
void GMainWindow::SetDefaultUIGeometry() {
@@ -1164,7 +1080,8 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
(state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
auto_paused = true;
OnPauseGame();
- } else if (ui->action_Start->isEnabled() && auto_paused && state == Qt::ApplicationActive) {
+ } else if (emulation_running && !emu_thread->IsRunning() && auto_paused &&
+ state == Qt::ApplicationActive) {
auto_paused = false;
OnStartGame();
}
@@ -1208,64 +1125,86 @@ void GMainWindow::ConnectWidgetEvents() {
}
void GMainWindow::ConnectMenuEvents() {
+ const auto connect_menu = [&](QAction* action, const Fn& event_fn) {
+ connect(action, &QAction::triggered, this, event_fn);
+ // Add actions to this window so that hiding menus in fullscreen won't disable them
+ addAction(action);
+ // Add actions to the render window so that they work outside of single window mode
+ render_window->addAction(action);
+ };
+
// File
- connect(ui->action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile);
- connect(ui->action_Load_Folder, &QAction::triggered, this, &GMainWindow::OnMenuLoadFolder);
- connect(ui->action_Install_File_NAND, &QAction::triggered, this,
- &GMainWindow::OnMenuInstallToNAND);
- connect(ui->action_Exit, &QAction::triggered, this, &QMainWindow::close);
- connect(ui->action_Load_Amiibo, &QAction::triggered, this, &GMainWindow::OnLoadAmiibo);
+ connect_menu(ui->action_Load_File, &GMainWindow::OnMenuLoadFile);
+ connect_menu(ui->action_Load_Folder, &GMainWindow::OnMenuLoadFolder);
+ connect_menu(ui->action_Install_File_NAND, &GMainWindow::OnMenuInstallToNAND);
+ connect_menu(ui->action_Exit, &QMainWindow::close);
+ connect_menu(ui->action_Load_Amiibo, &GMainWindow::OnLoadAmiibo);
// Emulation
- connect(ui->action_Start, &QAction::triggered, this, &GMainWindow::OnStartGame);
- connect(ui->action_Pause, &QAction::triggered, this, &GMainWindow::OnPauseGame);
- connect(ui->action_Stop, &QAction::triggered, this, &GMainWindow::OnStopGame);
- connect(ui->action_Report_Compatibility, &QAction::triggered, this,
- &GMainWindow::OnMenuReportCompatibility);
- connect(ui->action_Open_Mods_Page, &QAction::triggered, this, &GMainWindow::OnOpenModsPage);
- connect(ui->action_Open_Quickstart_Guide, &QAction::triggered, this,
- &GMainWindow::OnOpenQuickstartGuide);
- connect(ui->action_Open_FAQ, &QAction::triggered, this, &GMainWindow::OnOpenFAQ);
- connect(ui->action_Restart, &QAction::triggered, this,
- [this] { BootGame(QString(game_path)); });
- connect(ui->action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure);
- connect(ui->action_Configure_Current_Game, &QAction::triggered, this,
- &GMainWindow::OnConfigurePerGame);
+ connect_menu(ui->action_Pause, &GMainWindow::OnPauseContinueGame);
+ connect_menu(ui->action_Stop, &GMainWindow::OnStopGame);
+ connect_menu(ui->action_Report_Compatibility, &GMainWindow::OnMenuReportCompatibility);
+ connect_menu(ui->action_Open_Mods_Page, &GMainWindow::OnOpenModsPage);
+ connect_menu(ui->action_Open_Quickstart_Guide, &GMainWindow::OnOpenQuickstartGuide);
+ connect_menu(ui->action_Open_FAQ, &GMainWindow::OnOpenFAQ);
+ connect_menu(ui->action_Restart, &GMainWindow::OnRestartGame);
+ connect_menu(ui->action_Configure, &GMainWindow::OnConfigure);
+ connect_menu(ui->action_Configure_Current_Game, &GMainWindow::OnConfigurePerGame);
// View
- connect(ui->action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen);
- connect(ui->action_Single_Window_Mode, &QAction::triggered, this,
- &GMainWindow::ToggleWindowMode);
- connect(ui->action_Display_Dock_Widget_Headers, &QAction::triggered, this,
- &GMainWindow::OnDisplayTitleBars);
- connect(ui->action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar);
+ connect_menu(ui->action_Fullscreen, &GMainWindow::ToggleFullscreen);
+ connect_menu(ui->action_Single_Window_Mode, &GMainWindow::ToggleWindowMode);
+ connect_menu(ui->action_Display_Dock_Widget_Headers, &GMainWindow::OnDisplayTitleBars);
+ connect_menu(ui->action_Show_Filter_Bar, &GMainWindow::OnToggleFilterBar);
+
connect(ui->action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible);
- connect(ui->action_Reset_Window_Size_720, &QAction::triggered, this,
- &GMainWindow::ResetWindowSize720);
- connect(ui->action_Reset_Window_Size_900, &QAction::triggered, this,
- &GMainWindow::ResetWindowSize900);
- connect(ui->action_Reset_Window_Size_1080, &QAction::triggered, this,
- &GMainWindow::ResetWindowSize1080);
- ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_720);
- ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_900);
- ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_1080);
+ connect_menu(ui->action_Reset_Window_Size_720, &GMainWindow::ResetWindowSize720);
+ connect_menu(ui->action_Reset_Window_Size_900, &GMainWindow::ResetWindowSize900);
+ connect_menu(ui->action_Reset_Window_Size_1080, &GMainWindow::ResetWindowSize1080);
+ ui->menu_Reset_Window_Size->addActions({ui->action_Reset_Window_Size_720,
+ ui->action_Reset_Window_Size_900,
+ ui->action_Reset_Window_Size_1080});
// Tools
- connect(ui->action_Rederive, &QAction::triggered, this,
- std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning));
- connect(ui->action_Capture_Screenshot, &QAction::triggered, this,
- &GMainWindow::OnCaptureScreenshot);
+ connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this,
+ ReinitializeKeyBehavior::Warning));
+ connect_menu(ui->action_Capture_Screenshot, &GMainWindow::OnCaptureScreenshot);
// TAS
- connect(ui->action_TAS_Start, &QAction::triggered, this, &GMainWindow::OnTasStartStop);
- connect(ui->action_TAS_Record, &QAction::triggered, this, &GMainWindow::OnTasRecord);
- connect(ui->action_TAS_Reset, &QAction::triggered, this, &GMainWindow::OnTasReset);
- connect(ui->action_Configure_Tas, &QAction::triggered, this, &GMainWindow::OnConfigureTas);
+ connect_menu(ui->action_TAS_Start, &GMainWindow::OnTasStartStop);
+ connect_menu(ui->action_TAS_Record, &GMainWindow::OnTasRecord);
+ connect_menu(ui->action_TAS_Reset, &GMainWindow::OnTasReset);
+ connect_menu(ui->action_Configure_Tas, &GMainWindow::OnConfigureTas);
// Help
- connect(ui->action_Open_yuzu_Folder, &QAction::triggered, this, &GMainWindow::OnOpenYuzuFolder);
- connect(ui->action_About, &QAction::triggered, this, &GMainWindow::OnAbout);
+ connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder);
+ connect_menu(ui->action_About, &GMainWindow::OnAbout);
+}
+
+void GMainWindow::UpdateMenuState() {
+ const bool is_paused = emu_thread == nullptr || !emu_thread->IsRunning();
+
+ const std::array running_actions{
+ ui->action_Stop,
+ ui->action_Restart,
+ ui->action_Configure_Current_Game,
+ ui->action_Report_Compatibility,
+ ui->action_Load_Amiibo,
+ ui->action_Pause,
+ };
+
+ for (QAction* action : running_actions) {
+ action->setEnabled(emulation_running);
+ }
+
+ ui->action_Capture_Screenshot->setEnabled(emulation_running && !is_paused);
+
+ if (emulation_running && is_paused) {
+ ui->action_Pause->setText(tr("&Continue"));
+ } else {
+ ui->action_Pause->setText(tr("&Pause"));
+ }
}
void GMainWindow::OnDisplayTitleBars(bool show) {
@@ -1558,15 +1497,8 @@ void GMainWindow::ShutdownGame() {
disconnect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
// Update the GUI
- ui->action_Start->setEnabled(false);
- ui->action_Start->setText(tr("Start"));
- ui->action_Pause->setEnabled(false);
- ui->action_Stop->setEnabled(false);
- ui->action_Restart->setEnabled(false);
- ui->action_Configure_Current_Game->setEnabled(false);
- ui->action_Report_Compatibility->setEnabled(false);
- ui->action_Load_Amiibo->setEnabled(false);
- ui->action_Capture_Screenshot->setEnabled(false);
+ UpdateMenuState();
+
render_window->hide();
loading_screen->hide();
loading_screen->Clear();
@@ -2498,32 +2430,36 @@ void GMainWindow::OnStartGame() {
connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
- ui->action_Start->setEnabled(false);
- ui->action_Start->setText(tr("&Continue"));
-
- ui->action_Pause->setEnabled(true);
- ui->action_Stop->setEnabled(true);
- ui->action_Restart->setEnabled(true);
- ui->action_Configure_Current_Game->setEnabled(true);
- ui->action_Report_Compatibility->setEnabled(true);
+ UpdateMenuState();
OnTasStateChanged();
discord_rpc->Update();
- ui->action_Load_Amiibo->setEnabled(true);
- ui->action_Capture_Screenshot->setEnabled(true);
+}
+
+void GMainWindow::OnRestartGame() {
+ if (!system->IsPoweredOn()) {
+ return;
+ }
+ // Make a copy since BootGame edits game_path
+ BootGame(QString(game_path));
}
void GMainWindow::OnPauseGame() {
emu_thread->SetRunning(false);
-
- ui->action_Start->setEnabled(true);
- ui->action_Pause->setEnabled(false);
- ui->action_Stop->setEnabled(true);
- ui->action_Capture_Screenshot->setEnabled(false);
-
+ UpdateMenuState();
AllowOSSleep();
}
+void GMainWindow::OnPauseContinueGame() {
+ if (emulation_running) {
+ if (emu_thread->IsRunning()) {
+ OnPauseGame();
+ } else {
+ OnStartGame();
+ }
+ }
+}
+
void GMainWindow::OnStopGame() {
if (system->GetExitLock() && !ConfirmForceLockedExit()) {
return;
@@ -2882,6 +2818,10 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file
}
void GMainWindow::OnLoadAmiibo() {
+ if (emu_thread == nullptr || !emu_thread->IsRunning()) {
+ return;
+ }
+
const QString extensions{QStringLiteral("*.bin")};
const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions);
const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), {}, file_filter);
@@ -2945,6 +2885,10 @@ void GMainWindow::OnToggleFilterBar() {
}
void GMainWindow::OnCaptureScreenshot() {
+ if (emu_thread == nullptr || !emu_thread->IsRunning()) {
+ return;
+ }
+
const u64 title_id = system->GetCurrentProcessProgramID();
const auto screenshot_path =
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir));
@@ -3593,9 +3537,6 @@ void GMainWindow::OnLanguageChanged(const QString& locale) {
LoadTranslation();
ui->retranslateUi(this);
UpdateWindowTitle();
-
- if (emulation_running)
- ui->action_Start->setText(tr("&Continue"));
}
void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) {
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 556cbbaf7..0fd41ed4f 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -191,6 +191,7 @@ private:
void ConnectWidgetEvents();
void ConnectMenuEvents();
+ void UpdateMenuState();
void PreventOSSleep();
void AllowOSSleep();
@@ -240,7 +241,9 @@ private:
private slots:
void OnStartGame();
+ void OnRestartGame();
void OnPauseGame();
+ void OnPauseContinueGame();
void OnStopGame();
void OnMenuReportCompatibility();
void OnOpenModsPage();
@@ -294,6 +297,9 @@ private slots:
void OnMouseActivity();
private:
+ /// Updates an action's shortcut and text to reflect an updated hotkey from the hotkey registry.
+ void LinkActionShortcut(QAction* action, const QString& action_name);
+
void RemoveBaseContent(u64 program_id, const QString& entry_type);
void RemoveUpdateContent(u64 program_id, const QString& entry_type);
void RemoveAddOnContent(u64 program_id, const QString& entry_type);
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index c58aa2866..5719b2ee4 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -66,7 +66,6 @@
&Emulation
-
@@ -180,14 +179,6 @@
E&xit
-
-
- false
-
-
- &Start
-
-
false
--
cgit v1.2.3
From ad5142ac2c56aded4090ad031a9351cd188caacf Mon Sep 17 00:00:00 2001
From: german77
Date: Mon, 20 Sep 2021 14:56:55 -0500
Subject: common: Rewrite and move core/frontend/input.h to common
---
src/common/CMakeLists.txt | 1 +
src/common/input.h | 242 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 243 insertions(+)
create mode 100644 src/common/input.h
(limited to 'src')
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 23d43a394..919da4a53 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -73,6 +73,7 @@ add_library(common STATIC
hex_util.h
host_memory.cpp
host_memory.h
+ input.h
intrusive_red_black_tree.h
literals.h
logging/backend.cpp
diff --git a/src/common/input.h b/src/common/input.h
new file mode 100644
index 000000000..6eefc55f9
--- /dev/null
+++ b/src/common/input.h
@@ -0,0 +1,242 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include "common/logging/log.h"
+#include "common/param_package.h"
+
+namespace Input {
+
+enum class InputType {
+ None,
+ Battery,
+ Button,
+ Stick,
+ Analog,
+ Trigger,
+ Motion,
+ Touch,
+ Color,
+ Vibration,
+ Nfc,
+ Ir,
+};
+
+enum class BatteryLevel {
+ Empty,
+ Critical,
+ Low,
+ Medium,
+ Full,
+ Charging,
+};
+
+struct AnalogProperties {
+ float deadzone{};
+ float range{1.0f};
+ float threshold{0.5f};
+ float offset{};
+ bool inverted{};
+};
+
+struct AnalogStatus {
+ float value{};
+ float raw_value{};
+ AnalogProperties properties{};
+};
+
+struct ButtonStatus {
+ bool value{};
+ bool inverted{};
+ bool toggle{};
+ bool locked{};
+};
+
+using BatteryStatus = BatteryLevel;
+
+struct StickStatus {
+ AnalogStatus x{};
+ AnalogStatus y{};
+ bool left{};
+ bool right{};
+ bool up{};
+ bool down{};
+};
+
+struct TriggerStatus {
+ AnalogStatus analog{};
+ bool pressed{};
+};
+
+struct MotionSensor {
+ AnalogStatus x{};
+ AnalogStatus y{};
+ AnalogStatus z{};
+};
+
+struct MotionStatus {
+ MotionSensor gyro{};
+ MotionSensor accel{};
+ u64 delta_timestamp{};
+};
+
+struct TouchStatus {
+ ButtonStatus pressed{};
+ AnalogStatus x{};
+ AnalogStatus y{};
+ u32 id{};
+};
+
+struct BodyColorStatus {
+ u32 body{};
+ u32 buttons{};
+};
+
+struct VibrationStatus {
+ f32 low_amplitude{};
+ f32 low_frequency{};
+ f32 high_amplitude{};
+ f32 high_frequency{};
+};
+
+struct LedStatus {
+ bool led_1{};
+ bool led_2{};
+ bool led_3{};
+ bool led_4{};
+};
+
+struct CallbackStatus {
+ InputType type{InputType::None};
+ ButtonStatus button_status{};
+ StickStatus stick_status{};
+ AnalogStatus analog_status{};
+ TriggerStatus trigger_status{};
+ MotionStatus motion_status{};
+ TouchStatus touch_status{};
+ BodyColorStatus color_status{};
+ BatteryStatus battery_status{};
+ VibrationStatus vibration_status{};
+};
+
+struct InputCallback {
+ std::function on_change;
+};
+
+/// An abstract class template for an input device (a button, an analog input, etc.).
+class InputDevice {
+public:
+ virtual ~InputDevice() = default;
+
+ void SetCallback(InputCallback callback_) {
+ callback = std::move(callback_);
+ }
+
+ void TriggerOnChange(CallbackStatus status) {
+ if (callback.on_change) {
+ callback.on_change(status);
+ }
+ }
+
+private:
+ InputCallback callback;
+};
+
+/// An abstract class template for a factory that can create input devices.
+template
+class Factory {
+public:
+ virtual ~Factory() = default;
+ virtual std::unique_ptr Create(const Common::ParamPackage&) = 0;
+};
+
+namespace Impl {
+
+template
+using FactoryListType = std::unordered_map>>;
+
+template
+struct FactoryList {
+ static FactoryListType list;
+};
+
+template
+FactoryListType FactoryList::list;
+
+} // namespace Impl
+
+/**
+ * Registers an input device factory.
+ * @tparam InputDeviceType the type of input devices the factory can create
+ * @param name the name of the factory. Will be used to match the "engine" parameter when creating
+ * a device
+ * @param factory the factory object to register
+ */
+template
+void RegisterFactory(const std::string& name, std::shared_ptr> factory) {
+ auto pair = std::make_pair(name, std::move(factory));
+ if (!Impl::FactoryList::list.insert(std::move(pair)).second) {
+ LOG_ERROR(Input, "Factory '{}' already registered", name);
+ }
+}
+
+/**
+ * Unregisters an input device factory.
+ * @tparam InputDeviceType the type of input devices the factory can create
+ * @param name the name of the factory to unregister
+ */
+template
+void UnregisterFactory(const std::string& name) {
+ if (Impl::FactoryList::list.erase(name) == 0) {
+ LOG_ERROR(Input, "Factory '{}' not registered", name);
+ }
+}
+
+/**
+ * Create an input device from given paramters.
+ * @tparam InputDeviceType the type of input devices to create
+ * @param params a serialized ParamPackage string that contains all parameters for creating the
+ * device
+ */
+template
+std::unique_ptr CreateDeviceFromString(const std::string& params) {
+ const Common::ParamPackage package(params);
+ const std::string engine = package.Get("engine", "null");
+ const auto& factory_list = Impl::FactoryList::list;
+ const auto pair = factory_list.find(engine);
+ if (pair == factory_list.end()) {
+ if (engine != "null") {
+ LOG_ERROR(Input, "Unknown engine name: {}", engine);
+ }
+ return std::make_unique();
+ }
+ return pair->second->Create(package);
+}
+
+/**
+ * Create an input device from given paramters.
+ * @tparam InputDeviceType the type of input devices to create
+ * @param A ParamPackage that contains all parameters for creating the device
+ */
+template
+std::unique_ptr CreateDevice(const Common::ParamPackage package) {
+ const std::string engine = package.Get("engine", "null");
+ const auto& factory_list = Impl::FactoryList::list;
+ const auto pair = factory_list.find(engine);
+ if (pair == factory_list.end()) {
+ if (engine != "null") {
+ LOG_ERROR(Input, "Unknown engine name: {}", engine);
+ }
+ return std::make_unique();
+ }
+ return pair->second->Create(package);
+}
+
+} // namespace Input
--
cgit v1.2.3
From bf71d18af99368d7658c9519086c40e73c6abfdd Mon Sep 17 00:00:00 2001
From: german77
Date: Mon, 20 Sep 2021 15:02:01 -0500
Subject: core/hid: Move input_interpreter to hid
---
src/core/CMakeLists.txt | 4 +-
src/core/frontend/input_interpreter.cpp | 62 --------------
src/core/frontend/input_interpreter.h | 144 --------------------------------
src/core/hid/input_interpreter.cpp | 62 ++++++++++++++
src/core/hid/input_interpreter.h | 144 ++++++++++++++++++++++++++++++++
src/yuzu/applets/qt_web_browser.cpp | 2 +-
6 files changed, 209 insertions(+), 209 deletions(-)
delete mode 100644 src/core/frontend/input_interpreter.cpp
delete mode 100644 src/core/frontend/input_interpreter.h
create mode 100644 src/core/hid/input_interpreter.cpp
create mode 100644 src/core/hid/input_interpreter.h
(limited to 'src')
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 9f0fbba2d..14ba986d3 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -132,11 +132,11 @@ add_library(core STATIC
frontend/emu_window.h
frontend/framebuffer_layout.cpp
frontend/framebuffer_layout.h
- frontend/input_interpreter.cpp
- frontend/input_interpreter.h
frontend/input.h
hardware_interrupt_manager.cpp
hardware_interrupt_manager.h
+ hid/input_interpreter.cpp
+ hid/input_interpreter.h
hle/api_version.h
hle/ipc.h
hle/ipc_helpers.h
diff --git a/src/core/frontend/input_interpreter.cpp b/src/core/frontend/input_interpreter.cpp
deleted file mode 100644
index 9f6a90e8f..000000000
--- a/src/core/frontend/input_interpreter.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2020 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/core.h"
-#include "core/frontend/input_interpreter.h"
-#include "core/hle/service/hid/controllers/npad.h"
-#include "core/hle/service/hid/hid.h"
-#include "core/hle/service/sm/sm.h"
-
-InputInterpreter::InputInterpreter(Core::System& system)
- : npad{system.ServiceManager()
- .GetService("hid")
- ->GetAppletResource()
- ->GetController(Service::HID::HidController::NPad)} {
- ResetButtonStates();
-}
-
-InputInterpreter::~InputInterpreter() = default;
-
-void InputInterpreter::PollInput() {
- const u32 button_state = npad.GetAndResetPressState();
-
- previous_index = current_index;
- current_index = (current_index + 1) % button_states.size();
-
- button_states[current_index] = button_state;
-}
-
-void InputInterpreter::ResetButtonStates() {
- previous_index = 0;
- current_index = 0;
-
- button_states[0] = 0xFFFFFFFF;
-
- for (std::size_t i = 1; i < button_states.size(); ++i) {
- button_states[i] = 0;
- }
-}
-
-bool InputInterpreter::IsButtonPressed(HIDButton button) const {
- return (button_states[current_index] & (1U << static_cast(button))) != 0;
-}
-
-bool InputInterpreter::IsButtonPressedOnce(HIDButton button) const {
- const bool current_press =
- (button_states[current_index] & (1U << static_cast(button))) != 0;
- const bool previous_press =
- (button_states[previous_index] & (1U << static_cast(button))) != 0;
-
- return current_press && !previous_press;
-}
-
-bool InputInterpreter::IsButtonHeld(HIDButton button) const {
- u32 held_buttons{button_states[0]};
-
- for (std::size_t i = 1; i < button_states.size(); ++i) {
- held_buttons &= button_states[i];
- }
-
- return (held_buttons & (1U << static_cast(button))) != 0;
-}
diff --git a/src/core/frontend/input_interpreter.h b/src/core/frontend/input_interpreter.h
deleted file mode 100644
index 9495e3daf..000000000
--- a/src/core/frontend/input_interpreter.h
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright 2020 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include
-
-#include "common/common_types.h"
-
-namespace Core {
-class System;
-}
-
-namespace Service::HID {
-class Controller_NPad;
-}
-
-enum class HIDButton : u8 {
- A,
- B,
- X,
- Y,
- LStick,
- RStick,
- L,
- R,
- ZL,
- ZR,
- Plus,
- Minus,
-
- DLeft,
- DUp,
- DRight,
- DDown,
-
- LStickLeft,
- LStickUp,
- LStickRight,
- LStickDown,
-
- RStickLeft,
- RStickUp,
- RStickRight,
- RStickDown,
-
- LeftSL,
- LeftSR,
-
- RightSL,
- RightSR,
-};
-
-/**
- * The InputInterpreter class interfaces with HID to retrieve button press states.
- * Input is intended to be polled every 50ms so that a button is considered to be
- * held down after 400ms has elapsed since the initial button press and subsequent
- * repeated presses occur every 50ms.
- */
-class InputInterpreter {
-public:
- explicit InputInterpreter(Core::System& system);
- virtual ~InputInterpreter();
-
- /// Gets a button state from HID and inserts it into the array of button states.
- void PollInput();
-
- /// Resets all the button states to their defaults.
- void ResetButtonStates();
-
- /**
- * Checks whether the button is pressed.
- *
- * @param button The button to check.
- *
- * @returns True when the button is pressed.
- */
- [[nodiscard]] bool IsButtonPressed(HIDButton button) const;
-
- /**
- * Checks whether any of the buttons in the parameter list is pressed.
- *
- * @tparam HIDButton The buttons to check.
- *
- * @returns True when at least one of the buttons is pressed.
- */
- template
- [[nodiscard]] bool IsAnyButtonPressed() {
- return (IsButtonPressed(T) || ...);
- }
-
- /**
- * The specified button is considered to be pressed once
- * if it is currently pressed and not pressed previously.
- *
- * @param button The button to check.
- *
- * @returns True when the button is pressed once.
- */
- [[nodiscard]] bool IsButtonPressedOnce(HIDButton button) const;
-
- /**
- * Checks whether any of the buttons in the parameter list is pressed once.
- *
- * @tparam T The buttons to check.
- *
- * @returns True when at least one of the buttons is pressed once.
- */
- template
- [[nodiscard]] bool IsAnyButtonPressedOnce() const {
- return (IsButtonPressedOnce(T) || ...);
- }
-
- /**
- * The specified button is considered to be held down if it is pressed in all 9 button states.
- *
- * @param button The button to check.
- *
- * @returns True when the button is held down.
- */
- [[nodiscard]] bool IsButtonHeld(HIDButton button) const;
-
- /**
- * Checks whether any of the buttons in the parameter list is held down.
- *
- * @tparam T The buttons to check.
- *
- * @returns True when at least one of the buttons is held down.
- */
- template
- [[nodiscard]] bool IsAnyButtonHeld() const {
- return (IsButtonHeld(T) || ...);
- }
-
-private:
- Service::HID::Controller_NPad& npad;
-
- /// Stores 9 consecutive button states polled from HID.
- std::array button_states{};
-
- std::size_t previous_index{};
- std::size_t current_index{};
-};
diff --git a/src/core/hid/input_interpreter.cpp b/src/core/hid/input_interpreter.cpp
new file mode 100644
index 000000000..c33d8a11a
--- /dev/null
+++ b/src/core/hid/input_interpreter.cpp
@@ -0,0 +1,62 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/core.h"
+#include "core/hid/input_interpreter.h"
+#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/hid/hid.h"
+#include "core/hle/service/sm/sm.h"
+
+InputInterpreter::InputInterpreter(Core::System& system)
+ : npad{system.ServiceManager()
+ .GetService("hid")
+ ->GetAppletResource()
+ ->GetController(Service::HID::HidController::NPad)} {
+ ResetButtonStates();
+}
+
+InputInterpreter::~InputInterpreter() = default;
+
+void InputInterpreter::PollInput() {
+ const u32 button_state = npad.GetAndResetPressState();
+
+ previous_index = current_index;
+ current_index = (current_index + 1) % button_states.size();
+
+ button_states[current_index] = button_state;
+}
+
+void InputInterpreter::ResetButtonStates() {
+ previous_index = 0;
+ current_index = 0;
+
+ button_states[0] = 0xFFFFFFFF;
+
+ for (std::size_t i = 1; i < button_states.size(); ++i) {
+ button_states[i] = 0;
+ }
+}
+
+bool InputInterpreter::IsButtonPressed(HIDButton button) const {
+ return (button_states[current_index] & (1U << static_cast(button))) != 0;
+}
+
+bool InputInterpreter::IsButtonPressedOnce(HIDButton button) const {
+ const bool current_press =
+ (button_states[current_index] & (1U << static_cast(button))) != 0;
+ const bool previous_press =
+ (button_states[previous_index] & (1U << static_cast(button))) != 0;
+
+ return current_press && !previous_press;
+}
+
+bool InputInterpreter::IsButtonHeld(HIDButton button) const {
+ u32 held_buttons{button_states[0]};
+
+ for (std::size_t i = 1; i < button_states.size(); ++i) {
+ held_buttons &= button_states[i];
+ }
+
+ return (held_buttons & (1U << static_cast(button))) != 0;
+}
diff --git a/src/core/hid/input_interpreter.h b/src/core/hid/input_interpreter.h
new file mode 100644
index 000000000..9495e3daf
--- /dev/null
+++ b/src/core/hid/input_interpreter.h
@@ -0,0 +1,144 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+
+#include "common/common_types.h"
+
+namespace Core {
+class System;
+}
+
+namespace Service::HID {
+class Controller_NPad;
+}
+
+enum class HIDButton : u8 {
+ A,
+ B,
+ X,
+ Y,
+ LStick,
+ RStick,
+ L,
+ R,
+ ZL,
+ ZR,
+ Plus,
+ Minus,
+
+ DLeft,
+ DUp,
+ DRight,
+ DDown,
+
+ LStickLeft,
+ LStickUp,
+ LStickRight,
+ LStickDown,
+
+ RStickLeft,
+ RStickUp,
+ RStickRight,
+ RStickDown,
+
+ LeftSL,
+ LeftSR,
+
+ RightSL,
+ RightSR,
+};
+
+/**
+ * The InputInterpreter class interfaces with HID to retrieve button press states.
+ * Input is intended to be polled every 50ms so that a button is considered to be
+ * held down after 400ms has elapsed since the initial button press and subsequent
+ * repeated presses occur every 50ms.
+ */
+class InputInterpreter {
+public:
+ explicit InputInterpreter(Core::System& system);
+ virtual ~InputInterpreter();
+
+ /// Gets a button state from HID and inserts it into the array of button states.
+ void PollInput();
+
+ /// Resets all the button states to their defaults.
+ void ResetButtonStates();
+
+ /**
+ * Checks whether the button is pressed.
+ *
+ * @param button The button to check.
+ *
+ * @returns True when the button is pressed.
+ */
+ [[nodiscard]] bool IsButtonPressed(HIDButton button) const;
+
+ /**
+ * Checks whether any of the buttons in the parameter list is pressed.
+ *
+ * @tparam HIDButton The buttons to check.
+ *
+ * @returns True when at least one of the buttons is pressed.
+ */
+ template
+ [[nodiscard]] bool IsAnyButtonPressed() {
+ return (IsButtonPressed(T) || ...);
+ }
+
+ /**
+ * The specified button is considered to be pressed once
+ * if it is currently pressed and not pressed previously.
+ *
+ * @param button The button to check.
+ *
+ * @returns True when the button is pressed once.
+ */
+ [[nodiscard]] bool IsButtonPressedOnce(HIDButton button) const;
+
+ /**
+ * Checks whether any of the buttons in the parameter list is pressed once.
+ *
+ * @tparam T The buttons to check.
+ *
+ * @returns True when at least one of the buttons is pressed once.
+ */
+ template
+ [[nodiscard]] bool IsAnyButtonPressedOnce() const {
+ return (IsButtonPressedOnce(T) || ...);
+ }
+
+ /**
+ * The specified button is considered to be held down if it is pressed in all 9 button states.
+ *
+ * @param button The button to check.
+ *
+ * @returns True when the button is held down.
+ */
+ [[nodiscard]] bool IsButtonHeld(HIDButton button) const;
+
+ /**
+ * Checks whether any of the buttons in the parameter list is held down.
+ *
+ * @tparam T The buttons to check.
+ *
+ * @returns True when at least one of the buttons is held down.
+ */
+ template
+ [[nodiscard]] bool IsAnyButtonHeld() const {
+ return (IsButtonHeld(T) || ...);
+ }
+
+private:
+ Service::HID::Controller_NPad& npad;
+
+ /// Stores 9 consecutive button states polled from HID.
+ std::array button_states{};
+
+ std::size_t previous_index{};
+ std::size_t current_index{};
+};
diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp
index da8c6882a..24d72a496 100644
--- a/src/yuzu/applets/qt_web_browser.cpp
+++ b/src/yuzu/applets/qt_web_browser.cpp
@@ -15,7 +15,7 @@
#include "common/fs/path_util.h"
#include "core/core.h"
-#include "core/frontend/input_interpreter.h"
+#include "core/hid/input_interpreter.h"
#include "input_common/keyboard.h"
#include "input_common/main.h"
#include "yuzu/applets/qt_web_browser.h"
--
cgit v1.2.3
From 449576df93f6beb70cff0e009ccb2dd8bce1e085 Mon Sep 17 00:00:00 2001
From: german77
Date: Mon, 20 Sep 2021 16:29:43 -0500
Subject: core/hid: Move motion_input, create input converter and hid_types
---
src/core/CMakeLists.txt | 5 +
src/core/hid/hid_types.h | 388 +++++++++++++++++++++++++++++++++++++++
src/core/hid/input_converter.cpp | 345 ++++++++++++++++++++++++++++++++++
src/core/hid/input_converter.h | 77 ++++++++
src/core/hid/motion_input.cpp | 278 ++++++++++++++++++++++++++++
src/core/hid/motion_input.h | 71 +++++++
6 files changed, 1164 insertions(+)
create mode 100644 src/core/hid/hid_types.h
create mode 100644 src/core/hid/input_converter.cpp
create mode 100644 src/core/hid/input_converter.h
create mode 100644 src/core/hid/motion_input.cpp
create mode 100644 src/core/hid/motion_input.h
(limited to 'src')
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 14ba986d3..eddf455c0 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -135,8 +135,13 @@ add_library(core STATIC
frontend/input.h
hardware_interrupt_manager.cpp
hardware_interrupt_manager.h
+ hid/hid_types.h
+ hid/input_converter.cpp
+ hid/input_converter.h
hid/input_interpreter.cpp
hid/input_interpreter.h
+ hid/motion_input.cpp
+ hid/motion_input.h
hle/api_version.h
hle/ipc.h
hle/ipc_helpers.h
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
new file mode 100644
index 000000000..d3f7930c9
--- /dev/null
+++ b/src/core/hid/hid_types.h
@@ -0,0 +1,388 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/point.h"
+#include "common/uuid.h"
+
+namespace Core::HID {
+
+// This is nn::hid::NpadIdType
+enum class NpadIdType : u8 {
+ Player1 = 0x0,
+ Player2 = 0x1,
+ Player3 = 0x2,
+ Player4 = 0x3,
+ Player5 = 0x4,
+ Player6 = 0x5,
+ Player7 = 0x6,
+ Player8 = 0x7,
+ Other = 0x10,
+ Handheld = 0x20,
+
+ Invalid = 0xFF,
+};
+
+/// Converts a NpadIdType to an array index.
+constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) {
+ switch (npad_id_type) {
+ case NpadIdType::Player1:
+ return 0;
+ case NpadIdType::Player2:
+ return 1;
+ case NpadIdType::Player3:
+ return 2;
+ case NpadIdType::Player4:
+ return 3;
+ case NpadIdType::Player5:
+ return 4;
+ case NpadIdType::Player6:
+ return 5;
+ case NpadIdType::Player7:
+ return 6;
+ case NpadIdType::Player8:
+ return 7;
+ case NpadIdType::Other:
+ return 8;
+ case NpadIdType::Handheld:
+ return 9;
+ default:
+ return 0;
+ }
+}
+
+/// Converts an array index to a NpadIdType
+constexpr NpadIdType IndexToNpadIdType(size_t index) {
+ switch (index) {
+ case 0:
+ return NpadIdType::Player1;
+ case 1:
+ return NpadIdType::Player2;
+ case 2:
+ return NpadIdType::Player3;
+ case 3:
+ return NpadIdType::Player4;
+ case 4:
+ return NpadIdType::Player5;
+ case 5:
+ return NpadIdType::Player6;
+ case 6:
+ return NpadIdType::Player7;
+ case 7:
+ return NpadIdType::Player8;
+ case 8:
+ return NpadIdType::Other;
+ case 9:
+ return NpadIdType::Handheld;
+ default:
+ return NpadIdType::Invalid;
+ }
+}
+
+// This is nn::hid::NpadType
+enum class NpadType : u8 {
+ None = 0,
+ ProController = 3,
+ Handheld = 4,
+ JoyconDual = 5,
+ JoyconLeft = 6,
+ JoyconRight = 7,
+ GameCube = 8,
+ Pokeball = 9,
+ MaxNpadType = 10,
+};
+
+// This is nn::hid::NpadStyleTag
+struct NpadStyleTag {
+ union {
+ u32_le raw{};
+
+ BitField<0, 1, u32> fullkey;
+ BitField<1, 1, u32> handheld;
+ BitField<2, 1, u32> joycon_dual;
+ BitField<3, 1, u32> joycon_left;
+ BitField<4, 1, u32> joycon_right;
+ BitField<5, 1, u32> gamecube;
+ BitField<6, 1, u32> palma;
+ BitField<7, 1, u32> lark;
+ BitField<8, 1, u32> handheld_lark;
+ BitField<9, 1, u32> lucia;
+ BitField<29, 1, u32> system_ext;
+ BitField<30, 1, u32> system;
+ };
+};
+static_assert(sizeof(NpadStyleTag) == 4, "NpadStyleTag is an invalid size");
+
+// This is nn::hid::TouchAttribute
+struct TouchAttribute {
+ union {
+ u32 raw{};
+ BitField<0, 1, u32> start_touch;
+ BitField<1, 1, u32> end_touch;
+ };
+};
+static_assert(sizeof(TouchAttribute) == 0x4, "TouchAttribute is an invalid size");
+
+// This is nn::hid::TouchState
+struct TouchState {
+ u64_le delta_time;
+ TouchAttribute attribute;
+ u32_le finger;
+ Common::Point position;
+ u32_le diameter_x;
+ u32_le diameter_y;
+ u32_le rotation_angle;
+};
+static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
+
+// This is nn::hid::NpadControllerColor
+struct NpadControllerColor {
+ u32_le body;
+ u32_le button;
+};
+static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size");
+
+// This is nn::hid::AnalogStickState
+struct AnalogStickState {
+ s32_le x;
+ s32_le y;
+};
+static_assert(sizeof(AnalogStickState) == 8, "AnalogStickState is an invalid size");
+
+// This is nn::hid::server::NpadGcTriggerState
+struct NpadGcTriggerState {
+ s64_le sampling_number{};
+ s32_le left{};
+ s32_le right{};
+};
+static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
+
+// This is nn::hid::system::NpadBatteryLevel
+using BatteryLevel = u32;
+static_assert(sizeof(BatteryLevel) == 0x4, "BatteryLevel is an invalid size");
+
+// This is nn::hid::system::NpadPowerInfo
+struct NpadPowerInfo {
+ bool is_powered;
+ bool is_charging;
+ INSERT_PADDING_BYTES(0x6);
+ BatteryLevel battery_level;
+};
+static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size");
+
+// This is nn::hid::NpadButton
+enum class NpadButton : u64 {
+ None = 0,
+ A = 1U << 0,
+ B = 1U << 1,
+ X = 1U << 2,
+ Y = 1U << 3,
+ StickL = 1U << 4,
+ StickR = 1U << 5,
+ L = 1U << 6,
+ R = 1U << 7,
+ ZL = 1U << 8,
+ ZR = 1U << 9,
+ Plus = 1U << 10,
+ Minus = 1U << 11,
+
+ Left = 1U << 12,
+ Up = 1U << 13,
+ Right = 1U << 14,
+ Down = 1U << 15,
+
+ StickLLeft = 1U << 16,
+ StickLUp = 1U << 17,
+ StickLRight = 1U << 18,
+ StickLDown = 1U << 19,
+
+ StickRLeft = 1U << 20,
+ StickRUp = 1U << 21,
+ StickRRight = 1U << 22,
+ StickRDown = 1U << 23,
+
+ LeftSL = 1U << 24,
+ LeftSR = 1U << 25,
+
+ RightSL = 1U << 26,
+ RightSR = 1U << 27,
+
+ Palma = 1U << 28,
+ HandheldLeftB = 1U << 30,
+};
+DECLARE_ENUM_FLAG_OPERATORS(NpadButton);
+
+struct NpadButtonState {
+ union {
+ NpadButton raw{};
+
+ // Buttons
+ BitField<0, 1, u64> a;
+ BitField<1, 1, u64> b;
+ BitField<2, 1, u64> x;
+ BitField<3, 1, u64> y;
+ BitField<4, 1, u64> stick_l;
+ BitField<5, 1, u64> stick_r;
+ BitField<6, 1, u64> l;
+ BitField<7, 1, u64> r;
+ BitField<8, 1, u64> zl;
+ BitField<9, 1, u64> zr;
+ BitField<10, 1, u64> plus;
+ BitField<11, 1, u64> minus;
+
+ // D-Pad
+ BitField<12, 1, u64> left;
+ BitField<13, 1, u64> up;
+ BitField<14, 1, u64> right;
+ BitField<15, 1, u64> down;
+
+ // Left JoyStick
+ BitField<16, 1, u64> stick_l_left;
+ BitField<17, 1, u64> stick_l_up;
+ BitField<18, 1, u64> stick_l_right;
+ BitField<19, 1, u64> stick_l_down;
+
+ // Right JoyStick
+ BitField<20, 1, u64> stick_r_left;
+ BitField<21, 1, u64> stick_r_up;
+ BitField<22, 1, u64> stick_r_right;
+ BitField<23, 1, u64> stick_r_down;
+
+ BitField<24, 1, u64> left_sl;
+ BitField<25, 1, u64> left_sr;
+
+ BitField<26, 1, u64> right_sl;
+ BitField<27, 1, u64> right_sr;
+
+ BitField<28, 1, u64> palma;
+ BitField<30, 1, u64> handheld_left_b;
+ };
+};
+static_assert(sizeof(NpadButtonState) == 0x8, "NpadButtonState has incorrect size.");
+
+// This is nn::hid::DebugPadButton
+struct DebugPadButton {
+ union {
+ u32_le raw{};
+ BitField<0, 1, u32> a;
+ BitField<1, 1, u32> b;
+ BitField<2, 1, u32> x;
+ BitField<3, 1, u32> y;
+ BitField<4, 1, u32> l;
+ BitField<5, 1, u32> r;
+ BitField<6, 1, u32> zl;
+ BitField<7, 1, u32> zr;
+ BitField<8, 1, u32> plus;
+ BitField<9, 1, u32> minus;
+ BitField<10, 1, u32> d_left;
+ BitField<11, 1, u32> d_up;
+ BitField<12, 1, u32> d_right;
+ BitField<13, 1, u32> d_down;
+ };
+};
+static_assert(sizeof(DebugPadButton) == 0x4, "DebugPadButton is an invalid size");
+
+// This is nn::hid::VibrationDeviceType
+enum class VibrationDeviceType : u32 {
+ Unknown = 0,
+ LinearResonantActuator = 1,
+ GcErm = 2,
+};
+
+// This is nn::hid::VibrationDevicePosition
+enum class VibrationDevicePosition : u32 {
+ None = 0,
+ Left = 1,
+ Right = 2,
+};
+
+// This is nn::hid::VibrationValue
+struct VibrationValue {
+ f32 low_amplitude;
+ f32 low_frequency;
+ f32 high_amplitude;
+ f32 high_frequency;
+};
+static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size.");
+
+// This is nn::hid::VibrationGcErmCommand
+enum class VibrationGcErmCommand : u64 {
+ Stop = 0,
+ Start = 1,
+ StopHard = 2,
+};
+
+// This is nn::hid::VibrationDeviceInfo
+struct VibrationDeviceInfo {
+ VibrationDeviceType type{};
+ VibrationDevicePosition position{};
+};
+static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size.");
+
+// This is nn::hid::KeyboardModifier
+struct KeyboardModifier {
+ union {
+ u32_le raw{};
+ BitField<0, 1, u32> control;
+ BitField<1, 1, u32> shift;
+ BitField<2, 1, u32> left_alt;
+ BitField<3, 1, u32> right_alt;
+ BitField<4, 1, u32> gui;
+ BitField<8, 1, u32> caps_lock;
+ BitField<9, 1, u32> scroll_lock;
+ BitField<10, 1, u32> num_lock;
+ BitField<11, 1, u32> katakana;
+ BitField<12, 1, u32> hiragana;
+ };
+};
+static_assert(sizeof(KeyboardModifier) == 0x4, "KeyboardModifier is an invalid size");
+
+// This is nn::hid::KeyboardKey
+struct KeyboardKey {
+ // This should be a 256 bit flag
+ std::array key;
+};
+static_assert(sizeof(KeyboardKey) == 0x20, "KeyboardKey is an invalid size");
+
+// This is nn::hid::MouseButton
+struct MouseButton {
+ union {
+ u32_le raw{};
+ BitField<0, 1, u32> left;
+ BitField<1, 1, u32> right;
+ BitField<2, 1, u32> middle;
+ BitField<3, 1, u32> forward;
+ BitField<4, 1, u32> back;
+ };
+};
+static_assert(sizeof(MouseButton) == 0x4, "MouseButton is an invalid size");
+
+// This is nn::hid::MouseAttribute
+struct MouseAttribute {
+ union {
+ u32_le raw{};
+ BitField<0, 1, u32> transferable;
+ BitField<1, 1, u32> is_connected;
+ };
+};
+static_assert(sizeof(MouseAttribute) == 0x4, "MouseAttribute is an invalid size");
+
+// This is nn::hid::detail::MouseState
+struct MouseState {
+ s64_le sampling_number;
+ s32_le x;
+ s32_le y;
+ s32_le delta_x;
+ s32_le delta_y;
+ s32_le delta_wheel_x;
+ s32_le delta_wheel_y;
+ MouseButton button;
+ MouseAttribute attribute;
+};
+static_assert(sizeof(MouseState) == 0x28, "MouseState is an invalid size");
+} // namespace Core::HID
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp
new file mode 100644
index 000000000..5834622e9
--- /dev/null
+++ b/src/core/hid/input_converter.cpp
@@ -0,0 +1,345 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#include
+
+#include "common/input.h"
+#include "core/hid/input_converter.h"
+
+namespace Core::HID {
+
+Input::BatteryStatus TransformToBattery(const Input::CallbackStatus& callback) {
+ Input::BatteryStatus battery{};
+ switch (callback.type) {
+ case Input::InputType::Analog:
+ case Input::InputType::Trigger: {
+ const auto value = TransformToTrigger(callback).analog.value;
+ battery = Input::BatteryLevel::Empty;
+ if (value > 0.2f) {
+ battery = Input::BatteryLevel::Critical;
+ }
+ if (value > 0.4f) {
+ battery = Input::BatteryLevel::Low;
+ }
+ if (value > 0.6f) {
+ battery = Input::BatteryLevel::Medium;
+ }
+ if (value > 0.8f) {
+ battery = Input::BatteryLevel::Full;
+ }
+ if (value >= 1.0f) {
+ battery = Input::BatteryLevel::Charging;
+ }
+ break;
+ }
+ case Input::InputType::Battery:
+ battery = callback.battery_status;
+ break;
+ default:
+ LOG_ERROR(Input, "Conversion from type {} to battery not implemented", callback.type);
+ break;
+ }
+
+ return battery;
+}
+
+Input::ButtonStatus TransformToButton(const Input::CallbackStatus& callback) {
+ Input::ButtonStatus status{};
+ switch (callback.type) {
+ case Input::InputType::Analog:
+ case Input::InputType::Trigger:
+ status.value = TransformToTrigger(callback).pressed;
+ break;
+ case Input::InputType::Button:
+ status = callback.button_status;
+ break;
+ default:
+ LOG_ERROR(Input, "Conversion from type {} to button not implemented", callback.type);
+ break;
+ }
+
+ if (status.inverted) {
+ status.value = !status.value;
+ }
+
+ return status;
+}
+
+Input::MotionStatus TransformToMotion(const Input::CallbackStatus& callback) {
+ Input::MotionStatus status{};
+ switch (callback.type) {
+ case Input::InputType::Button: {
+ if (TransformToButton(callback).value) {
+ std::random_device device;
+ std::mt19937 gen(device());
+ std::uniform_int_distribution distribution(-1000, 1000);
+ Input::AnalogProperties properties{
+ .deadzone = 0.0,
+ .range = 1.0f,
+ .offset = 0.0,
+ };
+ status.accel.x = {
+ .value = 0,
+ .raw_value = static_cast(distribution(gen)) * 0.001f,
+ .properties = properties,
+ };
+ status.accel.y = {
+ .value = 0,
+ .raw_value = static_cast(distribution(gen)) * 0.001f,
+ .properties = properties,
+ };
+ status.accel.z = {
+ .value = 0,
+ .raw_value = static_cast(distribution(gen)) * 0.001f,
+ .properties = properties,
+ };
+ status.gyro.x = {
+ .value = 0,
+ .raw_value = static_cast(distribution(gen)) * 0.001f,
+ .properties = properties,
+ };
+ status.gyro.y = {
+ .value = 0,
+ .raw_value = static_cast(distribution(gen)) * 0.001f,
+ .properties = properties,
+ };
+ status.gyro.z = {
+ .value = 0,
+ .raw_value = static_cast(distribution(gen)) * 0.001f,
+ .properties = properties,
+ };
+ }
+ break;
+ }
+ case Input::InputType::Motion:
+ status = callback.motion_status;
+ break;
+ default:
+ LOG_ERROR(Input, "Conversion from type {} to motion not implemented", callback.type);
+ break;
+ }
+ SanitizeAnalog(status.accel.x, false);
+ SanitizeAnalog(status.accel.y, false);
+ SanitizeAnalog(status.accel.z, false);
+ SanitizeAnalog(status.gyro.x, false);
+ SanitizeAnalog(status.gyro.y, false);
+ SanitizeAnalog(status.gyro.z, false);
+
+ return status;
+}
+
+Input::StickStatus TransformToStick(const Input::CallbackStatus& callback) {
+ Input::StickStatus status{};
+
+ switch (callback.type) {
+ case Input::InputType::Stick:
+ status = callback.stick_status;
+ break;
+ default:
+ LOG_ERROR(Input, "Conversion from type {} to stick not implemented", callback.type);
+ break;
+ }
+
+ SanitizeStick(status.x, status.y, true);
+ const Input::AnalogProperties& properties_x = status.x.properties;
+ const Input::AnalogProperties& properties_y = status.y.properties;
+ const float x = status.x.value;
+ const float y = status.y.value;
+
+ // Set directional buttons
+ status.right = x > properties_x.threshold;
+ status.left = x < -properties_x.threshold;
+ status.up = y > properties_y.threshold;
+ status.down = y < -properties_y.threshold;
+
+ return status;
+}
+
+Input::TouchStatus TransformToTouch(const Input::CallbackStatus& callback) {
+ Input::TouchStatus status{};
+
+ switch (callback.type) {
+ case Input::InputType::Touch:
+ status = callback.touch_status;
+ break;
+ default:
+ LOG_ERROR(Input, "Conversion from type {} to touch not implemented", callback.type);
+ break;
+ }
+
+ SanitizeAnalog(status.x, true);
+ SanitizeAnalog(status.y, true);
+ float& x = status.x.value;
+ float& y = status.y.value;
+
+ // Adjust if value is inverted
+ x = status.x.properties.inverted ? 1.0f + x : x;
+ y = status.y.properties.inverted ? 1.0f + y : y;
+
+ // clamp value
+ x = std::clamp(x, 0.0f, 1.0f);
+ y = std::clamp(y, 0.0f, 1.0f);
+
+ if (status.pressed.inverted) {
+ status.pressed.value = !status.pressed.value;
+ }
+
+ return status;
+}
+
+Input::TriggerStatus TransformToTrigger(const Input::CallbackStatus& callback) {
+ Input::TriggerStatus status{};
+ float& raw_value = status.analog.raw_value;
+ bool calculate_button_value = true;
+
+ switch (callback.type) {
+ case Input::InputType::Analog:
+ status.analog.properties = callback.analog_status.properties;
+ raw_value = callback.analog_status.raw_value;
+ break;
+ case Input::InputType::Button:
+ status.analog.properties.range = 1.0f;
+ status.analog.properties.inverted = callback.button_status.inverted;
+ raw_value = callback.button_status.value ? 1.0f : 0.0f;
+ break;
+ case Input::InputType::Trigger:
+ status = callback.trigger_status;
+ calculate_button_value = false;
+ break;
+ default:
+ LOG_ERROR(Input, "Conversion from type {} to trigger not implemented", callback.type);
+ break;
+ }
+
+ SanitizeAnalog(status.analog, true);
+ const Input::AnalogProperties& properties = status.analog.properties;
+ float& value = status.analog.value;
+
+ // Set button status
+ if (calculate_button_value) {
+ status.pressed = value > properties.threshold;
+ }
+
+ // Adjust if value is inverted
+ value = properties.inverted ? 1.0f + value : value;
+
+ // clamp value
+ value = std::clamp(value, 0.0f, 1.0f);
+
+ return status;
+}
+
+void SanitizeAnalog(Input::AnalogStatus& analog, bool clamp_value) {
+ const Input::AnalogProperties& properties = analog.properties;
+ float& raw_value = analog.raw_value;
+ float& value = analog.value;
+
+ if (!std::isnormal(raw_value)) {
+ raw_value = 0;
+ }
+
+ // Apply center offset
+ raw_value -= properties.offset;
+
+ // Set initial values to be formated
+ value = raw_value;
+
+ // Calculate vector size
+ const float r = std::abs(value);
+
+ // Return zero if value is smaller than the deadzone
+ if (r <= properties.deadzone || properties.deadzone == 1.0f) {
+ analog.value = 0;
+ return;
+ }
+
+ // Adjust range of value
+ const float deadzone_factor =
+ 1.0f / r * (r - properties.deadzone) / (1.0f - properties.deadzone);
+ value = value * deadzone_factor / properties.range;
+
+ // Invert direction if needed
+ if (properties.inverted) {
+ value = -value;
+ }
+
+ // Clamp value
+ if (clamp_value) {
+ value = std::clamp(value, -1.0f, 1.0f);
+ }
+}
+
+void SanitizeStick(Input::AnalogStatus& analog_x, Input::AnalogStatus& analog_y, bool clamp_value) {
+ const Input::AnalogProperties& properties_x = analog_x.properties;
+ const Input::AnalogProperties& properties_y = analog_y.properties;
+ float& raw_x = analog_x.raw_value;
+ float& raw_y = analog_y.raw_value;
+ float& x = analog_x.value;
+ float& y = analog_y.value;
+
+ if (!std::isnormal(raw_x)) {
+ raw_x = 0;
+ }
+ if (!std::isnormal(raw_y)) {
+ raw_y = 0;
+ }
+
+ // Apply center offset
+ raw_x += properties_x.offset;
+ raw_y += properties_y.offset;
+
+ // Apply X scale correction from offset
+ if (std::abs(properties_x.offset) < 0.5f) {
+ if (raw_x > 0) {
+ raw_x /= 1 + properties_x.offset;
+ } else {
+ raw_x /= 1 - properties_x.offset;
+ }
+ }
+
+ // Apply Y scale correction from offset
+ if (std::abs(properties_y.offset) < 0.5f) {
+ if (raw_y > 0) {
+ raw_y /= 1 + properties_y.offset;
+ } else {
+ raw_y /= 1 - properties_y.offset;
+ }
+ }
+
+ // Invert direction if needed
+ raw_x = properties_x.inverted ? -raw_x : raw_x;
+ raw_y = properties_y.inverted ? -raw_y : raw_y;
+
+ // Set initial values to be formated
+ x = raw_x;
+ y = raw_y;
+
+ // Calculate vector size
+ float r = x * x + y * y;
+ r = std::sqrt(r);
+
+ // TODO(German77): Use deadzone and range of both axis
+
+ // Return zero if values are smaller than the deadzone
+ if (r <= properties_x.deadzone || properties_x.deadzone >= 1.0f) {
+ x = 0;
+ y = 0;
+ return;
+ }
+
+ // Adjust range of joystick
+ const float deadzone_factor =
+ 1.0f / r * (r - properties_x.deadzone) / (1.0f - properties_x.deadzone);
+ x = x * deadzone_factor / properties_x.range;
+ y = y * deadzone_factor / properties_x.range;
+ r = r * deadzone_factor / properties_x.range;
+
+ // Normalize joystick
+ if (clamp_value && r > 1.0f) {
+ x /= r;
+ y /= r;
+ }
+}
+
+} // namespace Core::HID
diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h
new file mode 100644
index 000000000..3cc32e26a
--- /dev/null
+++ b/src/core/hid/input_converter.h
@@ -0,0 +1,77 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#pragma once
+
+namespace Input {
+struct CallbackStatus;
+};
+
+namespace Core::HID {
+
+/**
+ * Converts raw input data into a valid battery status.
+ *
+ * @param Supported callbacks: Analog, Battery, Trigger.
+ * @return A valid BatteryStatus object.
+ */
+Input::BatteryStatus TransformToBattery(const Input::CallbackStatus& callback);
+
+/**
+ * Converts raw input data into a valid button status. Applies invert properties to the output.
+ *
+ * @param Supported callbacks: Analog, Button, Trigger.
+ * @return A valid TouchStatus object.
+ */
+Input::ButtonStatus TransformToButton(const Input::CallbackStatus& callback);
+
+/**
+ * Converts raw input data into a valid motion status.
+ *
+ * @param Supported callbacks: Motion.
+ * @return A valid TouchStatus object.
+ */
+Input::MotionStatus TransformToMotion(const Input::CallbackStatus& callback);
+
+/**
+ * Converts raw input data into a valid stick status. Applies offset, deadzone, range and invert
+ * properties to the output.
+ *
+ * @param Supported callbacks: Stick.
+ * @return A valid StickStatus object.
+ */
+Input::StickStatus TransformToStick(const Input::CallbackStatus& callback);
+
+/**
+ * Converts raw input data into a valid touch status.
+ *
+ * @param Supported callbacks: Touch.
+ * @return A valid TouchStatus object.
+ */
+Input::TouchStatus TransformToTouch(const Input::CallbackStatus& callback);
+
+/**
+ * Converts raw input data into a valid trigger status. Applies offset, deadzone, range and
+ * invert properties to the output. Button status uses the threshold property if necessary.
+ *
+ * @param Supported callbacks: Analog, Button, Trigger.
+ * @return A valid TriggerStatus object.
+ */
+Input::TriggerStatus TransformToTrigger(const Input::CallbackStatus& callback);
+
+/**
+ * Converts raw analog data into a valid analog value
+ * @param An analog object containing raw data and properties, bool that determines if the value
+ * needs to be clamped between -1.0f and 1.0f.
+ */
+void SanitizeAnalog(Input::AnalogStatus& analog, bool clamp_value);
+
+/**
+ * Converts raw stick data into a valid stick value
+ * @param Two analog objects containing raw data and properties, bool that determines if the value
+ * needs to be clamped into the unit circle.
+ */
+void SanitizeStick(Input::AnalogStatus& analog_x, Input::AnalogStatus& analog_y, bool clamp_value);
+
+} // namespace Core::HID
diff --git a/src/core/hid/motion_input.cpp b/src/core/hid/motion_input.cpp
new file mode 100644
index 000000000..93f37b77b
--- /dev/null
+++ b/src/core/hid/motion_input.cpp
@@ -0,0 +1,278 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#include "common/math_util.h"
+#include "core/hid/motion_input.h"
+
+namespace Core::HID {
+
+MotionInput::MotionInput() {
+ // Initialize PID constants with default values
+ SetPID(0.3f, 0.005f, 0.0f);
+}
+
+void MotionInput::SetPID(f32 new_kp, f32 new_ki, f32 new_kd) {
+ kp = new_kp;
+ ki = new_ki;
+ kd = new_kd;
+}
+
+void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) {
+ accel = acceleration;
+}
+
+void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
+ gyro = gyroscope - gyro_drift;
+
+ // Auto adjust drift to minimize drift
+ if (!IsMoving(0.1f)) {
+ gyro_drift = (gyro_drift * 0.9999f) + (gyroscope * 0.0001f);
+ }
+
+ if (gyro.Length2() < gyro_threshold) {
+ gyro = {};
+ } else {
+ only_accelerometer = false;
+ }
+}
+
+void MotionInput::SetQuaternion(const Common::Quaternion& quaternion) {
+ quat = quaternion;
+}
+
+void MotionInput::SetGyroDrift(const Common::Vec3f& drift) {
+ gyro_drift = drift;
+}
+
+void MotionInput::SetGyroThreshold(f32 threshold) {
+ gyro_threshold = threshold;
+}
+
+void MotionInput::EnableReset(bool reset) {
+ reset_enabled = reset;
+}
+
+void MotionInput::ResetRotations() {
+ rotations = {};
+}
+
+bool MotionInput::IsMoving(f32 sensitivity) const {
+ return gyro.Length() >= sensitivity || accel.Length() <= 0.9f || accel.Length() >= 1.1f;
+}
+
+bool MotionInput::IsCalibrated(f32 sensitivity) const {
+ return real_error.Length() < sensitivity;
+}
+
+void MotionInput::UpdateRotation(u64 elapsed_time) {
+ const auto sample_period = static_cast(elapsed_time) / 1000000.0f;
+ if (sample_period > 0.1f) {
+ return;
+ }
+ rotations += gyro * sample_period;
+}
+
+void MotionInput::UpdateOrientation(u64 elapsed_time) {
+ if (!IsCalibrated(0.1f)) {
+ ResetOrientation();
+ }
+ // Short name local variable for readability
+ f32 q1 = quat.w;
+ f32 q2 = quat.xyz[0];
+ f32 q3 = quat.xyz[1];
+ f32 q4 = quat.xyz[2];
+ const auto sample_period = static_cast(elapsed_time) / 1000000.0f;
+
+ // Ignore invalid elapsed time
+ if (sample_period > 0.1f) {
+ return;
+ }
+
+ const auto normal_accel = accel.Normalized();
+ auto rad_gyro = gyro * Common::PI * 2;
+ const f32 swap = rad_gyro.x;
+ rad_gyro.x = rad_gyro.y;
+ rad_gyro.y = -swap;
+ rad_gyro.z = -rad_gyro.z;
+
+ // Clear gyro values if there is no gyro present
+ if (only_accelerometer) {
+ rad_gyro.x = 0;
+ rad_gyro.y = 0;
+ rad_gyro.z = 0;
+ }
+
+ // Ignore drift correction if acceleration is not reliable
+ if (accel.Length() >= 0.75f && accel.Length() <= 1.25f) {
+ const f32 ax = -normal_accel.x;
+ const f32 ay = normal_accel.y;
+ const f32 az = -normal_accel.z;
+
+ // Estimated direction of gravity
+ const f32 vx = 2.0f * (q2 * q4 - q1 * q3);
+ const f32 vy = 2.0f * (q1 * q2 + q3 * q4);
+ const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
+
+ // Error is cross product between estimated direction and measured direction of gravity
+ const Common::Vec3f new_real_error = {
+ az * vx - ax * vz,
+ ay * vz - az * vy,
+ ax * vy - ay * vx,
+ };
+
+ derivative_error = new_real_error - real_error;
+ real_error = new_real_error;
+
+ // Prevent integral windup
+ if (ki != 0.0f && !IsCalibrated(0.05f)) {
+ integral_error += real_error;
+ } else {
+ integral_error = {};
+ }
+
+ // Apply feedback terms
+ if (!only_accelerometer) {
+ rad_gyro += kp * real_error;
+ rad_gyro += ki * integral_error;
+ rad_gyro += kd * derivative_error;
+ } else {
+ // Give more weight to accelerometer values to compensate for the lack of gyro
+ rad_gyro += 35.0f * kp * real_error;
+ rad_gyro += 10.0f * ki * integral_error;
+ rad_gyro += 10.0f * kd * derivative_error;
+
+ // Emulate gyro values for games that need them
+ gyro.x = -rad_gyro.y;
+ gyro.y = rad_gyro.x;
+ gyro.z = -rad_gyro.z;
+ UpdateRotation(elapsed_time);
+ }
+ }
+
+ const f32 gx = rad_gyro.y;
+ const f32 gy = rad_gyro.x;
+ const f32 gz = rad_gyro.z;
+
+ // Integrate rate of change of quaternion
+ const f32 pa = q2;
+ const f32 pb = q3;
+ const f32 pc = q4;
+ q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * sample_period);
+ q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * sample_period);
+ q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * sample_period);
+ q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * sample_period);
+
+ quat.w = q1;
+ quat.xyz[0] = q2;
+ quat.xyz[1] = q3;
+ quat.xyz[2] = q4;
+ quat = quat.Normalized();
+}
+
+std::array MotionInput::GetOrientation() const {
+ const Common::Quaternion quad{
+ .xyz = {-quat.xyz[1], -quat.xyz[0], -quat.w},
+ .w = -quat.xyz[2],
+ };
+ const std::array matrix4x4 = quad.ToMatrix();
+
+ return {Common::Vec3f(matrix4x4[0], matrix4x4[1], -matrix4x4[2]),
+ Common::Vec3f(matrix4x4[4], matrix4x4[5], -matrix4x4[6]),
+ Common::Vec3f(-matrix4x4[8], -matrix4x4[9], matrix4x4[10])};
+}
+
+Common::Vec3f MotionInput::GetAcceleration() const {
+ return accel;
+}
+
+Common::Vec3f MotionInput::GetGyroscope() const {
+ return gyro;
+}
+
+Common::Quaternion MotionInput::GetQuaternion() const {
+ return quat;
+}
+
+Common::Vec3f MotionInput::GetRotations() const {
+ return rotations;
+}
+
+void MotionInput::ResetOrientation() {
+ if (!reset_enabled || only_accelerometer) {
+ return;
+ }
+ if (!IsMoving(0.5f) && accel.z <= -0.9f) {
+ ++reset_counter;
+ if (reset_counter > 900) {
+ quat.w = 0;
+ quat.xyz[0] = 0;
+ quat.xyz[1] = 0;
+ quat.xyz[2] = -1;
+ SetOrientationFromAccelerometer();
+ integral_error = {};
+ reset_counter = 0;
+ }
+ } else {
+ reset_counter = 0;
+ }
+}
+
+void MotionInput::SetOrientationFromAccelerometer() {
+ int iterations = 0;
+ const f32 sample_period = 0.015f;
+
+ const auto normal_accel = accel.Normalized();
+
+ while (!IsCalibrated(0.01f) && ++iterations < 100) {
+ // Short name local variable for readability
+ f32 q1 = quat.w;
+ f32 q2 = quat.xyz[0];
+ f32 q3 = quat.xyz[1];
+ f32 q4 = quat.xyz[2];
+
+ Common::Vec3f rad_gyro;
+ const f32 ax = -normal_accel.x;
+ const f32 ay = normal_accel.y;
+ const f32 az = -normal_accel.z;
+
+ // Estimated direction of gravity
+ const f32 vx = 2.0f * (q2 * q4 - q1 * q3);
+ const f32 vy = 2.0f * (q1 * q2 + q3 * q4);
+ const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
+
+ // Error is cross product between estimated direction and measured direction of gravity
+ const Common::Vec3f new_real_error = {
+ az * vx - ax * vz,
+ ay * vz - az * vy,
+ ax * vy - ay * vx,
+ };
+
+ derivative_error = new_real_error - real_error;
+ real_error = new_real_error;
+
+ rad_gyro += 10.0f * kp * real_error;
+ rad_gyro += 5.0f * ki * integral_error;
+ rad_gyro += 10.0f * kd * derivative_error;
+
+ const f32 gx = rad_gyro.y;
+ const f32 gy = rad_gyro.x;
+ const f32 gz = rad_gyro.z;
+
+ // Integrate rate of change of quaternion
+ const f32 pa = q2;
+ const f32 pb = q3;
+ const f32 pc = q4;
+ q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * sample_period);
+ q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * sample_period);
+ q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * sample_period);
+ q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * sample_period);
+
+ quat.w = q1;
+ quat.xyz[0] = q2;
+ quat.xyz[1] = q3;
+ quat.xyz[2] = q4;
+ quat = quat.Normalized();
+ }
+}
+} // namespace Core::HID
diff --git a/src/core/hid/motion_input.h b/src/core/hid/motion_input.h
new file mode 100644
index 000000000..3deef5ac3
--- /dev/null
+++ b/src/core/hid/motion_input.h
@@ -0,0 +1,71 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#pragma once
+
+#include "common/common_types.h"
+#include "common/quaternion.h"
+#include "common/vector_math.h"
+
+namespace Core::HID {
+
+class MotionInput {
+public:
+ explicit MotionInput();
+
+ MotionInput(const MotionInput&) = default;
+ MotionInput& operator=(const MotionInput&) = default;
+
+ MotionInput(MotionInput&&) = default;
+ MotionInput& operator=(MotionInput&&) = default;
+
+ void SetPID(f32 new_kp, f32 new_ki, f32 new_kd);
+ void SetAcceleration(const Common::Vec3f& acceleration);
+ void SetGyroscope(const Common::Vec3f& gyroscope);
+ void SetQuaternion(const Common::Quaternion& quaternion);
+ void SetGyroDrift(const Common::Vec3f& drift);
+ void SetGyroThreshold(f32 threshold);
+
+ void EnableReset(bool reset);
+ void ResetRotations();
+
+ void UpdateRotation(u64 elapsed_time);
+ void UpdateOrientation(u64 elapsed_time);
+
+ [[nodiscard]] std::array GetOrientation() const;
+ [[nodiscard]] Common::Vec3f GetAcceleration() const;
+ [[nodiscard]] Common::Vec3f GetGyroscope() const;
+ [[nodiscard]] Common::Vec3f GetRotations() const;
+ [[nodiscard]] Common::Quaternion GetQuaternion() const;
+
+ [[nodiscard]] bool IsMoving(f32 sensitivity) const;
+ [[nodiscard]] bool IsCalibrated(f32 sensitivity) const;
+
+private:
+ void ResetOrientation();
+ void SetOrientationFromAccelerometer();
+
+ // PID constants
+ f32 kp;
+ f32 ki;
+ f32 kd;
+
+ // PID errors
+ Common::Vec3f real_error;
+ Common::Vec3f integral_error;
+ Common::Vec3f derivative_error;
+
+ Common::Quaternion quat{{0.0f, 0.0f, -1.0f}, 0.0f};
+ Common::Vec3f rotations;
+ Common::Vec3f accel;
+ Common::Vec3f gyro;
+ Common::Vec3f gyro_drift;
+
+ f32 gyro_threshold = 0.0f;
+ u32 reset_counter = 0;
+ bool reset_enabled = true;
+ bool only_accelerometer = true;
+};
+
+} // namespace Core::HID
--
cgit v1.2.3
From ea7b1fbc673e40d5e51f2d185ebe8542741164fa Mon Sep 17 00:00:00 2001
From: german77
Date: Mon, 20 Sep 2021 16:34:05 -0500
Subject: input_common: Create input_engine
---
src/input_common/input_engine.cpp | 361 ++++++++++++++++++++++++++++++++++++++
src/input_common/input_engine.h | 224 +++++++++++++++++++++++
2 files changed, 585 insertions(+)
create mode 100644 src/input_common/input_engine.cpp
create mode 100644 src/input_common/input_engine.h
(limited to 'src')
diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp
new file mode 100644
index 000000000..1534f24b0
--- /dev/null
+++ b/src/input_common/input_engine.cpp
@@ -0,0 +1,361 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#include "common/logging/log.h"
+#include "common/param_package.h"
+#include "input_common/input_engine.h"
+
+namespace InputCommon {
+
+void InputEngine::PreSetController(const PadIdentifier& identifier) {
+ std::lock_guard lock{mutex};
+ if (!controller_list.contains(identifier)) {
+ controller_list.insert_or_assign(identifier, ControllerData{});
+ }
+}
+
+void InputEngine::PreSetButton(const PadIdentifier& identifier, int button) {
+ std::lock_guard lock{mutex};
+ ControllerData& controller = controller_list.at(identifier);
+ if (!controller.buttons.contains(button)) {
+ controller.buttons.insert_or_assign(button, false);
+ }
+}
+
+void InputEngine::PreSetHatButton(const PadIdentifier& identifier, int button) {
+ std::lock_guard lock{mutex};
+ ControllerData& controller = controller_list.at(identifier);
+ if (!controller.hat_buttons.contains(button)) {
+ controller.hat_buttons.insert_or_assign(button, u8{0});
+ }
+}
+
+void InputEngine::PreSetAxis(const PadIdentifier& identifier, int axis) {
+ std::lock_guard lock{mutex};
+ ControllerData& controller = controller_list.at(identifier);
+ if (!controller.axes.contains(axis)) {
+ controller.axes.insert_or_assign(axis, 0.0f);
+ }
+}
+
+void InputEngine::PreSetMotion(const PadIdentifier& identifier, int motion) {
+ std::lock_guard lock{mutex};
+ ControllerData& controller = controller_list.at(identifier);
+ if (!controller.motions.contains(motion)) {
+ controller.motions.insert_or_assign(motion, BasicMotion{});
+ }
+}
+
+void InputEngine::SetButton(const PadIdentifier& identifier, int button, bool value) {
+ {
+ std::lock_guard lock{mutex};
+ ControllerData& controller = controller_list.at(identifier);
+ if (!configuring) {
+ controller.buttons.insert_or_assign(button, value);
+ }
+ }
+ TriggerOnButtonChange(identifier, button, value);
+}
+
+void InputEngine::SetHatButton(const PadIdentifier& identifier, int button, u8 value) {
+ {
+ std::lock_guard lock{mutex};
+ ControllerData& controller = controller_list.at(identifier);
+ if (!configuring) {
+ controller.hat_buttons.insert_or_assign(button, value);
+ }
+ }
+ TriggerOnHatButtonChange(identifier, button, value);
+}
+
+void InputEngine::SetAxis(const PadIdentifier& identifier, int axis, f32 value) {
+ {
+ std::lock_guard lock{mutex};
+ ControllerData& controller = controller_list.at(identifier);
+ if (!configuring) {
+ controller.axes.insert_or_assign(axis, value);
+ }
+ }
+ TriggerOnAxisChange(identifier, axis, value);
+}
+
+void InputEngine::SetBattery(const PadIdentifier& identifier, BatteryLevel value) {
+ {
+ std::lock_guard lock{mutex};
+ ControllerData& controller = controller_list.at(identifier);
+ if (!configuring) {
+ controller.battery = value;
+ }
+ }
+ TriggerOnBatteryChange(identifier, value);
+}
+
+void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value) {
+ {
+ std::lock_guard lock{mutex};
+ ControllerData& controller = controller_list.at(identifier);
+ if (!configuring) {
+ controller.motions.insert_or_assign(motion, value);
+ }
+ }
+ TriggerOnMotionChange(identifier, motion, value);
+}
+
+bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const {
+ std::lock_guard lock{mutex};
+ if (!controller_list.contains(identifier)) {
+ LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
+ identifier.pad, identifier.port);
+ return false;
+ }
+ ControllerData controller = controller_list.at(identifier);
+ if (!controller.buttons.contains(button)) {
+ LOG_ERROR(Input, "Invalid button {}", button);
+ return false;
+ }
+ return controller.buttons.at(button);
+}
+
+bool InputEngine::GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const {
+ std::lock_guard lock{mutex};
+ if (!controller_list.contains(identifier)) {
+ LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
+ identifier.pad, identifier.port);
+ return false;
+ }
+ ControllerData controller = controller_list.at(identifier);
+ if (!controller.hat_buttons.contains(button)) {
+ LOG_ERROR(Input, "Invalid hat button {}", button);
+ return false;
+ }
+ return (controller.hat_buttons.at(button) & direction) != 0;
+}
+
+f32 InputEngine::GetAxis(const PadIdentifier& identifier, int axis) const {
+ std::lock_guard lock{mutex};
+ if (!controller_list.contains(identifier)) {
+ LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
+ identifier.pad, identifier.port);
+ return 0.0f;
+ }
+ ControllerData controller = controller_list.at(identifier);
+ if (!controller.axes.contains(axis)) {
+ LOG_ERROR(Input, "Invalid axis {}", axis);
+ return 0.0f;
+ }
+ return controller.axes.at(axis);
+}
+
+BatteryLevel InputEngine::GetBattery(const PadIdentifier& identifier) const {
+ std::lock_guard lock{mutex};
+ if (!controller_list.contains(identifier)) {
+ LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
+ identifier.pad, identifier.port);
+ return BatteryLevel::Charging;
+ }
+ ControllerData controller = controller_list.at(identifier);
+ return controller.battery;
+}
+
+BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) const {
+ std::lock_guard lock{mutex};
+ if (!controller_list.contains(identifier)) {
+ LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
+ identifier.pad, identifier.port);
+ return {};
+ }
+ ControllerData controller = controller_list.at(identifier);
+ return controller.motions.at(motion);
+}
+
+void InputEngine::ResetButtonState() {
+ for (std::pair controller : controller_list) {
+ for (std::pair button : controller.second.buttons) {
+ SetButton(controller.first, button.first, false);
+ }
+ for (std::pair button : controller.second.hat_buttons) {
+ SetHatButton(controller.first, button.first, false);
+ }
+ }
+}
+
+void InputEngine::ResetAnalogState() {
+ for (std::pair controller : controller_list) {
+ for (std::pair axis : controller.second.axes) {
+ SetAxis(controller.first, axis.first, 0.0);
+ }
+ }
+}
+
+void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value) {
+ std::lock_guard lock{mutex_callback};
+ for (const std::pair poller_pair : callback_list) {
+ const InputIdentifier& poller = poller_pair.second;
+ if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Button, button)) {
+ continue;
+ }
+ if (poller.callback.on_change) {
+ poller.callback.on_change();
+ }
+ }
+ if (!configuring || !mapping_callback.on_data) {
+ return;
+ }
+ if (value == GetButton(identifier, button)) {
+ return;
+ }
+ mapping_callback.on_data(MappingData{
+ .engine = GetEngineName(),
+ .pad = identifier,
+ .type = EngineInputType::Button,
+ .index = button,
+ .button_value = value,
+ });
+}
+
+void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value) {
+ std::lock_guard lock{mutex_callback};
+ for (const std::pair poller_pair : callback_list) {
+ const InputIdentifier& poller = poller_pair.second;
+ if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::HatButton, button)) {
+ continue;
+ }
+ if (poller.callback.on_change) {
+ poller.callback.on_change();
+ }
+ }
+ if (!configuring || !mapping_callback.on_data) {
+ return;
+ }
+ for (std::size_t index = 1; index < 0xff; index <<= 1) {
+ bool button_value = (value & index) != 0;
+ if (button_value == GetHatButton(identifier, button, static_cast(index))) {
+ continue;
+ }
+ mapping_callback.on_data(MappingData{
+ .engine = GetEngineName(),
+ .pad = identifier,
+ .type = EngineInputType::HatButton,
+ .index = button,
+ .hat_name = GetHatButtonName(static_cast(index)),
+ });
+ }
+}
+
+void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value) {
+ std::lock_guard lock{mutex_callback};
+ for (const std::pair poller_pair : callback_list) {
+ const InputIdentifier& poller = poller_pair.second;
+ if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Analog, axis)) {
+ continue;
+ }
+ if (poller.callback.on_change) {
+ poller.callback.on_change();
+ }
+ }
+ if (!configuring || !mapping_callback.on_data) {
+ return;
+ }
+ if (std::abs(value - GetAxis(identifier, axis)) < 0.5f) {
+ return;
+ }
+ mapping_callback.on_data(MappingData{
+ .engine = GetEngineName(),
+ .pad = identifier,
+ .type = EngineInputType::Analog,
+ .index = axis,
+ .axis_value = value,
+ });
+}
+
+void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,
+ [[maybe_unused]] BatteryLevel value) {
+ std::lock_guard lock{mutex_callback};
+ for (const std::pair poller_pair : callback_list) {
+ const InputIdentifier& poller = poller_pair.second;
+ if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Battery, 0)) {
+ continue;
+ }
+ if (poller.callback.on_change) {
+ poller.callback.on_change();
+ }
+ }
+}
+
+void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion,
+ BasicMotion value) {
+ std::lock_guard lock{mutex_callback};
+ for (const std::pair poller_pair : callback_list) {
+ const InputIdentifier& poller = poller_pair.second;
+ if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Motion, motion)) {
+ continue;
+ }
+ if (poller.callback.on_change) {
+ poller.callback.on_change();
+ }
+ }
+ if (!configuring || !mapping_callback.on_data) {
+ return;
+ }
+ if (std::abs(value.gyro_x) < 1.0f && std::abs(value.gyro_y) < 1.0f &&
+ std::abs(value.gyro_z) < 1.0f) {
+ return;
+ }
+ mapping_callback.on_data(MappingData{
+ .engine = GetEngineName(),
+ .pad = identifier,
+ .type = EngineInputType::Motion,
+ .index = motion,
+ .motion_value = value,
+ });
+}
+
+bool InputEngine::IsInputIdentifierEqual(const InputIdentifier& input_identifier,
+ const PadIdentifier& identifier, EngineInputType type,
+ std::size_t index) const {
+ if (input_identifier.type != type) {
+ return false;
+ }
+ if (input_identifier.index != index) {
+ return false;
+ }
+ if (input_identifier.identifier != identifier) {
+ return false;
+ }
+ return true;
+}
+
+void InputEngine::BeginConfiguration() {
+ configuring = true;
+}
+
+void InputEngine::EndConfiguration() {
+ configuring = false;
+}
+
+const std::string& InputEngine::GetEngineName() const {
+ return input_engine;
+}
+
+int InputEngine::SetCallback(InputIdentifier input_identifier) {
+ std::lock_guard lock{mutex_callback};
+ callback_list.insert_or_assign(last_callback_key, input_identifier);
+ return last_callback_key++;
+}
+
+void InputEngine::SetMappingCallback(MappingCallback callback) {
+ std::lock_guard lock{mutex_callback};
+ mapping_callback = std::move(callback);
+}
+
+void InputEngine::DeleteCallback(int key) {
+ std::lock_guard lock{mutex_callback};
+ if (!callback_list.contains(key)) {
+ LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
+ return;
+ }
+ callback_list.erase(key);
+}
+
+} // namespace InputCommon
diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h
new file mode 100644
index 000000000..86a8e00d8
--- /dev/null
+++ b/src/input_common/input_engine.h
@@ -0,0 +1,224 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#pragma once
+
+#include
+#include
+#include
+
+#include "common/common_types.h"
+#include "common/input.h"
+#include "common/param_package.h"
+#include "common/uuid.h"
+#include "input_common/main.h"
+
+// Pad Identifier of data source
+struct PadIdentifier {
+ Common::UUID guid{};
+ std::size_t port{};
+ std::size_t pad{};
+
+ friend constexpr bool operator==(const PadIdentifier&, const PadIdentifier&) = default;
+};
+
+// Basic motion data containing data from the sensors and a timestamp in microsecons
+struct BasicMotion {
+ float gyro_x;
+ float gyro_y;
+ float gyro_z;
+ float accel_x;
+ float accel_y;
+ float accel_z;
+ u64 delta_timestamp;
+};
+
+// Stages of a battery charge
+enum class BatteryLevel {
+ Empty,
+ Critical,
+ Low,
+ Medium,
+ Full,
+ Charging,
+};
+
+// Types of input that are stored in the engine
+enum class EngineInputType {
+ None,
+ Button,
+ HatButton,
+ Analog,
+ Motion,
+ Battery,
+};
+
+namespace std {
+// Hash used to create lists from PadIdentifier data
+template <>
+struct hash {
+ size_t operator()(const PadIdentifier& pad_id) const noexcept {
+ u64 hash_value = pad_id.guid.uuid[1] ^ pad_id.guid.uuid[0];
+ hash_value ^= (static_cast(pad_id.port) << 32);
+ hash_value ^= static_cast(pad_id.pad);
+ return static_cast(hash_value);
+ }
+};
+
+} // namespace std
+
+namespace InputCommon {
+
+// Data from the engine and device needed for creating a ParamPackage
+struct MappingData {
+ std::string engine{};
+ PadIdentifier pad{};
+ EngineInputType type{};
+ int index{};
+ bool button_value{};
+ std::string hat_name{};
+ f32 axis_value{};
+ BasicMotion motion_value{};
+};
+
+// Triggered if data changed on the controller
+struct UpdateCallback {
+ std::function on_change;
+};
+
+// Triggered if data changed on the controller and the engine is on configuring mode
+struct MappingCallback {
+ std::function on_data;
+};
+
+// Input Identifier of data source
+struct InputIdentifier {
+ PadIdentifier identifier;
+ EngineInputType type;
+ std::size_t index;
+ UpdateCallback callback;
+};
+
+class InputEngine {
+public:
+ explicit InputEngine(const std::string& input_engine_) : input_engine(input_engine_) {
+ callback_list.clear();
+ }
+
+ virtual ~InputEngine() = default;
+
+ // Enable configuring mode for mapping
+ void BeginConfiguration();
+
+ // Disable configuring mode for mapping
+ void EndConfiguration();
+
+ // Sets rumble to a controller
+ virtual bool SetRumble([[maybe_unused]] const PadIdentifier& identifier,
+ [[maybe_unused]] const Input::VibrationStatus vibration) {
+ return false;
+ }
+
+ // Sets a led pattern for a controller
+ virtual void SetLeds([[maybe_unused]] const PadIdentifier& identifier,
+ [[maybe_unused]] const Input::LedStatus led_status) {
+ return;
+ }
+
+ // Returns the engine name
+ [[nodiscard]] const std::string& GetEngineName() const;
+
+ /// Used for automapping features
+ virtual std::vector GetInputDevices() const {
+ return {};
+ };
+
+ /// Retrieves the button mappings for the given device
+ virtual InputCommon::ButtonMapping GetButtonMappingForDevice(
+ [[maybe_unused]] const Common::ParamPackage& params) {
+ return {};
+ };
+
+ /// Retrieves the analog mappings for the given device
+ virtual InputCommon::AnalogMapping GetAnalogMappingForDevice(
+ [[maybe_unused]] const Common::ParamPackage& params) {
+ return {};
+ };
+
+ /// Retrieves the motion mappings for the given device
+ virtual InputCommon::MotionMapping GetMotionMappingForDevice(
+ [[maybe_unused]] const Common::ParamPackage& params) {
+ return {};
+ };
+
+ /// Retrieves the name of the given input.
+ virtual std::string GetUIName([[maybe_unused]] const Common::ParamPackage& params) const {
+ return GetEngineName();
+ };
+
+ /// Retrieves the index number of the given hat button direction
+ virtual u8 GetHatButtonId([[maybe_unused]] const std::string direction_name) const {
+ return 0;
+ };
+
+ void PreSetController(const PadIdentifier& identifier);
+ void PreSetButton(const PadIdentifier& identifier, int button);
+ void PreSetHatButton(const PadIdentifier& identifier, int button);
+ void PreSetAxis(const PadIdentifier& identifier, int axis);
+ void PreSetMotion(const PadIdentifier& identifier, int motion);
+ void ResetButtonState();
+ void ResetAnalogState();
+
+ bool GetButton(const PadIdentifier& identifier, int button) const;
+ bool GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const;
+ f32 GetAxis(const PadIdentifier& identifier, int axis) const;
+ BatteryLevel GetBattery(const PadIdentifier& identifier) const;
+ BasicMotion GetMotion(const PadIdentifier& identifier, int motion) const;
+
+ int SetCallback(InputIdentifier input_identifier);
+ void SetMappingCallback(MappingCallback callback);
+ void DeleteCallback(int key);
+
+protected:
+ void SetButton(const PadIdentifier& identifier, int button, bool value);
+ void SetHatButton(const PadIdentifier& identifier, int button, u8 value);
+ void SetAxis(const PadIdentifier& identifier, int axis, f32 value);
+ void SetBattery(const PadIdentifier& identifier, BatteryLevel value);
+ void SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value);
+
+ virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const {
+ return "Unknown";
+ }
+
+private:
+ struct ControllerData {
+ std::unordered_map buttons;
+ std::unordered_map hat_buttons;
+ std::unordered_map axes;
+ std::unordered_map motions;
+ BatteryLevel battery;
+ };
+
+ void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value);
+ void TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value);
+ void TriggerOnAxisChange(const PadIdentifier& identifier, int button, f32 value);
+ void TriggerOnBatteryChange(const PadIdentifier& identifier, BatteryLevel value);
+ void TriggerOnMotionChange(const PadIdentifier& identifier, int motion, BasicMotion value);
+
+ bool IsInputIdentifierEqual(const InputIdentifier& input_identifier,
+ const PadIdentifier& identifier, EngineInputType type,
+ std::size_t index) const;
+
+ mutable std::mutex mutex;
+ mutable std::mutex mutex_callback;
+ bool configuring{false};
+ bool is_callback_enabled{true};
+ const std::string input_engine;
+ int last_callback_key = 0;
+ std::unordered_map controller_list;
+ std::unordered_map callback_list;
+ MappingCallback mapping_callback;
+};
+
+} // namespace InputCommon
--
cgit v1.2.3
From 854c933716f0f5e1dbf62157c5a76e65213b30b2 Mon Sep 17 00:00:00 2001
From: german77
Date: Mon, 20 Sep 2021 16:41:15 -0500
Subject: input_common: Create input poller and mapping
---
src/input_common/CMakeLists.txt | 6 +
src/input_common/input_mapping.cpp | 171 ++++++++
src/input_common/input_mapping.h | 76 ++++
src/input_common/input_poller.cpp | 860 +++++++++++++++++++++++++++++++++++++
src/input_common/input_poller.h | 189 ++++++++
src/input_common/main.h | 3 +
6 files changed, 1305 insertions(+)
create mode 100644 src/input_common/input_mapping.cpp
create mode 100644 src/input_common/input_mapping.h
create mode 100644 src/input_common/input_poller.cpp
create mode 100644 src/input_common/input_poller.h
(limited to 'src')
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index dd13d948f..72f1e0f4a 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -3,6 +3,12 @@ add_library(input_common STATIC
analog_from_button.h
keyboard.cpp
keyboard.h
+ input_engine.cpp
+ input_engine.h
+ input_mapping.cpp
+ input_mapping.h
+ input_poller.cpp
+ input_poller.h
main.cpp
main.h
motion_from_button.cpp
diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp
new file mode 100644
index 000000000..0ffc71028
--- /dev/null
+++ b/src/input_common/input_mapping.cpp
@@ -0,0 +1,171 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#include "common/common_types.h"
+#include "input_common/input_engine.h"
+#include "input_common/input_mapping.h"
+
+namespace InputCommon {
+
+MappingFactory::MappingFactory() {}
+
+void MappingFactory::BeginMapping(Polling::InputType type) {
+ is_enabled = true;
+ input_type = type;
+ input_queue.Clear();
+ first_axis = -1;
+ second_axis = -1;
+}
+
+[[nodiscard]] const Common::ParamPackage MappingFactory::GetNextInput() {
+ Common::ParamPackage input;
+ input_queue.Pop(input);
+ return input;
+}
+
+void MappingFactory::RegisterInput(const MappingData& data) {
+ if (!is_enabled) {
+ return;
+ }
+ switch (input_type) {
+ case Polling::InputType::Button:
+ RegisterButton(data);
+ return;
+ case Polling::InputType::Stick:
+ RegisterStick(data);
+ return;
+ case Polling::InputType::Motion:
+ RegisterMotion(data);
+ return;
+ default:
+ return;
+ }
+}
+
+void MappingFactory::StopMapping() {
+ is_enabled = false;
+ input_type = Polling::InputType::None;
+ input_queue.Clear();
+}
+
+void MappingFactory::RegisterButton(const MappingData& data) {
+ Common::ParamPackage new_input;
+ new_input.Set("engine", data.engine);
+ if (data.pad.guid != Common::UUID{}) {
+ new_input.Set("guid", data.pad.guid.Format());
+ }
+ new_input.Set("port", static_cast(data.pad.port));
+ new_input.Set("pad", static_cast(data.pad.pad));
+ switch (data.type) {
+ case EngineInputType::Button:
+ // Workaround for old compatibility
+ if (data.engine == "keyboard") {
+ new_input.Set("code", data.index);
+ break;
+ }
+ new_input.Set("button", data.index);
+ break;
+ case EngineInputType::HatButton:
+ new_input.Set("hat", data.index);
+ new_input.Set("direction", data.hat_name);
+ break;
+ case EngineInputType::Analog:
+ new_input.Set("axis", data.index);
+ new_input.Set("threshold", 0.5f);
+ break;
+ default:
+ return;
+ }
+ input_queue.Push(new_input);
+}
+
+void MappingFactory::RegisterStick(const MappingData& data) {
+ Common::ParamPackage new_input;
+ new_input.Set("engine", data.engine);
+ if (data.pad.guid != Common::UUID{}) {
+ new_input.Set("guid", data.pad.guid.Format());
+ }
+ new_input.Set("port", static_cast(data.pad.port));
+ new_input.Set("pad", static_cast(data.pad.pad));
+
+ // If engine is mouse map the mouse position as a joystick
+ if (data.engine == "mouse") {
+ new_input.Set("axis_x", 0);
+ new_input.Set("axis_y", 1);
+ new_input.Set("threshold", 0.5f);
+ new_input.Set("range", 1.0f);
+ new_input.Set("deadzone", 0.0f);
+ input_queue.Push(new_input);
+ return;
+ }
+
+ switch (data.type) {
+ case EngineInputType::Button:
+ case EngineInputType::HatButton:
+ RegisterButton(data);
+ return;
+ case EngineInputType::Analog:
+ if (first_axis == data.index) {
+ return;
+ }
+ if (first_axis == -1) {
+ first_axis = data.index;
+ return;
+ }
+ new_input.Set("axis_x", first_axis);
+ new_input.Set("axis_y", data.index);
+ new_input.Set("threshold", 0.5f);
+ new_input.Set("range", 0.95f);
+ new_input.Set("deadzone", 0.15f);
+ break;
+ default:
+ return;
+ }
+ input_queue.Push(new_input);
+}
+
+void MappingFactory::RegisterMotion(const MappingData& data) {
+ Common::ParamPackage new_input;
+ new_input.Set("engine", data.engine);
+ if (data.pad.guid != Common::UUID{}) {
+ new_input.Set("guid", data.pad.guid.Format());
+ }
+ new_input.Set("port", static_cast(data.pad.port));
+ new_input.Set("pad", static_cast(data.pad.pad));
+ switch (data.type) {
+ case EngineInputType::Button:
+ case EngineInputType::HatButton:
+ RegisterButton(data);
+ return;
+ case EngineInputType::Analog:
+ if (first_axis == data.index) {
+ return;
+ }
+ if (second_axis == data.index) {
+ return;
+ }
+ if (first_axis == -1) {
+ first_axis = data.index;
+ return;
+ }
+ if (second_axis == -1) {
+ second_axis = data.index;
+ return;
+ }
+ new_input.Set("axis_x", first_axis);
+ new_input.Set("axis_y", second_axis);
+ new_input.Set("axis_z", data.index);
+ new_input.Set("range", 1.0f);
+ new_input.Set("deadzone", 0.20f);
+ break;
+ case EngineInputType::Motion:
+ new_input.Set("motion", data.index);
+ break;
+ default:
+ return;
+ }
+ input_queue.Push(new_input);
+}
+
+} // namespace InputCommon
diff --git a/src/input_common/input_mapping.h b/src/input_common/input_mapping.h
new file mode 100644
index 000000000..2622dba70
--- /dev/null
+++ b/src/input_common/input_mapping.h
@@ -0,0 +1,76 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#pragma once
+#include "common/threadsafe_queue.h"
+
+namespace InputCommon {
+class InputEngine;
+struct MappingData;
+
+class MappingFactory {
+public:
+ MappingFactory();
+
+ /**
+ * Resets all varables to beggin the mapping process
+ * @param "type": type of input desired to be returned
+ */
+ void BeginMapping(Polling::InputType type);
+
+ /// Returns an input event with mapping information from the input_queue
+ [[nodiscard]] const Common::ParamPackage GetNextInput();
+
+ /**
+ * Registers mapping input data from the driver
+ * @param "data": An struct containing all the information needed to create a proper
+ * ParamPackage
+ */
+ void RegisterInput(const MappingData& data);
+
+ /// Stop polling from all backends
+ void StopMapping();
+
+private:
+ /**
+ * If provided data satisfies the requeriments it will push an element to the input_queue
+ * Supported input:
+ * - Button: Creates a basic button ParamPackage
+ * - HatButton: Creates a basic hat button ParamPackage
+ * - Analog: Creates a basic analog ParamPackage
+ * @param "data": An struct containing all the information needed to create a proper
+ * ParamPackage
+ */
+ void RegisterButton(const MappingData& data);
+
+ /**
+ * If provided data satisfies the requeriments it will push an element to the input_queue
+ * Supported input:
+ * - Button, HatButton: Pass the data to RegisterButton
+ * - Analog: Stores the first axis and on the second axis creates a basic stick ParamPackage
+ * @param "data": An struct containing all the information needed to create a proper
+ * ParamPackage
+ */
+ void RegisterStick(const MappingData& data);
+
+ /**
+ * If provided data satisfies the requeriments it will push an element to the input_queue
+ * Supported input:
+ * - Button, HatButton: Pass the data to RegisterButton
+ * - Analog: Stores the first two axis and on the third axis creates a basic Motion
+ * ParamPackage
+ * - Motion: Creates a basic Motion ParamPackage
+ * @param "data": An struct containing all the information needed to create a proper
+ * ParamPackage
+ */
+ void RegisterMotion(const MappingData& data);
+
+ Common::SPSCQueue input_queue;
+ Polling::InputType input_type{Polling::InputType::None};
+ bool is_enabled{};
+ int first_axis = -1;
+ int second_axis = -1;
+};
+
+} // namespace InputCommon
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp
new file mode 100644
index 000000000..46a7dd276
--- /dev/null
+++ b/src/input_common/input_poller.cpp
@@ -0,0 +1,860 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#include "common/common_types.h"
+#include "common/input.h"
+
+#include "input_common/input_engine.h"
+#include "input_common/input_poller.h"
+
+namespace InputCommon {
+
+class DummyInput final : public Input::InputDevice {
+public:
+ explicit DummyInput() {}
+ ~DummyInput() {}
+};
+
+class InputFromButton final : public Input::InputDevice {
+public:
+ explicit InputFromButton(PadIdentifier identifier_, u32 button_, bool toggle_, bool inverted_,
+ InputEngine* input_engine_)
+ : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_),
+ input_engine(input_engine_) {
+ UpdateCallback engine_callback{[this]() { OnChange(); }};
+ const InputIdentifier input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::Button,
+ .index = button,
+ .callback = engine_callback,
+ };
+ last_button_value = false;
+ callback_key = input_engine->SetCallback(input_identifier);
+ }
+
+ ~InputFromButton() {
+ input_engine->DeleteCallback(callback_key);
+ }
+
+ Input::ButtonStatus GetStatus() const {
+ return {
+ .value = input_engine->GetButton(identifier, button),
+ .inverted = inverted,
+ .toggle = toggle,
+ };
+ }
+
+ void OnChange() {
+ const Input::CallbackStatus status{
+ .type = Input::InputType::Button,
+ .button_status = GetStatus(),
+ };
+
+ if (status.button_status.value != last_button_value) {
+ last_button_value = status.button_status.value;
+ TriggerOnChange(status);
+ }
+ }
+
+private:
+ const PadIdentifier identifier;
+ const u32 button;
+ const bool toggle;
+ const bool inverted;
+ int callback_key;
+ bool last_button_value;
+ InputEngine* input_engine;
+};
+
+class InputFromHatButton final : public Input::InputDevice {
+public:
+ explicit InputFromHatButton(PadIdentifier identifier_, u32 button_, u8 direction_, bool toggle_,
+ bool inverted_, InputEngine* input_engine_)
+ : identifier(identifier_), button(button_), direction(direction_), toggle(toggle_),
+ inverted(inverted_), input_engine(input_engine_) {
+ UpdateCallback engine_callback{[this]() { OnChange(); }};
+ const InputIdentifier input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::HatButton,
+ .index = button,
+ .callback = engine_callback,
+ };
+ last_button_value = false;
+ callback_key = input_engine->SetCallback(input_identifier);
+ }
+
+ ~InputFromHatButton() {
+ input_engine->DeleteCallback(callback_key);
+ }
+
+ Input::ButtonStatus GetStatus() const {
+ return {
+ .value = input_engine->GetHatButton(identifier, button, direction),
+ .inverted = inverted,
+ .toggle = toggle,
+ };
+ }
+
+ void OnChange() {
+ const Input::CallbackStatus status{
+ .type = Input::InputType::Button,
+ .button_status = GetStatus(),
+ };
+
+ if (status.button_status.value != last_button_value) {
+ last_button_value = status.button_status.value;
+ TriggerOnChange(status);
+ }
+ }
+
+private:
+ const PadIdentifier identifier;
+ const u32 button;
+ const u8 direction;
+ const bool toggle;
+ const bool inverted;
+ int callback_key;
+ bool last_button_value;
+ InputEngine* input_engine;
+};
+
+class InputFromStick final : public Input::InputDevice {
+public:
+ explicit InputFromStick(PadIdentifier identifier_, u32 axis_x_, u32 axis_y_,
+ Input::AnalogProperties properties_x_,
+ Input::AnalogProperties properties_y_, InputEngine* input_engine_)
+ : identifier(identifier_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_),
+ properties_y(properties_y_), input_engine(input_engine_) {
+ UpdateCallback engine_callback{[this]() { OnChange(); }};
+ const InputIdentifier x_input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::Analog,
+ .index = axis_x,
+ .callback = engine_callback,
+ };
+ const InputIdentifier y_input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::Analog,
+ .index = axis_y,
+ .callback = engine_callback,
+ };
+ last_axis_x_value = 0.0f;
+ last_axis_y_value = 0.0f;
+ callback_key_x = input_engine->SetCallback(x_input_identifier);
+ callback_key_y = input_engine->SetCallback(y_input_identifier);
+ }
+
+ ~InputFromStick() {
+ input_engine->DeleteCallback(callback_key_x);
+ input_engine->DeleteCallback(callback_key_y);
+ }
+
+ Input::StickStatus GetStatus() const {
+ Input::StickStatus status;
+ status.x = {
+ .raw_value = input_engine->GetAxis(identifier, axis_x),
+ .properties = properties_x,
+ };
+ status.y = {
+ .raw_value = input_engine->GetAxis(identifier, axis_y),
+ .properties = properties_y,
+ };
+ return status;
+ }
+
+ void OnChange() {
+ const Input::CallbackStatus status{
+ .type = Input::InputType::Stick,
+ .stick_status = GetStatus(),
+ };
+
+ if (status.stick_status.x.raw_value != last_axis_x_value ||
+ status.stick_status.y.raw_value != last_axis_y_value) {
+ last_axis_x_value = status.stick_status.x.raw_value;
+ last_axis_y_value = status.stick_status.y.raw_value;
+ TriggerOnChange(status);
+ }
+ }
+
+private:
+ const PadIdentifier identifier;
+ const u32 axis_x;
+ const u32 axis_y;
+ const Input::AnalogProperties properties_x;
+ const Input::AnalogProperties properties_y;
+ int callback_key_x;
+ int callback_key_y;
+ float last_axis_x_value;
+ float last_axis_y_value;
+ InputEngine* input_engine;
+};
+
+class InputFromTouch final : public Input::InputDevice {
+public:
+ explicit InputFromTouch(PadIdentifier identifier_, u32 touch_id_, u32 button_, bool toggle_,
+ bool inverted_, u32 axis_x_, u32 axis_y_,
+ Input::AnalogProperties properties_x_,
+ Input::AnalogProperties properties_y_, InputEngine* input_engine_)
+ : identifier(identifier_), touch_id(touch_id_), button(button_), toggle(toggle_),
+ inverted(inverted_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_),
+ properties_y(properties_y_), input_engine(input_engine_) {
+ UpdateCallback engine_callback{[this]() { OnChange(); }};
+ const InputIdentifier button_input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::Button,
+ .index = button,
+ .callback = engine_callback,
+ };
+ const InputIdentifier x_input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::Analog,
+ .index = axis_x,
+ .callback = engine_callback,
+ };
+ const InputIdentifier y_input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::Analog,
+ .index = axis_y,
+ .callback = engine_callback,
+ };
+ last_axis_x_value = 0.0f;
+ last_axis_y_value = 0.0f;
+ last_button_value = false;
+ callback_key_button = input_engine->SetCallback(button_input_identifier);
+ callback_key_x = input_engine->SetCallback(x_input_identifier);
+ callback_key_y = input_engine->SetCallback(y_input_identifier);
+ }
+
+ ~InputFromTouch() {
+ input_engine->DeleteCallback(callback_key_button);
+ input_engine->DeleteCallback(callback_key_x);
+ input_engine->DeleteCallback(callback_key_y);
+ }
+
+ Input::TouchStatus GetStatus() const {
+ Input::TouchStatus status;
+ status.id = touch_id;
+ status.pressed = {
+ .value = input_engine->GetButton(identifier, button),
+ .inverted = inverted,
+ .toggle = toggle,
+ };
+ status.x = {
+ .raw_value = input_engine->GetAxis(identifier, axis_x),
+ .properties = properties_x,
+ };
+ status.y = {
+ .raw_value = input_engine->GetAxis(identifier, axis_y),
+ .properties = properties_y,
+ };
+ return status;
+ }
+
+ void OnChange() {
+ const Input::CallbackStatus status{
+ .type = Input::InputType::Touch,
+ .touch_status = GetStatus(),
+ };
+
+ if (status.touch_status.x.raw_value != last_axis_x_value ||
+ status.touch_status.y.raw_value != last_axis_y_value ||
+ status.touch_status.pressed.value != last_button_value) {
+ last_axis_x_value = status.touch_status.x.raw_value;
+ last_axis_y_value = status.touch_status.y.raw_value;
+ last_button_value = status.touch_status.pressed.value;
+ TriggerOnChange(status);
+ }
+ }
+
+private:
+ const PadIdentifier identifier;
+ const u32 touch_id;
+ const u32 button;
+ const bool toggle;
+ const bool inverted;
+ const u32 axis_x;
+ const u32 axis_y;
+ const Input::AnalogProperties properties_x;
+ const Input::AnalogProperties properties_y;
+ int callback_key_button;
+ int callback_key_x;
+ int callback_key_y;
+ bool last_button_value;
+ float last_axis_x_value;
+ float last_axis_y_value;
+ InputEngine* input_engine;
+};
+
+class InputFromTrigger final : public Input::InputDevice {
+public:
+ explicit InputFromTrigger(PadIdentifier identifier_, u32 button_, bool toggle_, bool inverted_,
+ u32 axis_, Input::AnalogProperties properties_,
+ InputEngine* input_engine_)
+ : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_),
+ axis(axis_), properties(properties_), input_engine(input_engine_) {
+ UpdateCallback engine_callback{[this]() { OnChange(); }};
+ const InputIdentifier button_input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::Button,
+ .index = button,
+ .callback = engine_callback,
+ };
+ const InputIdentifier axis_input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::Analog,
+ .index = axis,
+ .callback = engine_callback,
+ };
+ last_axis_value = 0.0f;
+ last_button_value = false;
+ callback_key_button = input_engine->SetCallback(button_input_identifier);
+ axis_callback_key = input_engine->SetCallback(axis_input_identifier);
+ }
+
+ ~InputFromTrigger() {
+ input_engine->DeleteCallback(callback_key_button);
+ input_engine->DeleteCallback(axis_callback_key);
+ }
+
+ Input::TriggerStatus GetStatus() const {
+ const Input::AnalogStatus analog_status{
+ .raw_value = input_engine->GetAxis(identifier, axis),
+ .properties = properties,
+ };
+ return {
+ .analog = analog_status,
+ .pressed = input_engine->GetButton(identifier, button),
+ };
+ }
+
+ void OnChange() {
+ const Input::CallbackStatus status{
+ .type = Input::InputType::Trigger,
+ .trigger_status = GetStatus(),
+ };
+
+ if (status.trigger_status.analog.raw_value != last_axis_value ||
+ status.trigger_status.pressed != last_button_value) {
+ last_axis_value = status.trigger_status.analog.raw_value;
+ last_button_value = status.trigger_status.pressed;
+ TriggerOnChange(status);
+ }
+ }
+
+private:
+ const PadIdentifier identifier;
+ const u32 button;
+ const bool toggle;
+ const bool inverted;
+ const u32 axis;
+ const Input::AnalogProperties properties;
+ int callback_key_button;
+ int axis_callback_key;
+ bool last_button_value;
+ float last_axis_value;
+ InputEngine* input_engine;
+};
+
+class InputFromAnalog final : public Input::InputDevice {
+public:
+ explicit InputFromAnalog(PadIdentifier identifier_, u32 axis_,
+ Input::AnalogProperties properties_, InputEngine* input_engine_)
+ : identifier(identifier_), axis(axis_), properties(properties_),
+ input_engine(input_engine_) {
+ UpdateCallback engine_callback{[this]() { OnChange(); }};
+ const InputIdentifier input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::Analog,
+ .index = axis,
+ .callback = engine_callback,
+ };
+ last_axis_value = 0.0f;
+ callback_key = input_engine->SetCallback(input_identifier);
+ }
+
+ ~InputFromAnalog() {
+ input_engine->DeleteCallback(callback_key);
+ }
+
+ Input::AnalogStatus GetStatus() const {
+ return {
+ .raw_value = input_engine->GetAxis(identifier, axis),
+ .properties = properties,
+ };
+ }
+
+ void OnChange() {
+ const Input::CallbackStatus status{
+ .type = Input::InputType::Analog,
+ .analog_status = GetStatus(),
+ };
+
+ if (status.analog_status.raw_value != last_axis_value) {
+ last_axis_value = status.analog_status.raw_value;
+ TriggerOnChange(status);
+ }
+ }
+
+private:
+ const PadIdentifier identifier;
+ const u32 axis;
+ const Input::AnalogProperties properties;
+ int callback_key;
+ float last_axis_value;
+ InputEngine* input_engine;
+};
+
+class InputFromBattery final : public Input::InputDevice {
+public:
+ explicit InputFromBattery(PadIdentifier identifier_, InputEngine* input_engine_)
+ : identifier(identifier_), input_engine(input_engine_) {
+ UpdateCallback engine_callback{[this]() { OnChange(); }};
+ const InputIdentifier input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::Battery,
+ .index = 0,
+ .callback = engine_callback,
+ };
+ last_battery_value = Input::BatteryStatus::Charging;
+ callback_key = input_engine->SetCallback(input_identifier);
+ }
+
+ ~InputFromBattery() {
+ input_engine->DeleteCallback(callback_key);
+ }
+
+ Input::BatteryStatus GetStatus() const {
+ return static_cast(input_engine->GetBattery(identifier));
+ }
+
+ void OnChange() {
+ const Input::CallbackStatus status{
+ .type = Input::InputType::Battery,
+ .battery_status = GetStatus(),
+ };
+
+ if (status.battery_status != last_battery_value) {
+ last_battery_value = status.battery_status;
+ TriggerOnChange(status);
+ }
+ }
+
+private:
+ const PadIdentifier identifier;
+ int callback_key;
+ Input::BatteryStatus last_battery_value;
+ InputEngine* input_engine;
+};
+
+class InputFromMotion final : public Input::InputDevice {
+public:
+ explicit InputFromMotion(PadIdentifier identifier_, u32 motion_sensor_,
+ InputEngine* input_engine_)
+ : identifier(identifier_), motion_sensor(motion_sensor_), input_engine(input_engine_) {
+ UpdateCallback engine_callback{[this]() { OnChange(); }};
+ const InputIdentifier input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::Motion,
+ .index = motion_sensor,
+ .callback = engine_callback,
+ };
+ callback_key = input_engine->SetCallback(input_identifier);
+ }
+
+ ~InputFromMotion() {
+ input_engine->DeleteCallback(callback_key);
+ }
+
+ Input::MotionStatus GetStatus() const {
+ const auto basic_motion = input_engine->GetMotion(identifier, motion_sensor);
+ Input::MotionStatus status{};
+ const Input::AnalogProperties properties = {
+ .deadzone = 0.001f,
+ .range = 1.0f,
+ .offset = 0.0f,
+ };
+ status.accel.x = {.raw_value = basic_motion.accel_x, .properties = properties};
+ status.accel.y = {.raw_value = basic_motion.accel_y, .properties = properties};
+ status.accel.z = {.raw_value = basic_motion.accel_z, .properties = properties};
+ status.gyro.x = {.raw_value = basic_motion.gyro_x, .properties = properties};
+ status.gyro.y = {.raw_value = basic_motion.gyro_y, .properties = properties};
+ status.gyro.z = {.raw_value = basic_motion.gyro_z, .properties = properties};
+ status.delta_timestamp = basic_motion.delta_timestamp;
+ return status;
+ }
+
+ void OnChange() {
+ const Input::CallbackStatus status{
+ .type = Input::InputType::Motion,
+ .motion_status = GetStatus(),
+ };
+
+ TriggerOnChange(status);
+ }
+
+private:
+ const PadIdentifier identifier;
+ const u32 motion_sensor;
+ int callback_key;
+ InputEngine* input_engine;
+};
+
+class InputFromAxisMotion final : public Input::InputDevice {
+public:
+ explicit InputFromAxisMotion(PadIdentifier identifier_, u32 axis_x_, u32 axis_y_, u32 axis_z_,
+ Input::AnalogProperties properties_x_,
+ Input::AnalogProperties properties_y_,
+ Input::AnalogProperties properties_z_, InputEngine* input_engine_)
+ : identifier(identifier_), axis_x(axis_x_), axis_y(axis_y_), axis_z(axis_z_),
+ properties_x(properties_x_), properties_y(properties_y_), properties_z(properties_z_),
+ input_engine(input_engine_) {
+ UpdateCallback engine_callback{[this]() { OnChange(); }};
+ const InputIdentifier x_input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::Analog,
+ .index = axis_x,
+ .callback = engine_callback,
+ };
+ const InputIdentifier y_input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::Analog,
+ .index = axis_y,
+ .callback = engine_callback,
+ };
+ const InputIdentifier z_input_identifier{
+ .identifier = identifier,
+ .type = EngineInputType::Analog,
+ .index = axis_z,
+ .callback = engine_callback,
+ };
+ last_axis_x_value = 0.0f;
+ last_axis_y_value = 0.0f;
+ last_axis_z_value = 0.0f;
+ callback_key_x = input_engine->SetCallback(x_input_identifier);
+ callback_key_y = input_engine->SetCallback(y_input_identifier);
+ callback_key_z = input_engine->SetCallback(z_input_identifier);
+ }
+
+ ~InputFromAxisMotion() {
+ input_engine->DeleteCallback(callback_key_x);
+ input_engine->DeleteCallback(callback_key_y);
+ input_engine->DeleteCallback(callback_key_z);
+ }
+
+ Input::MotionStatus GetStatus() const {
+ Input::MotionStatus status{};
+ status.gyro.x = {
+ .raw_value = input_engine->GetAxis(identifier, axis_x),
+ .properties = properties_x,
+ };
+ status.gyro.y = {
+ .raw_value = input_engine->GetAxis(identifier, axis_y),
+ .properties = properties_y,
+ };
+ status.gyro.z = {
+ .raw_value = input_engine->GetAxis(identifier, axis_z),
+ .properties = properties_z,
+ };
+ return status;
+ }
+
+ void OnChange() {
+ const Input::CallbackStatus status{
+ .type = Input::InputType::Motion,
+ .motion_status = GetStatus(),
+ };
+
+ if (status.motion_status.gyro.x.raw_value != last_axis_x_value ||
+ status.motion_status.gyro.y.raw_value != last_axis_y_value ||
+ status.motion_status.gyro.z.raw_value != last_axis_z_value) {
+ last_axis_x_value = status.motion_status.gyro.x.raw_value;
+ last_axis_y_value = status.motion_status.gyro.y.raw_value;
+ last_axis_z_value = status.motion_status.gyro.z.raw_value;
+ TriggerOnChange(status);
+ }
+ }
+
+private:
+ const PadIdentifier identifier;
+ const u32 axis_x;
+ const u32 axis_y;
+ const u32 axis_z;
+ const Input::AnalogProperties properties_x;
+ const Input::AnalogProperties properties_y;
+ const Input::AnalogProperties properties_z;
+ int callback_key_x;
+ int callback_key_y;
+ int callback_key_z;
+ float last_axis_x_value;
+ float last_axis_y_value;
+ float last_axis_z_value;
+ InputEngine* input_engine;
+};
+
+std::unique_ptr InputFactory::CreateButtonDevice(
+ const Common::ParamPackage& params) {
+ const PadIdentifier identifier = {
+ .guid = Common::UUID{params.Get("guid", "")},
+ .port = static_cast(params.Get("port", 0)),
+ .pad = static_cast(params.Get("pad", 0)),
+ };
+
+ const auto button_id = static_cast(params.Get("button", 0));
+ const auto keyboard_key = static_cast(params.Get("code", 0));
+ const auto toggle = params.Get("toggle", false);
+ const auto inverted = params.Get("inverted", false);
+ input_engine->PreSetController(identifier);
+ input_engine->PreSetButton(identifier, button_id);
+ input_engine->PreSetButton(identifier, keyboard_key);
+ if (keyboard_key != 0) {
+ return std::make_unique(identifier, keyboard_key, toggle, inverted,
+ input_engine.get());
+ }
+ return std::make_unique