diff options
-rw-r--r-- | src/input_common/drivers/udp_client.cpp | 74 | ||||
-rw-r--r-- | src/input_common/helpers/udp_protocol.h | 21 | ||||
-rw-r--r-- | src/tests/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/tests/input_common/calibration_configuration_job.cpp | 136 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.h | 2 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 50 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/blit_image.cpp | 123 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/blit_image.h | 30 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_blit_screen.cpp | 37 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_texture_cache.cpp | 34 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_texture_cache.h | 8 | ||||
-rw-r--r-- | src/video_core/texture_cache/texture_cache.h | 15 | ||||
-rw-r--r-- | src/yuzu/configuration/config.cpp | 2 | ||||
-rw-r--r-- | src/yuzu/game_list.cpp | 19 | ||||
-rw-r--r-- | src/yuzu/uisettings.h | 3 |
15 files changed, 354 insertions, 203 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 5aaeb16ca..2e19fced2 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1855,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/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; |