summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/input_common/drivers/udp_client.cpp74
-rw-r--r--src/input_common/helpers/udp_protocol.h21
-rw-r--r--src/tests/CMakeLists.txt3
-rw-r--r--src/tests/input_common/calibration_configuration_job.cpp136
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h2
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp50
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp123
-rw-r--r--src/video_core/renderer_vulkan/blit_image.h30
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp37
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp34
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h8
-rw-r--r--src/video_core/texture_cache/texture_cache.h22
-rw-r--r--src/yuzu/configuration/config.cpp2
-rw-r--r--src/yuzu/game_list.cpp19
-rw-r--r--src/yuzu/main.cpp13
-rw-r--r--src/yuzu/uisettings.h3
16 files changed, 365 insertions, 212 deletions
diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp
index 4ab991a7d..a1ce4525d 100644
--- a/src/input_common/drivers/udp_client.cpp
+++ b/src/input_common/drivers/udp_client.cpp
@@ -536,42 +536,46 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
std::function<void(u16, u16, u16, u16)> data_callback) {
std::thread([=, this] {
+ u16 min_x{UINT16_MAX};
+ u16 min_y{UINT16_MAX};
+ u16 max_x{};
+ u16 max_y{};
+
Status current_status{Status::Initialized};
- SocketCallback callback{
- [](Response::Version) {}, [](Response::PortInfo) {},
- [&](Response::PadData data) {
- static constexpr u16 CALIBRATION_THRESHOLD = 100;
- static constexpr u16 MAX_VALUE = UINT16_MAX;
-
- if (current_status == Status::Initialized) {
- // Receiving data means the communication is ready now
- current_status = Status::Ready;
- status_callback(current_status);
- }
- const auto& touchpad_0 = data.touch[0];
- if (touchpad_0.is_active == 0) {
- return;
- }
- LOG_DEBUG(Input, "Current touch: {} {}", touchpad_0.x, touchpad_0.y);
- const u16 min_x = std::min(MAX_VALUE, static_cast<u16>(touchpad_0.x));
- const u16 min_y = std::min(MAX_VALUE, static_cast<u16>(touchpad_0.y));
- if (current_status == Status::Ready) {
- // First touch - min data (min_x/min_y)
- current_status = Status::Stage1Completed;
- status_callback(current_status);
- }
- if (touchpad_0.x - min_x > CALIBRATION_THRESHOLD &&
- touchpad_0.y - min_y > CALIBRATION_THRESHOLD) {
- // Set the current position as max value and finishes configuration
- const u16 max_x = touchpad_0.x;
- const u16 max_y = touchpad_0.y;
- current_status = Status::Completed;
- data_callback(min_x, min_y, max_x, max_y);
- status_callback(current_status);
-
- complete_event.Set();
- }
- }};
+ SocketCallback callback{[](Response::Version) {}, [](Response::PortInfo) {},
+ [&](Response::PadData data) {
+ constexpr u16 CALIBRATION_THRESHOLD = 100;
+
+ if (current_status == Status::Initialized) {
+ // Receiving data means the communication is ready now
+ current_status = Status::Ready;
+ status_callback(current_status);
+ }
+ if (data.touch[0].is_active == 0) {
+ return;
+ }
+ LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x,
+ data.touch[0].y);
+ min_x = std::min(min_x, static_cast<u16>(data.touch[0].x));
+ min_y = std::min(min_y, static_cast<u16>(data.touch[0].y));
+ if (current_status == Status::Ready) {
+ // First touch - min data (min_x/min_y)
+ current_status = Status::Stage1Completed;
+ status_callback(current_status);
+ }
+ if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD &&
+ data.touch[0].y - min_y > CALIBRATION_THRESHOLD) {
+ // Set the current position as max value and finishes
+ // configuration
+ max_x = data.touch[0].x;
+ max_y = data.touch[0].y;
+ current_status = Status::Completed;
+ data_callback(min_x, min_y, max_x, max_y);
+ status_callback(current_status);
+
+ complete_event.Set();
+ }
+ }};
Socket socket{host, port, std::move(callback)};
std::thread worker_thread{SocketLoop, &socket};
complete_event.Wait();
diff --git a/src/input_common/helpers/udp_protocol.h b/src/input_common/helpers/udp_protocol.h
index bcba12c58..2d5d54ddb 100644
--- a/src/input_common/helpers/udp_protocol.h
+++ b/src/input_common/helpers/udp_protocol.h
@@ -54,6 +54,18 @@ struct Message {
template <typename T>
constexpr Type GetMessageType();
+template <typename T>
+Message<T> CreateMessage(const u32 magic, const T data, const u32 sender_id) {
+ boost::crc_32_type crc;
+ Header header{
+ magic, PROTOCOL_VERSION, sizeof(T) + sizeof(Type), 0, sender_id, GetMessageType<T>(),
+ };
+ Message<T> message{header, data};
+ crc.process_bytes(&message, sizeof(Message<T>));
+ message.header.crc = crc.checksum();
+ return message;
+}
+
namespace Request {
enum RegisterFlags : u8 {
@@ -101,14 +113,7 @@ static_assert(std::is_trivially_copyable_v<PadData>,
*/
template <typename T>
Message<T> Create(const T data, const u32 client_id = 0) {
- boost::crc_32_type crc;
- Header header{
- CLIENT_MAGIC, PROTOCOL_VERSION, sizeof(T) + sizeof(Type), 0, client_id, GetMessageType<T>(),
- };
- Message<T> message{header, data};
- crc.process_bytes(&message, sizeof(Message<T>));
- message.header.crc = crc.checksum();
- return message;
+ return CreateMessage(CLIENT_MAGIC, data, client_id);
}
} // namespace Request
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index c4c012f3d..4a20c0768 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -10,11 +10,12 @@ add_executable(tests
core/network/network.cpp
tests.cpp
video_core/buffer_base.cpp
+ input_common/calibration_configuration_job.cpp
)
create_target_directory_groups(tests)
-target_link_libraries(tests PRIVATE common core)
+target_link_libraries(tests PRIVATE common core input_common)
target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} catch-single-include Threads::Threads)
add_test(NAME tests COMMAND tests)
diff --git a/src/tests/input_common/calibration_configuration_job.cpp b/src/tests/input_common/calibration_configuration_job.cpp
new file mode 100644
index 000000000..8c77d81e9
--- /dev/null
+++ b/src/tests/input_common/calibration_configuration_job.cpp
@@ -0,0 +1,136 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <array>
+#include <string>
+#include <thread>
+#include <boost/asio.hpp>
+#include <boost/crc.hpp>
+#include <catch2/catch.hpp>
+
+#include "input_common/drivers/udp_client.h"
+#include "input_common/helpers/udp_protocol.h"
+
+class FakeCemuhookServer {
+public:
+ FakeCemuhookServer()
+ : socket(io_service, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 0)) {}
+
+ ~FakeCemuhookServer() {
+ is_running = false;
+ boost::system::error_code error_code;
+ socket.shutdown(boost::asio::socket_base::shutdown_both, error_code);
+ socket.close();
+ if (handler.joinable()) {
+ handler.join();
+ }
+ }
+
+ u16 GetPort() {
+ return socket.local_endpoint().port();
+ }
+
+ std::string GetHost() {
+ return socket.local_endpoint().address().to_string();
+ }
+
+ void Run(const std::vector<InputCommon::CemuhookUDP::Response::TouchPad> touch_movement_path) {
+ constexpr size_t HeaderSize = sizeof(InputCommon::CemuhookUDP::Header);
+ constexpr size_t PadDataSize =
+ sizeof(InputCommon::CemuhookUDP::Message<InputCommon::CemuhookUDP::Response::PadData>);
+
+ REQUIRE(touch_movement_path.size() > 0);
+ is_running = true;
+ handler = std::thread([touch_movement_path, this]() {
+ auto current_touch_position = touch_movement_path.begin();
+ while (is_running) {
+ boost::asio::ip::udp::endpoint sender_endpoint;
+ boost::system::error_code error_code;
+ auto received_size = socket.receive_from(boost::asio::buffer(receive_buffer),
+ sender_endpoint, 0, error_code);
+
+ if (received_size < HeaderSize) {
+ continue;
+ }
+
+ InputCommon::CemuhookUDP::Header header{};
+ std::memcpy(&header, receive_buffer.data(), HeaderSize);
+ switch (header.type) {
+ case InputCommon::CemuhookUDP::Type::PadData: {
+ InputCommon::CemuhookUDP::Response::PadData pad_data{};
+ pad_data.touch[0] = *current_touch_position;
+ const auto pad_message = InputCommon::CemuhookUDP::CreateMessage(
+ InputCommon::CemuhookUDP::SERVER_MAGIC, pad_data, 0);
+ std::memcpy(send_buffer.data(), &pad_message, PadDataSize);
+ socket.send_to(boost::asio::buffer(send_buffer, PadDataSize), sender_endpoint,
+ 0, error_code);
+
+ bool can_advance =
+ std::next(current_touch_position) != touch_movement_path.end();
+ if (can_advance) {
+ std::advance(current_touch_position, 1);
+ }
+ break;
+ }
+ case InputCommon::CemuhookUDP::Type::PortInfo:
+ case InputCommon::CemuhookUDP::Type::Version:
+ default:
+ break;
+ }
+ }
+ });
+ }
+
+private:
+ boost::asio::io_service io_service;
+ boost::asio::ip::udp::socket socket;
+ std::array<u8, InputCommon::CemuhookUDP::MAX_PACKET_SIZE> send_buffer;
+ std::array<u8, InputCommon::CemuhookUDP::MAX_PACKET_SIZE> receive_buffer;
+ bool is_running = false;
+ std::thread handler;
+};
+
+TEST_CASE("CalibrationConfigurationJob completed", "[input_common]") {
+ Common::Event complete_event;
+ FakeCemuhookServer server;
+ server.Run({{
+ .is_active = 1,
+ .x = 0,
+ .y = 0,
+ },
+ {
+ .is_active = 1,
+ .x = 200,
+ .y = 200,
+ }});
+
+ InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status status{};
+ u16 min_x{};
+ u16 min_y{};
+ u16 max_x{};
+ u16 max_y{};
+ InputCommon::CemuhookUDP::CalibrationConfigurationJob job(
+ server.GetHost(), server.GetPort(),
+ [&status,
+ &complete_event](InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status status_) {
+ status = status_;
+ if (status ==
+ InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status::Completed) {
+ complete_event.Set();
+ }
+ },
+ [&](u16 min_x_, u16 min_y_, u16 max_x_, u16 max_y_) {
+ min_x = min_x_;
+ min_y = min_y_;
+ max_x = max_x_;
+ max_y = max_y_;
+ });
+
+ complete_event.WaitUntil(std::chrono::system_clock::now() + std::chrono::seconds(10));
+ REQUIRE(status == InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status::Completed);
+ REQUIRE(min_x == 0);
+ REQUIRE(min_y == 0);
+ REQUIRE(max_x == 200);
+ REQUIRE(max_y == 200);
+}
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 37d5e6a6b..dbf1df79c 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -92,7 +92,7 @@ public:
void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
- void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled) {
+ void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) {
UNIMPLEMENTED();
}
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 28daacd82..f81c1b233 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -437,39 +437,29 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
glBindTextureUnit(0, fxaa_texture.handle);
}
-
- // Set projection matrix
const std::array ortho_matrix =
MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height));
- GLuint fragment_handle;
- const auto filter = Settings::values.scaling_filter.GetValue();
- switch (filter) {
- case Settings::ScalingFilter::NearestNeighbor:
- fragment_handle = present_bilinear_fragment.handle;
- break;
- case Settings::ScalingFilter::Bilinear:
- fragment_handle = present_bilinear_fragment.handle;
- break;
- case Settings::ScalingFilter::Bicubic:
- fragment_handle = present_bicubic_fragment.handle;
- break;
- case Settings::ScalingFilter::Gaussian:
- fragment_handle = present_gaussian_fragment.handle;
- break;
- case Settings::ScalingFilter::ScaleForce:
- fragment_handle = present_scaleforce_fragment.handle;
- break;
- case Settings::ScalingFilter::Fsr:
- LOG_WARNING(
- Render_OpenGL,
- "FidelityFX FSR Super Sampling is not supported in OpenGL, changing to ScaleForce");
- fragment_handle = present_scaleforce_fragment.handle;
- break;
- default:
- fragment_handle = present_bilinear_fragment.handle;
- break;
- }
+ const auto fragment_handle = [this]() {
+ switch (Settings::values.scaling_filter.GetValue()) {
+ case Settings::ScalingFilter::NearestNeighbor:
+ case Settings::ScalingFilter::Bilinear:
+ return present_bilinear_fragment.handle;
+ case Settings::ScalingFilter::Bicubic:
+ return present_bicubic_fragment.handle;
+ case Settings::ScalingFilter::Gaussian:
+ return present_gaussian_fragment.handle;
+ case Settings::ScalingFilter::ScaleForce:
+ return present_scaleforce_fragment.handle;
+ case Settings::ScalingFilter::Fsr:
+ LOG_WARNING(
+ Render_OpenGL,
+ "FidelityFX Super Resolution is not supported in OpenGL, changing to ScaleForce");
+ return present_scaleforce_fragment.handle;
+ default:
+ return present_bilinear_fragment.handle;
+ }
+ }();
program_manager.BindPresentPrograms(present_vertex.handle, fragment_handle);
glProgramUniformMatrix3x2fv(present_vertex.handle, ModelViewMatrixLocation, 1, GL_FALSE,
ortho_matrix.data());
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index 9a38b6b34..cd5995897 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -4,6 +4,7 @@
#include <algorithm>
+#include "common/settings.h"
#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
#include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h"
#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
@@ -335,6 +336,17 @@ void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Regi
cmdbuf.SetScissor(0, scissor);
cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
}
+
+VkExtent2D GetConversionExtent(const ImageView& src_image_view) {
+ const auto& resolution = Settings::values.resolution_info;
+ const bool is_rescaled = src_image_view.IsRescaled();
+ u32 width = src_image_view.size.width;
+ u32 height = src_image_view.size.height;
+ return VkExtent2D{
+ .width = is_rescaled ? resolution.ScaleUp(width) : width,
+ .height = is_rescaled ? resolution.ScaleUp(height) : height,
+ };
+}
} // Anonymous namespace
BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_,
@@ -425,61 +437,52 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
}
void BlitImageHelper::ConvertD32ToR32(const Framebuffer* dst_framebuffer,
- const ImageView& src_image_view, u32 up_scale,
- u32 down_shift) {
+ const ImageView& src_image_view) {
ConvertDepthToColorPipeline(convert_d32_to_r32_pipeline, dst_framebuffer->RenderPass());
- Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift);
+ Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view);
}
void BlitImageHelper::ConvertR32ToD32(const Framebuffer* dst_framebuffer,
- const ImageView& src_image_view, u32 up_scale,
- u32 down_shift) {
+ const ImageView& src_image_view) {
ConvertColorToDepthPipeline(convert_r32_to_d32_pipeline, dst_framebuffer->RenderPass());
- Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift);
+ Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view);
}
void BlitImageHelper::ConvertD16ToR16(const Framebuffer* dst_framebuffer,
- const ImageView& src_image_view, u32 up_scale,
- u32 down_shift) {
+ const ImageView& src_image_view) {
ConvertDepthToColorPipeline(convert_d16_to_r16_pipeline, dst_framebuffer->RenderPass());
- Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift);
+ Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view);
}
void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
- const ImageView& src_image_view, u32 up_scale,
- u32 down_shift) {
+ const ImageView& src_image_view) {
ConvertColorToDepthPipeline(convert_r16_to_d16_pipeline, dst_framebuffer->RenderPass());
- Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift);
+ Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view);
}
void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
- ImageView& src_image_view, u32 up_scale, u32 down_shift) {
+ const ImageView& src_image_view) {
ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
- convert_abgr8_to_d24s8_frag, true);
- ConvertColor(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale,
- down_shift);
+ convert_abgr8_to_d24s8_frag);
+ Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
}
void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
- ImageView& src_image_view, u32 up_scale, u32 down_shift) {
+ ImageView& src_image_view) {
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);
+ convert_d24s8_to_abgr8_frag);
+ ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view);
}
void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
- const ImageView& src_image_view, u32 up_scale, u32 down_shift) {
+ const ImageView& src_image_view) {
const VkPipelineLayout layout = *one_texture_pipeline_layout;
const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
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),
- };
+ const VkExtent2D extent = GetConversionExtent(src_image_view);
+
scheduler.RequestRenderpass(dst_framebuffer);
- scheduler.Record([pipeline, layout, sampler, src_view, extent, up_scale, down_shift,
- this](vk::CommandBuffer cmdbuf) {
+ scheduler.Record([pipeline, layout, sampler, src_view, extent, this](vk::CommandBuffer cmdbuf) {
const VkOffset2D offset{
.x = 0,
.y = 0,
@@ -563,18 +566,16 @@ void BlitImageHelper::ConvertColor(VkPipeline pipeline, const Framebuffer* dst_f
}
void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
- ImageView& src_image_view, u32 up_scale, u32 down_shift) {
+ ImageView& src_image_view) {
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;
- 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),
- };
+ const VkExtent2D extent = GetConversionExtent(src_image_view);
+
scheduler.RequestRenderpass(dst_framebuffer);
- scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent, up_scale,
- down_shift, this](vk::CommandBuffer cmdbuf) {
+ scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent,
+ this](vk::CommandBuffer cmdbuf) {
const VkOffset2D offset{
.x = 0,
.y = 0,
@@ -695,11 +696,14 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip
return *blit_depth_stencil_pipelines.back();
}
-void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
+void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass,
+ bool is_target_depth) {
if (pipeline) {
return;
}
- const std::array stages = MakeStages(*full_screen_vert, *convert_depth_to_float_frag);
+ VkShaderModule frag_shader =
+ is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag;
+ const std::array stages = MakeStages(*full_screen_vert, frag_shader);
pipeline = device.GetLogical().CreateGraphicsPipeline({
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = nullptr,
@@ -712,8 +716,9 @@ void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRend
.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,
+ .pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr,
+ .pColorBlendState = is_target_depth ? &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO
+ : &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.layout = *one_texture_pipeline_layout,
.renderPass = renderpass,
@@ -723,37 +728,17 @@ void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRend
});
}
+void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
+ ConvertPipeline(pipeline, renderpass, false);
+}
+
void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
- if (pipeline) {
- return;
- }
- const std::array stages = MakeStages(*full_screen_vert, *convert_float_to_depth_frag);
- pipeline = device.GetLogical().CreateGraphicsPipeline({
- .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
- .pNext = nullptr,
- .flags = 0,
- .stageCount = static_cast<u32>(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 = *one_texture_pipeline_layout,
- .renderPass = renderpass,
- .subpass = 0,
- .basePipelineHandle = VK_NULL_HANDLE,
- .basePipelineIndex = 0,
- });
+ ConvertPipeline(pipeline, renderpass, true);
}
void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
- vk::ShaderModule& module, bool is_target_depth,
- bool single_texture) {
+ vk::ShaderModule& module, bool single_texture,
+ bool is_target_depth) {
if (pipeline) {
return;
}
@@ -782,13 +767,13 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren
}
void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
- vk::ShaderModule& module, bool single_texture) {
- ConvertPipelineEx(pipeline, renderpass, module, false, single_texture);
+ vk::ShaderModule& module) {
+ ConvertPipelineEx(pipeline, renderpass, module, false, false);
}
void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
- vk::ShaderModule& module, bool single_texture) {
- ConvertPipelineEx(pipeline, renderpass, module, true, single_texture);
+ vk::ShaderModule& module) {
+ ConvertPipelineEx(pipeline, renderpass, module, true, true);
}
} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h
index b1a717090..1d9f61a52 100644
--- a/src/video_core/renderer_vulkan/blit_image.h
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -44,50 +44,46 @@ public:
const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter,
Tegra::Engines::Fermi2D::Operation operation);
- void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
- u32 up_scale, u32 down_shift);
+ void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
- void ConvertR32ToD32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
- u32 up_scale, u32 down_shift);
+ void ConvertR32ToD32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
- void ConvertD16ToR16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
- u32 up_scale, u32 down_shift);
+ void ConvertD16ToR16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
- void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
- u32 up_scale, u32 down_shift);
+ void ConvertR16ToD16(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 ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
- void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
- u32 up_scale, u32 down_shift);
+ void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view);
private:
void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
- const ImageView& src_image_view, u32 up_scale, u32 down_shift);
+ const ImageView& src_image_view);
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);
+ ImageView& src_image_view);
[[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key);
[[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key);
+ void ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, bool is_target_depth);
+
void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
void ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
- vk::ShaderModule& module, bool is_target_depth, bool single_texture);
+ vk::ShaderModule& module, bool single_texture, bool is_target_depth);
void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
- vk::ShaderModule& module, bool single_texture);
+ vk::ShaderModule& module);
void ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
- vk::ShaderModule& module, bool single_texture);
+ vk::ShaderModule& module);
const Device& device;
VKScheduler& scheduler;
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 1e447e621..c71a1f44d 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -391,28 +391,23 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
.offset = {0, 0},
.extent = size,
};
- const auto filter = Settings::values.scaling_filter.GetValue();
cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
- switch (filter) {
- case Settings::ScalingFilter::NearestNeighbor:
- cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *bilinear_pipeline);
- break;
- case Settings::ScalingFilter::Bilinear:
- cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *bilinear_pipeline);
- break;
- case Settings::ScalingFilter::Bicubic:
- cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *bicubic_pipeline);
- break;
- case Settings::ScalingFilter::Gaussian:
- cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *gaussian_pipeline);
- break;
- case Settings::ScalingFilter::ScaleForce:
- cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *scaleforce_pipeline);
- break;
- default:
- cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *bilinear_pipeline);
- break;
- }
+ auto graphics_pipeline = [this]() {
+ switch (Settings::values.scaling_filter.GetValue()) {
+ case Settings::ScalingFilter::NearestNeighbor:
+ case Settings::ScalingFilter::Bilinear:
+ return *bilinear_pipeline;
+ case Settings::ScalingFilter::Bicubic:
+ return *bicubic_pipeline;
+ case Settings::ScalingFilter::Gaussian:
+ return *gaussian_pipeline;
+ case Settings::ScalingFilter::ScaleForce:
+ return *scaleforce_pipeline;
+ default:
+ return *bilinear_pipeline;
+ }
+ }();
+ cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline);
cmdbuf.SetViewport(0, viewport);
cmdbuf.SetScissor(0, scissor);
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 197cba8e3..1941170cb 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -1057,37 +1057,37 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
});
}
-void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view,
- bool rescaled) {
- const u32 up_scale = rescaled ? resolution.up_scale : 1;
- const u32 down_shift = rescaled ? resolution.down_shift : 0;
+void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) {
switch (dst_view.format) {
case PixelFormat::R16_UNORM:
if (src_view.format == PixelFormat::D16_UNORM) {
- return blit_image_helper.ConvertD16ToR16(dst, src_view, up_scale, down_shift);
+ return blit_image_helper.ConvertD16ToR16(dst, src_view);
}
break;
case PixelFormat::A8B8G8R8_UNORM:
if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) {
- return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view, up_scale, down_shift);
+ return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view);
}
break;
case PixelFormat::R32_FLOAT:
if (src_view.format == PixelFormat::D32_FLOAT) {
- return blit_image_helper.ConvertD32ToR32(dst, src_view, up_scale, down_shift);
+ return blit_image_helper.ConvertD32ToR32(dst, src_view);
}
break;
case PixelFormat::D16_UNORM:
if (src_view.format == PixelFormat::R16_UNORM) {
- return blit_image_helper.ConvertR16ToD16(dst, src_view, up_scale, down_shift);
+ return blit_image_helper.ConvertR16ToD16(dst, src_view);
}
break;
case PixelFormat::S8_UINT_D24_UNORM:
- return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view, up_scale, down_shift);
+ if (src_view.format == PixelFormat::A8B8G8R8_UNORM ||
+ src_view.format == PixelFormat::B8G8R8A8_UNORM) {
+ return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view);
+ }
break;
case PixelFormat::D32_FLOAT:
if (src_view.format == PixelFormat::R32_FLOAT) {
- return blit_image_helper.ConvertR32ToD32(dst, src_view, up_scale, down_shift);
+ return blit_image_helper.ConvertR32ToD32(dst, src_view);
}
break;
default:
@@ -1329,6 +1329,10 @@ void Image::DownloadMemory(const StagingBufferRef& map, std::span<const BufferIm
}
}
+bool Image::IsRescaled() const noexcept {
+ return True(flags & ImageFlagBits::Rescaled);
+}
+
bool Image::ScaleUp(bool ignore) {
if (True(flags & ImageFlagBits::Rescaled)) {
return false;
@@ -1469,7 +1473,8 @@ bool Image::BlitScaleHelper(bool scale_up) {
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
ImageId image_id_, Image& image)
: VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device},
- image_handle{image.Handle()}, samples{ConvertSampleCount(image.info.num_samples)} {
+ src_image{&image}, image_handle{image.Handle()},
+ samples(ConvertSampleCount(image.info.num_samples)) {
using Shader::TextureType;
const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info);
@@ -1607,6 +1612,13 @@ VkImageView ImageView::StorageView(Shader::TextureType texture_type,
return *view;
}
+bool ImageView::IsRescaled() const noexcept {
+ if (!src_image) {
+ return false;
+ }
+ return src_image->IsRescaled();
+}
+
vk::ImageView ImageView::MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask) {
return device->GetLogical().CreateImageView({
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 753e3e8a1..c592f2666 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -65,7 +65,7 @@ public:
void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
- void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled);
+ void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view);
bool CanAccelerateImageUpload(Image&) const noexcept {
return false;
@@ -139,6 +139,8 @@ public:
return std::exchange(initialized, true);
}
+ bool IsRescaled() const noexcept;
+
bool ScaleUp(bool ignore = false);
bool ScaleDown(bool ignore = false);
@@ -189,6 +191,8 @@ public:
[[nodiscard]] VkImageView StorageView(Shader::TextureType texture_type,
Shader::ImageFormat image_format);
+ [[nodiscard]] bool IsRescaled() const noexcept;
+
[[nodiscard]] VkImageView Handle(Shader::TextureType texture_type) const noexcept {
return *image_views[static_cast<size_t>(texture_type)];
}
@@ -222,6 +226,8 @@ private:
[[nodiscard]] vk::ImageView MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask);
const Device* device = nullptr;
+ const Image* src_image{};
+
std::array<vk::ImageView, Shader::NUM_TEXTURE_TYPES> image_views;
std::unique_ptr<StorageViews> storage_views;
vk::ImageView depth_view;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index e195b1e98..2e19fced2 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -1137,8 +1137,13 @@ typename TextureCache<P>::BlitImages TextureCache<P>::GetBlitImages(
} while (has_deleted_images);
const ImageBase& src_image = slot_images[src_id];
const ImageBase& dst_image = slot_images[dst_id];
+ const bool native_bgr = runtime.HasNativeBgr();
if (GetFormatType(dst_info.format) != GetFormatType(dst_image.info.format) ||
- GetFormatType(src_info.format) != GetFormatType(src_image.info.format)) {
+ GetFormatType(src_info.format) != GetFormatType(src_image.info.format) ||
+ !VideoCore::Surface::IsViewCompatible(dst_info.format, dst_image.info.format, false,
+ native_bgr) ||
+ !VideoCore::Surface::IsViewCompatible(src_info.format, src_image.info.format, false,
+ native_bgr)) {
// Make sure the images match the expected format.
do {
has_deleted_images = false;
@@ -1850,9 +1855,20 @@ void TextureCache<P>::CopyImage(ImageId dst_id, ImageId src_id, std::vector<Imag
.height = std::min(dst_view.size.height, src_view.size.height),
.depth = std::min(dst_view.size.depth, src_view.size.depth),
};
- UNIMPLEMENTED_IF(copy.extent != expected_size);
+ const Extent3D scaled_extent = [is_rescaled, expected_size]() {
+ if (!is_rescaled) {
+ return expected_size;
+ }
+ const auto& resolution = Settings::values.resolution_info;
+ return Extent3D{
+ .width = resolution.ScaleUp(expected_size.width),
+ .height = resolution.ScaleUp(expected_size.height),
+ .depth = expected_size.depth,
+ };
+ }();
+ UNIMPLEMENTED_IF(copy.extent != scaled_extent);
- runtime.ConvertImage(dst_framebuffer, dst_view, src_view, is_rescaled);
+ runtime.ConvertImage(dst_framebuffer, dst_view, src_view);
}
}
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 463d500c2..0f679c37e 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -776,6 +776,7 @@ void Config::ReadUIGamelistValues() {
ReadBasicSetting(UISettings::values.row_1_text_id);
ReadBasicSetting(UISettings::values.row_2_text_id);
ReadBasicSetting(UISettings::values.cache_game_list);
+ ReadBasicSetting(UISettings::values.favorites_expanded);
const int favorites_size = qt_config->beginReadArray(QStringLiteral("favorites"));
for (int i = 0; i < favorites_size; i++) {
qt_config->setArrayIndex(i);
@@ -1300,6 +1301,7 @@ void Config::SaveUIGamelistValues() {
WriteBasicSetting(UISettings::values.row_1_text_id);
WriteBasicSetting(UISettings::values.row_2_text_id);
WriteBasicSetting(UISettings::values.cache_game_list);
+ WriteBasicSetting(UISettings::values.favorites_expanded);
qt_config->beginWriteArray(QStringLiteral("favorites"));
for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) {
qt_config->setArrayIndex(i);
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 1a5e41588..8b5c4a10a 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -173,13 +173,17 @@ void GameList::OnItemExpanded(const QModelIndex& item) {
const bool is_dir = type == GameListItemType::CustomDir || type == GameListItemType::SdmcDir ||
type == GameListItemType::UserNandDir ||
type == GameListItemType::SysNandDir;
-
- if (!is_dir) {
+ const bool is_fave = type == GameListItemType::Favorites;
+ if (!is_dir && !is_fave) {
return;
}
-
- UISettings::values.game_dirs[item.data(GameListDir::GameDirRole).toInt()].expanded =
- tree_view->isExpanded(item);
+ const bool is_expanded = tree_view->isExpanded(item);
+ if (is_fave) {
+ UISettings::values.favorites_expanded = is_expanded;
+ return;
+ }
+ const int item_dir_index = item.data(GameListDir::GameDirRole).toInt();
+ UISettings::values.game_dirs[item_dir_index].expanded = is_expanded;
}
// Event in order to filter the gamelist after editing the searchfield
@@ -458,10 +462,13 @@ void GameList::DonePopulating(const QStringList& watch_list) {
emit ShowList(!IsEmpty());
item_model->invisibleRootItem()->appendRow(new GameListAddDir());
+
+ // Add favorites row
item_model->invisibleRootItem()->insertRow(0, new GameListFavorites());
tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(),
UISettings::values.favorited_ids.size() == 0);
- tree_view->expand(item_model->invisibleRootItem()->child(0)->index());
+ tree_view->setExpanded(item_model->invisibleRootItem()->child(0)->index(),
+ UISettings::values.favorites_expanded.GetValue());
for (const auto id : UISettings::values.favorited_ids) {
AddFavorite(id);
}
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index df736513b..b7bb43348 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1304,16 +1304,13 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
case Core::SystemResultStatus::ErrorVideoCore:
QMessageBox::critical(
this, tr("An error occurred initializing the video core."),
- tr("yuzu has encountered an error while running the video core, please see the "
- "log for more details."
+ tr("yuzu has encountered an error while running the video core. "
+ "This is usually caused by outdated GPU drivers, including integrated ones. "
+ "Please see the log for more details. "
"For more information on accessing the log, please see the following page: "
- "<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How "
- "to "
- "Upload the Log File</a>."
- "Ensure that you have the latest graphics drivers for your GPU."));
-
+ "<a href='https://yuzu-emu.org/help/reference/log-files/'>"
+ "How to Upload the Log File</a>. "));
break;
-
default:
if (result > Core::SystemResultStatus::ErrorLoader) {
const u16 loader_id = static_cast<u16>(Core::SystemResultStatus::ErrorLoader);
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index 936914ef3..a610e7e25 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -74,7 +74,6 @@ struct Values {
QString game_dir_deprecated;
bool game_dir_deprecated_deepscan;
QVector<UISettings::GameDir> game_dirs;
- QVector<u64> favorited_ids;
QStringList recent_files;
QString language;
@@ -96,6 +95,8 @@ struct Values {
Settings::BasicSetting<uint8_t> row_2_text_id{2, "row_2_text_id"};
std::atomic_bool is_game_list_reload_pending{false};
Settings::BasicSetting<bool> cache_game_list{true, "cache_game_list"};
+ Settings::BasicSetting<bool> favorites_expanded{true, "favorites_expanded"};
+ QVector<u64> favorited_ids;
bool configuration_applied;
bool reset_to_defaults;