From 1e0ba7e98d9513045950e4a2999ef390b88f33b6 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Fri, 28 Mar 2025 23:29:14 +0100 Subject: [PATCH] Overlays: Allow to play save data movies in save data list --- rpcs3/Emu/CMakeLists.txt | 1 + rpcs3/Emu/Cell/Modules/cellSaveData.cpp | 4 +- rpcs3/Emu/Cell/Modules/cellSaveData.h | 2 +- rpcs3/Emu/RSX/GL/GLOverlays.cpp | 25 ++-- rpcs3/Emu/RSX/GL/GLOverlays.h | 4 +- .../HomeMenu/overlay_home_menu_components.cpp | 2 +- .../HomeMenu/overlay_home_menu_components.h | 6 +- .../overlay_home_menu_message_box.cpp | 2 +- .../HomeMenu/overlay_home_menu_page.cpp | 6 +- .../RSX/Overlays/overlay_animated_icon.cpp | 2 +- rpcs3/Emu/RSX/Overlays/overlay_controls.cpp | 81 +++++++----- rpcs3/Emu/RSX/Overlays/overlay_controls.h | 29 +++-- rpcs3/Emu/RSX/Overlays/overlay_edit_text.cpp | 4 +- rpcs3/Emu/RSX/Overlays/overlay_list_view.cpp | 13 +- rpcs3/Emu/RSX/Overlays/overlay_message.cpp | 2 +- .../Emu/RSX/Overlays/overlay_perf_metrics.cpp | 2 +- .../Emu/RSX/Overlays/overlay_progress_bar.cpp | 8 +- .../Emu/RSX/Overlays/overlay_save_dialog.cpp | 37 +++--- rpcs3/Emu/RSX/Overlays/overlay_save_dialog.h | 11 +- rpcs3/Emu/RSX/Overlays/overlay_video.cpp | 116 ++++++++++++++++++ rpcs3/Emu/RSX/Overlays/overlay_video.h | 40 ++++++ rpcs3/Emu/RSX/VK/VKOverlays.cpp | 69 +++++++---- rpcs3/Emu/RSX/VK/VKOverlays.h | 5 +- rpcs3/Emu/System.h | 1 + rpcs3/emucore.vcxproj | 2 + rpcs3/emucore.vcxproj.filters | 6 + rpcs3/headless_application.cpp | 3 + rpcs3/rpcs3qt/gui_application.cpp | 3 + rpcs3/rpcs3qt/qt_video_source.cpp | 28 ++++- rpcs3/rpcs3qt/qt_video_source.h | 13 +- rpcs3/rpcs3qt/save_data_dialog.cpp | 4 +- rpcs3/rpcs3qt/save_data_dialog.h | 2 +- rpcs3/rpcs3qt/save_manager_dialog.cpp | 2 +- rpcs3/rpcs3qt/save_manager_dialog.h | 2 +- rpcs3/util/video_source.h | 29 +++-- 35 files changed, 421 insertions(+), 145 deletions(-) create mode 100644 rpcs3/Emu/RSX/Overlays/overlay_video.cpp create mode 100644 rpcs3/Emu/RSX/Overlays/overlay_video.h diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 743b6c88d3..d68ab8c795 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -546,6 +546,7 @@ target_sources(rpcs3_emu PRIVATE RSX/Overlays/overlay_trophy_notification.cpp RSX/Overlays/overlay_user_list_dialog.cpp RSX/Overlays/overlay_utils.cpp + RSX/Overlays/overlay_video.cpp RSX/Overlays/Shaders/shader_loading_dialog.cpp RSX/Overlays/Shaders/shader_loading_dialog_native.cpp RSX/Program/CgBinaryFragmentProgram.cpp diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index be7583074a..7c54db0173 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -307,7 +307,7 @@ static error_code select_and_delete(ppu_thread& ppu) // Display a blocking Save Data List asynchronously in the GUI thread. if (auto save_dialog = Emu.GetCallbacks().get_save_dialog()) { - selected = save_dialog->ShowSaveDataList(save_entries, focused, SAVEDATA_OP_LIST_DELETE, vm::null, g_fxo->get().enable_overlay); + selected = save_dialog->ShowSaveDataList(base_dir, save_entries, focused, SAVEDATA_OP_LIST_DELETE, vm::null, g_fxo->get().enable_overlay); } // Reschedule after a blocking dialog returns @@ -1183,7 +1183,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v // Display a blocking Save Data List asynchronously in the GUI thread. if (auto save_dialog = Emu.GetCallbacks().get_save_dialog()) { - selected = save_dialog->ShowSaveDataList(save_entries, focused, operation, listSet, g_fxo->get().enable_overlay); + selected = save_dialog->ShowSaveDataList(base_dir, save_entries, focused, operation, listSet, g_fxo->get().enable_overlay); } else { diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.h b/rpcs3/Emu/Cell/Modules/cellSaveData.h index 73b0af4f01..0632c2500b 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.h +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.h @@ -361,5 +361,5 @@ class SaveDialogBase public: virtual ~SaveDialogBase(); - virtual s32 ShowSaveDataList(std::vector& save_entries, s32 focused, u32 op, vm::ptr listSet, bool enable_overlay) = 0; + virtual s32 ShowSaveDataList(const std::string& base_dir, std::vector& save_entries, s32 focused, u32 op, vm::ptr listSet, bool enable_overlay) = 0; }; diff --git a/rpcs3/Emu/RSX/GL/GLOverlays.cpp b/rpcs3/Emu/RSX/GL/GLOverlays.cpp index c5fac83404..983bed6f85 100644 --- a/rpcs3/Emu/RSX/GL/GLOverlays.cpp +++ b/rpcs3/Emu/RSX/GL/GLOverlays.cpp @@ -218,12 +218,12 @@ namespace gl m_input_filter = gl::filter::linear; } - gl::texture_view* ui_overlay_renderer::load_simple_image(rsx::overlays::image_info* desc, bool temp_resource, u32 owner_uid) + gl::texture_view* ui_overlay_renderer::load_simple_image(rsx::overlays::image_info_base* desc, bool temp_resource, u32 owner_uid) { auto tex = std::make_unique(GL_TEXTURE_2D, desc->w, desc->h, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR); tex->copy_from(desc->get_data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {}); - GLenum remap[] = { GL_RED, GL_ALPHA, GL_BLUE, GL_GREEN }; + const GLenum remap[] = { GL_RED, GL_ALPHA, GL_BLUE, GL_GREEN }; auto view = std::make_unique(tex.get(), remap); auto result = view.get(); @@ -234,7 +234,7 @@ namespace gl } else { - u64 key = reinterpret_cast(desc); + const u64 key = reinterpret_cast(desc); temp_image_cache[key] = std::make_pair(owner_uid, std::move(tex)); temp_view_cache[key] = std::move(view); } @@ -249,7 +249,7 @@ namespace gl rsx::overlays::resource_config configuration; configuration.load_files(); - for (const auto &res : configuration.texture_raw_data) + for (const auto& res : configuration.texture_raw_data) { load_simple_image(res.get(), false, -1); } @@ -318,13 +318,22 @@ namespace gl return result; } - gl::texture_view* ui_overlay_renderer::find_temp_image(rsx::overlays::image_info* desc, u32 owner_uid) + gl::texture_view* ui_overlay_renderer::find_temp_image(rsx::overlays::image_info_base* desc, u32 owner_uid) { - auto key = reinterpret_cast(desc); + const bool dirty = std::exchange(desc->dirty, false); + const u64 key = reinterpret_cast(desc); + auto cached = temp_view_cache.find(key); if (cached != temp_view_cache.end()) { - return cached->second.get(); + gl::texture_view* view = cached->second.get(); + + if (dirty) + { + view->image()->copy_from(desc->get_data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {}); + } + + return view; } return load_simple_image(desc, true, owner_uid); @@ -420,7 +429,7 @@ namespace gl } case rsx::overlays::image_resource_id::raw_image: { - cmd_->bind_texture(31, GL_TEXTURE_2D, find_temp_image(static_cast(cmd.config.external_data_ref), ui.uid)->id()); + cmd_->bind_texture(31, GL_TEXTURE_2D, find_temp_image(static_cast(cmd.config.external_data_ref), ui.uid)->id()); break; } case rsx::overlays::image_resource_id::font_file: diff --git a/rpcs3/Emu/RSX/GL/GLOverlays.h b/rpcs3/Emu/RSX/GL/GLOverlays.h index f70e885d2e..bd2be2d0ed 100644 --- a/rpcs3/Emu/RSX/GL/GLOverlays.h +++ b/rpcs3/Emu/RSX/GL/GLOverlays.h @@ -75,7 +75,7 @@ namespace gl ui_overlay_renderer(); - gl::texture_view* load_simple_image(rsx::overlays::image_info* desc, bool temp_resource, u32 owner_uid); + gl::texture_view* load_simple_image(rsx::overlays::image_info_base* desc, bool temp_resource, u32 owner_uid); void create(); void destroy(); @@ -84,7 +84,7 @@ namespace gl gl::texture_view* find_font(rsx::overlays::font* font); - gl::texture_view* find_temp_image(rsx::overlays::image_info* desc, u32 owner_uid); + gl::texture_view* find_temp_image(rsx::overlays::image_info_base* desc, u32 owner_uid); void set_primitive_type(rsx::overlays::primitive_type type); diff --git a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_components.cpp b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_components.cpp index c1c685210b..d0ed9dc460 100644 --- a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_components.cpp +++ b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_components.cpp @@ -40,7 +40,7 @@ namespace rsx { update_value(); - if (!is_compiled) + if (!is_compiled()) { const f32 col = m_last_value ? 1.0f : 0.3f; const f32 bkg = m_last_value ? 0.3f : 1.0f; diff --git a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_components.h b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_components.h index 186f67c3fe..7a54acddd8 100644 --- a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_components.h +++ b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_components.h @@ -64,7 +64,7 @@ namespace rsx if (const T new_value = m_setting->get(); new_value != m_last_value || initializing) { m_last_value = new_value; - is_compiled = false; + m_is_compiled = false; } } } @@ -101,7 +101,7 @@ namespace rsx { this->update_value(); - if (!this->is_compiled) + if (!this->is_compiled()) { const std::string value_text = Emu.GetCallbacks().get_localized_setting(home_menu_setting>::m_setting, static_cast(this->m_last_value)); m_dropdown.set_text(value_text); @@ -145,7 +145,7 @@ namespace rsx { this->update_value(); - if (!this->is_compiled) + if (!this->is_compiled()) { const f64 percentage = std::clamp((this->m_last_value - static_cast(m_minimum)) / std::fabs(m_maximum - m_minimum), 0.0, 1.0); m_slider.set_pos(m_slider.x, this->y + (this->h - m_slider.h) / 2); diff --git a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_message_box.cpp b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_message_box.cpp index 1f1ac3c5fa..4d9196ad07 100644 --- a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_message_box.cpp +++ b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_message_box.cpp @@ -44,7 +44,7 @@ namespace rsx compiled_resource& home_menu_message_box::get_compiled() { - if (!is_compiled) + if (!is_compiled()) { compiled_resource& compiled = overlay_element::get_compiled(); compiled.add(m_label.get_compiled()); diff --git a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_page.cpp b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_page.cpp index 9be95e016b..f298de0a81 100644 --- a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_page.cpp +++ b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_page.cpp @@ -258,9 +258,9 @@ namespace rsx compiled_resource& home_menu_page::get_compiled() { - if (!is_compiled || (m_message_box && !m_message_box->is_compiled)) + if (!is_compiled() || (m_message_box && !m_message_box->is_compiled())) { - is_compiled = false; + m_is_compiled = false; if (home_menu_page* page = get_current_page(false)) { @@ -281,7 +281,7 @@ namespace rsx } } - is_compiled = true; + m_is_compiled = true; } return compiled_resources; diff --git a/rpcs3/Emu/RSX/Overlays/overlay_animated_icon.cpp b/rpcs3/Emu/RSX/Overlays/overlay_animated_icon.cpp index 55f1f5dc84..7361856976 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_animated_icon.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_animated_icon.cpp @@ -58,7 +58,7 @@ namespace rsx compiled_resource& animated_icon::get_compiled() { - if (!is_compiled) + if (!is_compiled()) { compiled_resources = image_view::get_compiled(); } diff --git a/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp b/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp index ca6410e19a..23e7fccb55 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp @@ -302,7 +302,7 @@ namespace rsx void overlay_element::refresh() { // Just invalidate for draw when get_compiled() is called - is_compiled = false; + m_is_compiled = false; } void overlay_element::translate(s16 _x, s16 _y) @@ -310,7 +310,7 @@ namespace rsx x += _x; y += _y; - is_compiled = false; + m_is_compiled = false; } void overlay_element::scale(f32 _x, f32 _y, bool origin_scaling) @@ -324,7 +324,7 @@ namespace rsx w = static_cast(_x * w); h = static_cast(_y * h); - is_compiled = false; + m_is_compiled = false; } void overlay_element::set_pos(s16 _x, s16 _y) @@ -332,7 +332,7 @@ namespace rsx x = _x; y = _y; - is_compiled = false; + m_is_compiled = false; } void overlay_element::set_size(u16 _w, u16 _h) @@ -340,7 +340,7 @@ namespace rsx w = _w; h = _h; - is_compiled = false; + m_is_compiled = false; } void overlay_element::set_padding(u16 left, u16 right, u16 top, u16 bottom) @@ -350,13 +350,13 @@ namespace rsx padding_top = top; padding_bottom = bottom; - is_compiled = false; + m_is_compiled = false; } void overlay_element::set_padding(u16 padding) { padding_left = padding_right = padding_top = padding_bottom = padding; - is_compiled = false; + m_is_compiled = false; } // NOTE: Functions as a simple position offset. Top left corner is the anchor. @@ -365,25 +365,36 @@ namespace rsx margin_left = left; margin_top = top; - is_compiled = false; + m_is_compiled = false; } void overlay_element::set_margin(u16 margin) { margin_left = margin_top = margin; - is_compiled = false; + m_is_compiled = false; } void overlay_element::set_text(const std::string& text) { - this->text = utf8_to_u32string(text); - is_compiled = false; + std::u32string new_text = utf8_to_u32string(text); + const bool is_dirty = this->text != new_text; + this->text = std::move(new_text); + + if (is_dirty) + { + m_is_compiled = false; + } } void overlay_element::set_unicode_text(const std::u32string& text) { + const bool is_dirty = this->text != text; this->text = text; - is_compiled = false; + + if (is_dirty) + { + m_is_compiled = false; + } } void overlay_element::set_text(localized_string_id id) @@ -394,19 +405,19 @@ namespace rsx void overlay_element::set_font(const char* font_name, u16 font_size) { font_ref = fontmgr::get(font_name, font_size); - is_compiled = false; + m_is_compiled = false; } void overlay_element::align_text(text_align align) { alignment = align; - is_compiled = false; + m_is_compiled = false; } void overlay_element::set_wrap_text(bool state) { wrap_text = state; - is_compiled = false; + m_is_compiled = false; } font* overlay_element::get_font() const @@ -563,7 +574,7 @@ namespace rsx compiled_resource& overlay_element::get_compiled() { - if (!is_compiled) + if (!is_compiled()) { compiled_resources.clear(); @@ -599,7 +610,7 @@ namespace rsx compiled_resources.add(std::move(compiled_resources_temp), margin_left - horizontal_scroll_offset, margin_top - vertical_scroll_offset); } - is_compiled = true; + m_is_compiled = true; } return compiled_resources; @@ -664,7 +675,7 @@ namespace rsx { overlay_element::translate(_x, _y); - for (auto &itm : m_items) + for (auto& itm : m_items) itm->translate(_x, _y); } @@ -675,13 +686,23 @@ namespace rsx translate(dx, dy); } + bool layout_container::is_compiled() + { + if (m_is_compiled && std::any_of(m_items.cbegin(), m_items.cend(), [](const auto& item){ return item && !item->is_compiled(); })) + { + m_is_compiled = false; + } + + return m_is_compiled; + } + compiled_resource& layout_container::get_compiled() { - if (!is_compiled) + if (!is_compiled()) { compiled_resource result = overlay_element::get_compiled(); - for (auto &itm : m_items) + for (auto& itm : m_items) result.add(itm->get_compiled()); compiled_resources = result; @@ -716,7 +737,7 @@ namespace rsx return m_items.back().get(); } - auto result = item.get(); + overlay_element* result = item.get(); m_items.insert(m_items.begin() + offset, std::move(item)); return result; } @@ -726,12 +747,12 @@ namespace rsx if (scroll_offset_value == 0 && auto_resize) return layout_container::get_compiled(); - if (!is_compiled) + if (!is_compiled()) { compiled_resource result = overlay_element::get_compiled(); const f32 global_y_offset = static_cast(-scroll_offset_value); - for (auto &item : m_items) + for (auto& item : m_items) { if (!item) { @@ -808,7 +829,7 @@ namespace rsx if (scroll_offset_value == 0 && auto_resize) return layout_container::get_compiled(); - if (!is_compiled) + if (!is_compiled()) { compiled_resource result = overlay_element::get_compiled(); const f32 global_x_offset = static_cast(-scroll_offset_value); @@ -862,7 +883,7 @@ namespace rsx compiled_resource& image_view::get_compiled() { - if (!is_compiled) + if (!is_compiled()) { auto& result = overlay_element::get_compiled(); auto& cmd_img = result.draw_commands.front(); @@ -880,7 +901,7 @@ namespace rsx verts[2] += vertex(padding_left, -padding_top, 0, 0); verts[3] += vertex(-padding_right, -padding_top, 0, 0); - is_compiled = true; + m_is_compiled = true; } return compiled_resources; @@ -892,7 +913,7 @@ namespace rsx external_ref = nullptr; } - void image_view::set_raw_image(image_info* raw_image) + void image_view::set_raw_image(image_info_base* raw_image) { image_resource_ref = image_resource_id::raw_image; external_ref = raw_image; @@ -935,7 +956,7 @@ namespace rsx compiled_resource& image_button::get_compiled() { - if (!is_compiled) + if (!is_compiled()) { auto& compiled = image_view::get_compiled(); for (auto& cmd : compiled.draw_commands) @@ -987,7 +1008,7 @@ namespace rsx compiled_resource& rounded_rect::get_compiled() { - if (!is_compiled) + if (!is_compiled()) { compiled_resources.clear(); @@ -1068,7 +1089,7 @@ namespace rsx compiled_resources.add(std::move(compiled_resources_temp), margin_left, margin_top); } - is_compiled = true; + m_is_compiled = true; } return compiled_resources; diff --git a/rpcs3/Emu/RSX/Overlays/overlay_controls.h b/rpcs3/Emu/RSX/Overlays/overlay_controls.h index 0229767af8..b6dd2b84da 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_controls.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_controls.h @@ -30,23 +30,29 @@ namespace rsx triangle_fan = 4 }; - struct image_info + struct image_info_base + { + int w = 0, h = 0, channels = 0; + int bpp = 0; + bool dirty = false; + + virtual const u8* get_data() const = 0; + }; + + struct image_info : public image_info_base { private: u8* data = nullptr; std::vector data_grey; public: - int w = 0, h = 0, channels = 0; - int bpp = 0; - image_info(image_info&) = delete; image_info(const std::string& filename, bool grayscaled = false); image_info(const std::vector& bytes, bool grayscaled = false); ~image_info(); void load_data(const std::vector& bytes, bool grayscaled = false); - const u8* get_data() const { return channels == 4 ? data : data_grey.empty() ? nullptr : data_grey.data(); } + const u8* get_data() const override { return channels == 4 ? data : data_grey.empty() ? nullptr : data_grey.data(); } }; struct resource_config @@ -165,7 +171,6 @@ namespace rsx void set_sinus_offset(f32 sinus_modifier); compiled_resource compiled_resources; - bool is_compiled = false; bool visible = true; @@ -185,6 +190,7 @@ namespace rsx virtual ~overlay_element() = default; virtual void refresh(); + virtual bool is_compiled() { return m_is_compiled; } virtual void translate(s16 _x, s16 _y); virtual void scale(f32 _x, f32 _y, bool origin_scaling); virtual void set_pos(s16 _x, s16 _y); @@ -204,6 +210,10 @@ namespace rsx virtual std::vector render_text(const char32_t* string, f32 x, f32 y); virtual compiled_resource& get_compiled(); void measure_text(u16& width, u16& height, bool ignore_word_wrap = false) const; + virtual void set_selected(bool selected) { static_cast(selected); } + + protected: + bool m_is_compiled = false; // Only use m_is_compiled as a getter in is_compiled() if possible }; struct layout_container : public overlay_element @@ -221,6 +231,8 @@ namespace rsx void translate(s16 _x, s16 _y) override; void set_pos(s16 _x, s16 _y) override; + bool is_compiled() override; + compiled_resource& get_compiled() override; virtual u16 get_scroll_offset_px() = 0; @@ -248,6 +260,7 @@ namespace rsx compiled_resource& get_compiled() override { // No draw + m_is_compiled = true; return compiled_resources; } }; @@ -263,7 +276,7 @@ namespace rsx struct image_view : public overlay_element { - private: + protected: u8 image_resource_ref = image_resource_id::none; void* external_ref = nullptr; @@ -276,7 +289,7 @@ namespace rsx compiled_resource& get_compiled() override; void set_image_resource(u8 resource_id); - void set_raw_image(image_info* raw_image); + void set_raw_image(image_info_base* raw_image); void clear_image(); void set_blur_strength(u8 strength); }; diff --git a/rpcs3/Emu/RSX/Overlays/overlay_edit_text.cpp b/rpcs3/Emu/RSX/Overlays/overlay_edit_text.cpp index 7658563bcc..ce2b685046 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_edit_text.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_edit_text.cpp @@ -196,7 +196,7 @@ namespace rsx compiled_resource& edit_text::get_compiled() { - if (!is_compiled) + if (!is_compiled()) { auto renderer = get_font(); const auto [caret_x, caret_y] = renderer->get_char_offset(text.c_str(), caret_position, clip_text ? w : -1, wrap_text); @@ -252,7 +252,7 @@ namespace rsx cmd.config.clip_rect = {static_cast(x), static_cast(y), static_cast(x + w), static_cast(y + h)}; } - is_compiled = true; + m_is_compiled = true; } return compiled_resources; diff --git a/rpcs3/Emu/RSX/Overlays/overlay_list_view.cpp b/rpcs3/Emu/RSX/Overlays/overlay_list_view.cpp index 0802d3ff95..093902dbe3 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_list_view.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_list_view.cpp @@ -91,6 +91,15 @@ namespace rsx void list_view::update_selection() { const overlay_element* current_element = get_selected_entry(); + + for (auto& item : m_items) + { + if (item) + { + item->set_selected(item.get() == current_element); + } + } + if (!current_element) { return; // Ideally unreachable but it should still be possible to recover by user interaction. @@ -195,7 +204,7 @@ namespace rsx m_cancel_btn->set_pos(x + 180, y + h + 20); m_cancel_only = cancel_only; - is_compiled = false; + m_is_compiled = false; } bool list_view::get_cancel_only() const @@ -219,7 +228,7 @@ namespace rsx compiled_resource& list_view::get_compiled() { - if (!is_compiled) + if (!is_compiled()) { auto& compiled = vertical_layout::get_compiled(); compiled.add(m_highlight_box->get_compiled()); diff --git a/rpcs3/Emu/RSX/Overlays/overlay_message.cpp b/rpcs3/Emu/RSX/Overlays/overlay_message.cpp index b00f0cc5b3..218f7a2a3a 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_message.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_message.cpp @@ -100,7 +100,7 @@ namespace rsx } // Disable caching - is_compiled = false; + m_is_compiled = false; compiled_resources = rounded_rect::get_compiled(); compiled_resources.add(m_text.get_compiled()); diff --git a/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp b/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp index 0c4b9becac..8b68357208 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp @@ -814,7 +814,7 @@ namespace rsx compiled_resource& graph::get_compiled() { - if (is_compiled) + if (is_compiled()) { return compiled_resources; } diff --git a/rpcs3/Emu/RSX/Overlays/overlay_progress_bar.cpp b/rpcs3/Emu/RSX/Overlays/overlay_progress_bar.cpp index ee9ce7b4d3..860f54544a 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_progress_bar.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_progress_bar.cpp @@ -23,7 +23,7 @@ namespace rsx void progress_bar::set_limit(f32 limit) { m_limit = limit; - is_compiled = false; + m_is_compiled = false; } void progress_bar::set_value(f32 value) @@ -32,7 +32,7 @@ namespace rsx f32 indicator_width = (w * m_value) / m_limit; indicator.set_size(static_cast(indicator_width), h); - is_compiled = false; + m_is_compiled = false; } void progress_bar::set_pos(s16 _x, s16 _y) @@ -68,12 +68,12 @@ namespace rsx text_view.set_size(w, text_h); set_pos(text_view.x, text_view.y); - is_compiled = false; + m_is_compiled = false; } compiled_resource& progress_bar::get_compiled() { - if (!is_compiled) + if (!is_compiled()) { auto& compiled = overlay_element::get_compiled(); compiled.add(text_view.get_compiled()); diff --git a/rpcs3/Emu/RSX/Overlays/overlay_save_dialog.cpp b/rpcs3/Emu/RSX/Overlays/overlay_save_dialog.cpp index 1754b3694c..86e9905f2f 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_save_dialog.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_save_dialog.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "overlay_save_dialog.h" +#include "overlay_video.h" #include "Utilities/date_time.h" #include "Emu/System.h" @@ -7,26 +8,18 @@ namespace rsx { namespace overlays { - save_dialog::save_dialog_entry::save_dialog_entry(const std::string& text1, const std::string& text2, const std::string& text3, u8 resource_id, const std::vector& icon_buf) + save_dialog::save_dialog_entry::save_dialog_entry(const std::string& text1, const std::string& text2, const std::string& text3, u8 resource_id, const std::vector& icon_buf, const std::string& video_path) { - std::unique_ptr image = std::make_unique(); + std::unique_ptr image = resource_id != image_resource_id::raw_image + ? std::make_unique(video_path, resource_id) + : !icon_buf.empty() ? std::make_unique(video_path, icon_buf) + : std::make_unique(video_path, resource_config::standard_image_resource::save); // Fallback image->set_size(160, 110); image->set_padding(36, 36, 11, 11); // Square image, 88x88 - if (resource_id != image_resource_id::raw_image) - { - static_cast(image.get())->set_image_resource(resource_id); - } - else if (!icon_buf.empty()) + if (resource_id == image_resource_id::raw_image && !icon_buf.empty()) { image->set_padding(0, 0, 11, 11); // Half sized icon, 320x176->160x88 - icon_data = std::make_unique(icon_buf); - static_cast(image.get())->set_raw_image(icon_data.get()); - } - else - { - // Fallback - static_cast(image.get())->set_image_resource(resource_config::standard_image_resource::save); } std::unique_ptr text_stack = std::make_unique(); @@ -74,10 +67,18 @@ namespace rsx // Pack this->pack_padding = 15; - add_element(image); + m_image = add_element(image); add_element(text_stack); } + void save_dialog::save_dialog_entry::set_selected(bool selected) + { + if (m_image) + { + static_cast(m_image)->set_active(selected); + } + } + save_dialog::save_dialog() { m_dim_background = std::make_unique(); @@ -197,7 +198,7 @@ namespace rsx return result; } - s32 save_dialog::show(std::vector& save_entries, u32 focused, u32 op, vm::ptr listSet, bool enable_overlay) + s32 save_dialog::show(const std::string& base_dir, std::vector& save_entries, u32 focused, u32 op, vm::ptr listSet, bool enable_overlay) { rsx_log.notice("Showing native UI save_dialog (save_entries=%d, focused=%d, op=0x%x, listSet=*0x%x, enable_overlay=%d)", save_entries.size(), focused, op, listSet, enable_overlay); @@ -218,7 +219,7 @@ namespace rsx { const std::string date_and_size = fmt::format("%s %s", entry.date(), entry.data_size()); std::unique_ptr e; - e = std::make_unique(entry.subtitle, date_and_size, entry.details, image_resource_id::raw_image, entry.iconBuf); + e = std::make_unique(entry.subtitle, date_and_size, entry.details, image_resource_id::raw_image, entry.iconBuf, base_dir + entry.dirName + "/ICON1.PAM"); entries.emplace_back(std::move(e)); } @@ -270,7 +271,7 @@ namespace rsx id = image_resource_id::raw_image; } - std::unique_ptr new_stub = std::make_unique(title, get_localized_string(localized_string_id::CELL_SAVEDATA_NEW_SAVED_DATA_SUB_TITLE), "", id, icon); + std::unique_ptr new_stub = std::make_unique(title, get_localized_string(localized_string_id::CELL_SAVEDATA_NEW_SAVED_DATA_SUB_TITLE), "", id, icon, ""); m_list->add_entry(new_stub); } diff --git a/rpcs3/Emu/RSX/Overlays/overlay_save_dialog.h b/rpcs3/Emu/RSX/Overlays/overlay_save_dialog.h index e33119cc72..0c65379153 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_save_dialog.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_save_dialog.h @@ -13,11 +13,12 @@ namespace rsx private: struct save_dialog_entry : horizontal_layout { - private: - std::unique_ptr icon_data; - public: - save_dialog_entry(const std::string& text1, const std::string& text2, const std::string& text3, u8 resource_id, const std::vector& icon_buf); + save_dialog_entry(const std::string& text1, const std::string& text2, const std::string& text3, u8 resource_id, const std::vector& icon_buf, const std::string& video_path); + void set_selected(bool selected) override; + + private: + overlay_element* m_image = nullptr; }; std::unique_ptr m_dim_background; @@ -38,7 +39,7 @@ namespace rsx compiled_resource get_compiled() override; - s32 show(std::vector& save_entries, u32 focused, u32 op, vm::ptr listSet, bool enable_overlay); + s32 show(const std::string& base_dir, std::vector& save_entries, u32 focused, u32 op, vm::ptr listSet, bool enable_overlay); }; } } diff --git a/rpcs3/Emu/RSX/Overlays/overlay_video.cpp b/rpcs3/Emu/RSX/Overlays/overlay_video.cpp new file mode 100644 index 0000000000..ac6017d35f --- /dev/null +++ b/rpcs3/Emu/RSX/Overlays/overlay_video.cpp @@ -0,0 +1,116 @@ +#include "stdafx.h" +#include "overlay_video.h" +#include "Emu/System.h" + +namespace rsx +{ + namespace overlays + { + video_view::video_view(const std::string& video_path, const std::string& thumbnail_path) + { + init_video(video_path); + + if (!thumbnail_path.empty()) + { + m_thumbnail_info = std::make_unique(thumbnail_path); + set_raw_image(m_thumbnail_info.get()); + } + } + + video_view::video_view(const std::string& video_path, const std::vector& thumbnail_buf) + { + init_video(video_path); + + if (!thumbnail_buf.empty()) + { + m_thumbnail_info = std::make_unique(thumbnail_buf); + set_raw_image(m_thumbnail_info.get()); + } + } + + video_view::video_view(const std::string& video_path, u8 thumbnail_id) + : m_thumbnail_id(thumbnail_id) + { + init_video(video_path); + set_image_resource(thumbnail_id); + } + + video_view::~video_view() + { + } + + void video_view::init_video(const std::string& video_path) + { + if (video_path.empty()) return; + + m_video_source = Emu.GetCallbacks().make_video_source(); + ensure(!!m_video_source); + + m_video_source->set_update_callback([this]() + { + if (m_video_active) + { + m_is_compiled = false; + } + }); + m_video_source->set_video_path(video_path); + } + + void video_view::set_active(bool active) + { + if (m_video_source) + { + m_video_source->set_active(active); + m_video_active = active; + m_is_compiled = false; + } + } + + void video_view::update() + { + if (m_video_active && m_video_source && m_video_source->get_active()) + { + if (!m_video_source->has_new()) + { + return; + } + + m_buffer_index = (m_buffer_index + 1) % m_video_info.size(); + + auto& info = m_video_info.at(m_buffer_index); + if (!info) + { + info = std::make_unique(); + } + + m_video_source->get_image(info->data, info->w, info->h, info->channels, info->bpp); + info->dirty = true; + + set_raw_image(info.get()); + m_is_compiled = false; + return; + } + + if (m_thumbnail_info && m_thumbnail_info.get() != external_ref) + { + set_raw_image(m_thumbnail_info.get()); + m_is_compiled = false; + return; + } + + if (m_thumbnail_id != image_resource_id::none && m_thumbnail_id != image_resource_ref) + { + set_image_resource(m_thumbnail_id); + m_is_compiled = false; + return; + } + } + + compiled_resource& video_view::get_compiled() + { + update(); + + return external_ref ? image_view::get_compiled() : overlay_element::get_compiled(); + } + } +} diff --git a/rpcs3/Emu/RSX/Overlays/overlay_video.h b/rpcs3/Emu/RSX/Overlays/overlay_video.h new file mode 100644 index 0000000000..bdff580f0e --- /dev/null +++ b/rpcs3/Emu/RSX/Overlays/overlay_video.h @@ -0,0 +1,40 @@ +#pragma once + +#include "overlay_controls.h" +#include "util/video_source.h" + +namespace rsx +{ + namespace overlays + { + struct video_info : public image_info_base + { + std::vector data; + const u8* get_data() const override { return data.empty() ? nullptr : data.data(); } + }; + + class video_view final : public image_view + { + public: + video_view(const std::string& video_path, const std::string& thumbnail_path); + video_view(const std::string& video_path, const std::vector& thumbnail_buf); + video_view(const std::string& video_path, u8 thumbnail_id); + virtual ~video_view(); + + void set_active(bool active); + + void update(); + compiled_resource& get_compiled() override; + + private: + void init_video(const std::string& video_path); + + usz m_buffer_index = 0; + std::array, 2> m_video_info; // double buffer + std::unique_ptr m_video_source; + std::unique_ptr m_thumbnail_info; + u8 m_thumbnail_id = image_resource_id::none; + bool m_video_active = false; // This is the expected state. The actual state is found in the video source. + }; + } +} diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.cpp b/rpcs3/Emu/RSX/VK/VKOverlays.cpp index 2976d90c76..f195ee6c15 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.cpp +++ b/rpcs3/Emu/RSX/VK/VKOverlays.cpp @@ -386,22 +386,14 @@ namespace vk VK_BLEND_OP_ADD, VK_BLEND_OP_ADD); } - vk::image_view* ui_overlay_renderer::upload_simple_texture(vk::render_device& dev, vk::command_buffer& cmd, - vk::data_heap& upload_heap, u64 key, u32 w, u32 h, u32 layers, bool font, bool temp, const void* pixel_src, u32 owner_uid) + void ui_overlay_renderer::upload_simple_texture(vk::image* tex, vk::command_buffer& cmd, + vk::data_heap& upload_heap, u32 w, u32 h, u32 layers, bool font, const void* pixel_src) { - const VkFormat format = (font) ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM; const u32 pitch = (font) ? w : w * 4; const u32 data_size = pitch * h * layers; const auto offset = upload_heap.alloc<512>(data_size); const auto addr = upload_heap.map(offset, data_size); - const VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, layers }; - - auto tex = std::make_unique(dev, dev.get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - VK_IMAGE_TYPE_2D, format, std::max(w, 1u), std::max(h, 1u), 1, 1, layers, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - 0, VMM_ALLOCATION_POOL_UNDEFINED); - if (pixel_src && data_size) std::memcpy(addr, pixel_src, data_size); else if (data_size) @@ -409,17 +401,31 @@ namespace vk upload_heap.unmap(); - VkBufferImageCopy region; - region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, layers }; - region.bufferOffset = offset; - region.bufferRowLength = w; - region.bufferImageHeight = h; - region.imageOffset = {}; - region.imageExtent = { static_cast(w), static_cast(h), 1u }; - - change_image_layout(cmd, tex.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, range); + const VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, layers }; + VkBufferImageCopy region { + .bufferOffset = offset, + .bufferRowLength = w, + .bufferImageHeight = h, + .imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, layers }, + .imageOffset = {}, + .imageExtent = { static_cast(w), static_cast(h), 1u } + }; + change_image_layout(cmd, tex, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, range); vkCmdCopyBufferToImage(cmd, upload_heap.heap->value, tex->value, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - change_image_layout(cmd, tex.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, range); + change_image_layout(cmd, tex, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, range); + } + + vk::image_view* ui_overlay_renderer::upload_simple_texture(vk::render_device& dev, vk::command_buffer& cmd, + vk::data_heap& upload_heap, u64 key, u32 w, u32 h, u32 layers, bool font, bool temp, const void* pixel_src, u32 owner_uid) + { + const VkFormat format = (font) ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM; + + auto tex = std::make_unique(dev, dev.get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + VK_IMAGE_TYPE_2D, format, std::max(w, 1u), std::max(h, 1u), 1, 1, layers, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + 0, VMM_ALLOCATION_POOL_UNDEFINED); + + upload_simple_texture(tex.get(), cmd, upload_heap, w, h, layers, font, pixel_src); auto view = std::make_unique(dev, tex.get()); @@ -521,12 +527,23 @@ namespace vk true, false, bytes.data(), -1); } - vk::image_view* ui_overlay_renderer::find_temp_image(rsx::overlays::image_info* desc, vk::command_buffer& cmd, vk::data_heap& upload_heap, u32 owner_uid) + vk::image_view* ui_overlay_renderer::find_temp_image(rsx::overlays::image_info_base* desc, vk::command_buffer& cmd, vk::data_heap& upload_heap, u32 owner_uid) { - u64 key = reinterpret_cast(desc); - auto found = temp_view_cache.find(key); - if (found != temp_view_cache.end()) - return found->second.get(); + const bool dirty = std::exchange(desc->dirty, false); + const u64 key = reinterpret_cast(desc); + + auto cached = temp_view_cache.find(key); + if (cached != temp_view_cache.end()) + { + vk::image_view* view = cached->second.get(); + + if (dirty) + { + upload_simple_texture(view->image(), cmd, upload_heap, desc->w, desc->h, 1, false, desc->get_data()); + } + + return view; + } return upload_simple_texture(cmd.get_command_pool().get_owner(), cmd, upload_heap, key, desc->w, desc->h, 1, false, true, desc->get_data(), owner_uid); @@ -693,7 +710,7 @@ namespace vk : rsx::overlays::texture_sampling_mode::font3D; break; case rsx::overlays::image_resource_id::raw_image: - src = find_temp_image(static_cast(command.config.external_data_ref), cmd, upload_heap, ui.uid); + src = find_temp_image(static_cast(command.config.external_data_ref), cmd, upload_heap, ui.uid); break; default: src = view_cache[command.config.texture_ref].get(); diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.h b/rpcs3/Emu/RSX/VK/VKOverlays.h index 2b11285653..7308a5c894 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.h +++ b/rpcs3/Emu/RSX/VK/VKOverlays.h @@ -154,6 +154,9 @@ namespace vk ui_overlay_renderer(); + void upload_simple_texture(vk::image* tex, vk::command_buffer& cmd, + vk::data_heap& upload_heap, u32 w, u32 h, u32 layers, bool font, const void* pixel_src); + vk::image_view* upload_simple_texture(vk::render_device& dev, vk::command_buffer& cmd, vk::data_heap& upload_heap, u64 key, u32 w, u32 h, u32 layers, bool font, bool temp, const void* pixel_src, u32 owner_uid); @@ -164,7 +167,7 @@ namespace vk void remove_temp_resources(u32 key); vk::image_view* find_font(rsx::overlays::font* font, vk::command_buffer& cmd, vk::data_heap& upload_heap); - vk::image_view* find_temp_image(rsx::overlays::image_info* desc, vk::command_buffer& cmd, vk::data_heap& upload_heap, u32 owner_uid); + vk::image_view* find_temp_image(rsx::overlays::image_info_base* desc, vk::command_buffer& cmd, vk::data_heap& upload_heap, u32 owner_uid); std::vector get_push_constants() override; diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 2d9b2d954b..4306fe9658 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -111,6 +111,7 @@ struct EmuCallbacks std::function display_sleep_control_supported; std::function enable_display_sleep; std::function check_microphone_permissions; + std::function()> make_video_source; }; namespace utils diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 7a5234d01a..07414051ed 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -147,6 +147,7 @@ + @@ -682,6 +683,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 50e3e666a7..c0ef133d1a 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1354,6 +1354,9 @@ Emu\GPU\RSX\Common + + Emu\GPU\RSX\Overlays + @@ -2719,6 +2722,9 @@ Utilities + + Emu\GPU\RSX\Overlays + diff --git a/rpcs3/headless_application.cpp b/rpcs3/headless_application.cpp index ee7cd42cee..0d0eb8d834 100644 --- a/rpcs3/headless_application.cpp +++ b/rpcs3/headless_application.cpp @@ -8,6 +8,7 @@ #include "Emu/Cell/Modules/sceNpTrophy.h" #include "Emu/Io/Null/null_camera_handler.h" #include "Emu/Io/Null/null_music_handler.h" +#include "util/video_source.h" #include @@ -173,6 +174,8 @@ void headless_application::InitializeCallbacks() callbacks.check_microphone_permissions = [](){}; + callbacks.make_video_source = [](){ return nullptr; }; + Emu.SetCallbacks(std::move(callbacks)); } diff --git a/rpcs3/rpcs3qt/gui_application.cpp b/rpcs3/rpcs3qt/gui_application.cpp index 077e05ca68..b170737e43 100644 --- a/rpcs3/rpcs3qt/gui_application.cpp +++ b/rpcs3/rpcs3qt/gui_application.cpp @@ -27,6 +27,7 @@ #include "Emu/vfs_config.h" #include "util/init_mutex.hpp" #include "util/console.h" +#include "qt_video_source.h" #include "trophy_notification_helper.h" #include "save_data_dialog.h" #include "msg_dialog_frame.h" @@ -955,6 +956,8 @@ void gui_application::InitializeCallbacks() }); }; + callbacks.make_video_source = [](){ return std::make_unique(); }; + Emu.SetCallbacks(std::move(callbacks)); } diff --git a/rpcs3/rpcs3qt/qt_video_source.cpp b/rpcs3/rpcs3qt/qt_video_source.cpp index 2338c09bf8..9537f89127 100644 --- a/rpcs3/rpcs3qt/qt_video_source.cpp +++ b/rpcs3/rpcs3qt/qt_video_source.cpp @@ -14,9 +14,9 @@ qt_video_source::~qt_video_source() stop_movie(); } -void qt_video_source::set_video_path(const std::string& path) +void qt_video_source::set_video_path(const std::string& video_path) { - m_video_path = QString::fromStdString(path); + m_video_path = QString::fromStdString(video_path); } void qt_video_source::set_active(bool active) @@ -209,14 +209,14 @@ qt_video_source_wrapper::~qt_video_source_wrapper() }); } -void qt_video_source_wrapper::set_video_path(const std::string& path) +void qt_video_source_wrapper::set_video_path(const std::string& video_path) { - Emu.BlockingCallFromMainThread([this, &path]() + Emu.CallFromMainThread([this, path = video_path]() { m_qt_video_source = std::make_unique(); m_qt_video_source->m_image_change_callback = [this](const QVideoFrame& frame) { - std::lock_guard lock(m_qt_video_source->m_image_mutex); + std::unique_lock lock(m_qt_video_source->m_image_mutex); if (m_qt_video_source->m_movie) { @@ -236,12 +236,30 @@ void qt_video_source_wrapper::set_video_path(const std::string& path) { m_qt_video_source->m_image.convertTo(QImage::Format_RGBA8888); } + + lock.unlock(); + + notify_update(); }; m_qt_video_source->set_video_path(path); + }); +} + +void qt_video_source_wrapper::set_active(bool active) +{ + Emu.CallFromMainThread([this, active]() + { m_qt_video_source->set_active(true); }); } +bool qt_video_source_wrapper::get_active() const +{ + ensure(m_qt_video_source); + + return m_qt_video_source->get_active(); +} + void qt_video_source_wrapper::get_image(std::vector& data, int& w, int& h, int& ch, int& bpp) { ensure(m_qt_video_source); diff --git a/rpcs3/rpcs3qt/qt_video_source.h b/rpcs3/rpcs3qt/qt_video_source.h index f8b2267e5f..aa6e61af94 100644 --- a/rpcs3/rpcs3qt/qt_video_source.h +++ b/rpcs3/rpcs3qt/qt_video_source.h @@ -17,17 +17,14 @@ public: qt_video_source(); virtual ~qt_video_source(); - void set_video_path(const std::string& path) override; + void set_video_path(const std::string& video_path) override; const QString& video_path() const { return m_video_path; } void get_image(std::vector& data, int& w, int& h, int& ch, int& bpp) override; bool has_new() const override { return m_has_new; } virtual void set_active(bool active); - [[nodiscard]] bool get_active() const - { - return m_active; - } + bool get_active() const override { return m_active; } void start_movie(); void stop_movie(); @@ -67,9 +64,11 @@ public: qt_video_source_wrapper() : video_source() {} virtual ~qt_video_source_wrapper(); - void set_video_path(const std::string& path) override; - void get_image(std::vector& data, int& w, int& h, int& ch, int& bpp) override; + void set_video_path(const std::string& video_path) override; + void set_active(bool active) override; + bool get_active() const override; bool has_new() const override { return m_qt_video_source && m_qt_video_source->has_new(); } + void get_image(std::vector& data, int& w, int& h, int& ch, int& bpp) override; private: std::unique_ptr m_qt_video_source; diff --git a/rpcs3/rpcs3qt/save_data_dialog.cpp b/rpcs3/rpcs3qt/save_data_dialog.cpp index 105fd7d27c..f98f615e54 100644 --- a/rpcs3/rpcs3qt/save_data_dialog.cpp +++ b/rpcs3/rpcs3qt/save_data_dialog.cpp @@ -12,7 +12,7 @@ LOG_CHANNEL(cellSaveData); -s32 save_data_dialog::ShowSaveDataList(std::vector& save_entries, s32 focused, u32 op, vm::ptr listSet, bool enable_overlay) +s32 save_data_dialog::ShowSaveDataList(const std::string& base_dir, std::vector& save_entries, s32 focused, u32 op, vm::ptr listSet, bool enable_overlay) { cellSaveData.notice("ShowSaveDataList(save_entries=%d, focused=%d, op=0x%x, listSet=*0x%x, enable_overlay=%d)", save_entries.size(), focused, op, listSet, enable_overlay); @@ -29,7 +29,7 @@ s32 save_data_dialog::ShowSaveDataList(std::vector& save_entries, { cellSaveData.notice("ShowSaveDataList: Showing native UI dialog"); - const s32 result = manager->create()->show(save_entries, focused, op, listSet, enable_overlay); + const s32 result = manager->create()->show(base_dir, save_entries, focused, op, listSet, enable_overlay); if (result != rsx::overlays::user_interface::selection_code::error) { cellSaveData.notice("ShowSaveDataList: Native UI dialog returned with selection %d", result); diff --git a/rpcs3/rpcs3qt/save_data_dialog.h b/rpcs3/rpcs3qt/save_data_dialog.h index b33b16b77f..e98ee8e4ac 100644 --- a/rpcs3/rpcs3qt/save_data_dialog.h +++ b/rpcs3/rpcs3qt/save_data_dialog.h @@ -6,5 +6,5 @@ class save_data_dialog : public SaveDialogBase { public: - s32 ShowSaveDataList(std::vector& save_entries, s32 focused, u32 op, vm::ptr listSet, bool enable_overlay) override; + s32 ShowSaveDataList(const std::string& base_dir, std::vector& save_entries, s32 focused, u32 op, vm::ptr listSet, bool enable_overlay) override; }; diff --git a/rpcs3/rpcs3qt/save_manager_dialog.cpp b/rpcs3/rpcs3qt/save_manager_dialog.cpp index 9e3b51b8e2..5f3302be8a 100644 --- a/rpcs3/rpcs3qt/save_manager_dialog.cpp +++ b/rpcs3/rpcs3qt/save_manager_dialog.cpp @@ -586,7 +586,7 @@ void save_manager_dialog::OnEntriesRemove() } // Pop-up a small context-menu, being a replacement for save_data_manage_dialog -void save_manager_dialog::ShowContextMenu(const QPoint &pos) +void save_manager_dialog::ShowContextMenu(const QPoint& pos) { const int idx = m_list->currentRow(); if (idx == -1) diff --git a/rpcs3/rpcs3qt/save_manager_dialog.h b/rpcs3/rpcs3qt/save_manager_dialog.h index e685b2b6d5..791ee9a814 100644 --- a/rpcs3/rpcs3qt/save_manager_dialog.h +++ b/rpcs3/rpcs3qt/save_manager_dialog.h @@ -42,7 +42,7 @@ private: void Init(); void UpdateList(); void UpdateIcons(); - void ShowContextMenu(const QPoint &pos); + void ShowContextMenu(const QPoint& pos); void WaitForRepaintThreads(bool abort); void closeEvent(QCloseEvent* event) override; diff --git a/rpcs3/util/video_source.h b/rpcs3/util/video_source.h index b5737bccc0..9449ed238e 100644 --- a/rpcs3/util/video_source.h +++ b/rpcs3/util/video_source.h @@ -1,20 +1,33 @@ #pragma once #include "types.hpp" +#include class video_source { public: video_source() {}; virtual ~video_source() {}; - virtual void set_video_path(const std::string& path) { static_cast(path); } - virtual bool has_new() const { return false; }; - virtual void get_image(std::vector& data, int& w, int& h, int& ch, int& bpp) + virtual void set_video_path(const std::string& video_path) = 0; + virtual void set_active(bool active) = 0; + virtual bool get_active() const = 0; + virtual bool has_new() const = 0; + virtual void get_image(std::vector& data, int& w, int& h, int& ch, int& bpp) = 0; + + void set_update_callback(std::function callback) { - static_cast(data); - static_cast(w); - static_cast(h); - static_cast(ch); - static_cast(bpp); + m_update_callback = callback; } + +protected: + void notify_update() + { + if (m_update_callback) + { + m_update_callback(); + } + } + +private: + std::function m_update_callback; };